C++学习 2019-1-10

本文详细介绍了牌壳程序的设计与实现过程,包括CardsApp类的完善,牌的显示、移动与规则应用,以及如何通过鼠标操作实现牌的拿取与放置。重点讲解了光标牌的显示函数ShowCursorCards,牌移动逻辑的实现,以及规则类Rule中的ReceiveCards函数,确保牌能够根据游戏规则正确地被接收或还原。

接着昨天的继续完成牌壳的程序。

1.继续完成 CardsApp 类

1.1 在 CardsApp 类的析构函数中删除光标链表 lstCursorCards 上的牌;

1.2 为显示光标上的牌创建一个函数:ShowCursorCards,只需传入一个 dc 就可以;

1.首先需要一个 int X 和一个 int Y 来记录光标在横轴和纵轴上移动的距离,X 和 Y 可以由在 OnLButtonUp 和 OnMouseMove 里获取的鼠标坐标相减获得;
2.对光标链表上的元素进行遍历,遍历的过程中进行贴图;
3.在 OnGameDraw 函数里使用 this 调用 ShowCursorCards 函数。

1.3 具体程序

void CCardsApp::ShowCursorCards(HDC hdc)
{
	int X = pointMouseMove.x - pointMouseDown.x;
	int Y = pointMouseMove.y - pointMouseDown.y;

	list<Node*>::iterator ite = lstCursorCards.begin();
	while (ite != lstCursorCards.end())
	{
		HDC tempDC = ::CreateCompatibleDC(hdc);
		::SelectObject(tempDC, (*ite)->pCards->m_hBmpCards);
		::BitBlt(hdc, (*ite)->x+X, (*ite)->y+Y, 71, 96, tempDC, 0, 0, SRCCOPY);
		::DeleteDC(tempDC);

		++ite;
	}
}

2.向项目中添加 AAARule 类

2.1 本次的 AAARule 类已经在之前的学习中编写完成,可以直接复制拷贝到当前工作目录下;

2.2 在完成了上述步骤后可以进行拿牌的操作,但是会发现一个问题:当鼠标在窗口外部时移动鼠标,牌也会跟着移动,即当鼠标移出窗口时,希望牌回到原来的位置,因此我们需要一些小技巧来进行捕获鼠标消息。

1.在 OnLButtonDown 中截获鼠标消息: ::SetCapture(m_hMainWnd);
2.在 OnLButtonUp 中释放鼠标消息: ::ReleaseCapture()。

经过上述两步操作即可完成鼠标移出当前窗口后,牌会回到原位而不是随着鼠标继续移动。

2.3 具体代码

void CCardsApp::OnLButtonDown(POINT point)      //  WM_LBUTTONDOWN
{
	pointMouseDown = point;
	::SetCapture(m_hMainWnd);

	// 判断是否有拿牌的规则
	if (m_pRule)
	{
		m_pRule->GetCards(point, m_pRank, lstCursorCards);
	}

	this->OnGameDraw();
}

void CCardsApp::OnLButtonUp(POINT point)        //  WM_LBUTTONUP
{
	// 释放截获鼠标消息的动作
	::ReleaseCapture();

	if (m_pRule)					// 若有规则,则判断光标的链表是不是空,
	{
		if(lstCursorCards.empty() == false)
		{
			// 如果光标链表不是空,判断能否接受牌,不能则还原
			if(m_pRule->ReceiveCards(point, m_pRank, lstCursorCards) == false)
				m_pRule->RevertCards(m_pRank, lstCursorCards);
		}
		// 如果是空,则判断能否进行发牌
		else
		{
			if(m_pRule->IsOpenCards(point, m_pRank) == true)
				m_pRule->OpenCards(m_pRank);
		}
		this->OnGameDraw();
	}
}

3.完成 Rule 类中的 ReceiveCards 函数

3.1 首先我们遍历所有的链表,由于本函数的目的是判断是否收到了牌,因此需要判断是否能够接收牌;

3.2 若能够接收牌,若当前链表可以接收牌(满足 IsReceiveCardsRule ),则我们将光标上的链表放到当前链表的最后,并对齐、更新位置 this->UpDatePos ;

3.3 若光标链表牌的原位置仍有牌则将该牌翻过来,并将记录拿牌的链表的下标数 m_nGetCardsListID 归为初始值 -1 。

3.4 具体代码

bool CRule::ReceiveCards(POINT point, CCardsRank* pCradsRank, list<Node*>& lstCursorCards)
{
	for (size_t i=0; i<pCradsRank->m_vecRank.size(); i++)
	{
		// 判断是否能够接收牌,
		if(this->IsReceiveCardsRule(point, i, pCradsRank, lstCursorCards) == true)
		{
			// 能接收则与第i个链表结合
			pCradsRank->m_vecRank[i].splice(pCradsRank->m_vecRank[i].end(), lstCursorCards);
			// 对齐,更新位置
			this->UpDatePos(pCradsRank, i);
			// 将移动牌原位置上一张牌进行翻牌:如果有的话
			if(m_nGetCardsListID != -1 && pCradsRank->m_vecRank[m_nGetCardsListID].empty() == false)
				pCradsRank->m_vecRank[m_nGetCardsListID].back()->bflag = true;
			m_nGetCardsListID = -1;			//  使用后归位初始值
			return true;
		}
	}
	return false;
}

4.到此为止,牌壳基本创建完毕,之后老师又讲解了纸牌游戏的相关知识,但是由于我没有听得太懂,故本次不对纸牌游戏进行记录,纸牌游戏放到我理解之后在进行更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值