最近几天的课程是将之前写的纸牌游戏的牌壳进行重写。之前的纸牌游戏只是单纯的继承了牌壳里的类,从而完成纸牌的规则,进而实现了纸牌游戏,但是并没有对扑克牌类游戏的模版进行学习,接下来需要仔细学习扑克牌类的游戏模版。

1.首先创建一个空的模版,也就是基于Win32应用程序创建的窗口,之前在进行任何游戏的实现时都需要有的WinMain.cpp,这个文件是为了创建一个空的Win32项目。

1.1 首先我们将之前写好的 COObject.h、COObject.cpp、CGameApp.h以及 WinMain.cpp文件拷贝到新的工程中去。

1.2 当我们改完字符集属性之后,发现了一个错误:

1>WinMain.obj : error LNK2019: 无法解析的外部符号 "class CGameApp * __cdecl CreateObject(void)" (?CreateObject@@YAPAVCGameApp@@XZ),该符号在函数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) 中被引用
1>D:\all_works\C\colin\CPP\1-7\Win32Project1\Debug\Win32Project1.exe : fatal error LNK1120: 1 个无法解析的外部命令

问题来了:这是为什么呢?

起始原因很简单,因为CGameApp是一个接口类,其需要一个类来进行继承。我们创建一个继承 CGameApp 的类:CCardsApp 类,并在CCardsApp.cpp文件中动态创建一个对象:IMPLEMENT(CCards)。这样以后,我们就能看到窗口了。

2.创建一个 sys.h 的头文件

2.1 该头文件中装的是以后需要用到的头文件、一个牌的节点、以及一个用来表示牌颜色的联合体(这个联合体的顺序是按照我们添加牌为位图时牌的顺序而定义的)。

sys.h

#pragma once#include <windows.h>
#include <list>
#include <vector>
#include <algorithm>
#include "resource.h"using namespace std;// 牌的颜色
enum {Cards_Flower,Cards_Square,Cards_Red,Cards_Black};class CCards;
struct Node
{bool bflag;   //  标示正反面int x;int y;CCards* pCards;
};

3.完成cards类

1.首先对于 CCards 类,我们考虑:一张牌应该需要几个属性? 答案是三个:1)图像句柄、2)牌的颜色、3)牌的数字。

因此我们给 CCards 类创建三个成员属性:HBITMAP m_hBmpCards; int m_nCardsColor;int m_nCardsNum;
并且添加一个初始化 CCards 类的函数:void InitCards(HINSTANCE hIns, int nBmpID, int nCardsNum, int nColor)。

CCards.h

#pragma once
#include "sys.h"class CCards
{public:CCards(void);~CCards(void);public:HBITMAP m_hBmpCards;int m_nCardsColor;int m_nCardsNum;public:void InitCards(HINSTANCE hIns, int nBmpID, int nCardsNum, int nColor);
};

2.完成 InitCards 函数

2.1 首先我们来考虑:对于牌的初始化,我们需要进行载入位图,并为卡牌的颜色和数字进行赋值(首先应该在构造函数中将颜色和数字初始化为0;并且在析构函数中,我们需要将载入的位图清空)。

CCards.cpp

#include "Cards.h"CCards::CCards(void)
{m_hBmpCards = 0;m_nCardsColor = 0;m_nCardsNum = 0;
}CCards::~CCards(void)
{DeleteObject(m_hBmpCards);m_hBmpCards = 0;
}void CCards::InitCards(HINSTANCE hIns, int nBmpID, int nCardsNum, int nColor)
{m_hBmpCards = LoadBitmap(hIns, MAKEINTRESOURCE(nBmpID));m_nCardsNum = nCardsNum;m_nCardsColor = nColor;
}

3. 完成 CPoker 类

3.1 在完成 CCards 类之后,我们可以开始完成 CPoker 类。对于 CPoker 类,我们知道,一副扑克具有13张牌,因此我们在 CPoker 类中使用一个 vector<CCards*> 类型的成员来保存一副扑克中的牌。虽然我们知道一副扑克由13张牌组成,但是在进行定义vector成员时,我们仍旧不可以直接定义为这样的形式:vector<CCards*> m_vecCards(13),而是需要在构造函数中进行初始化。原因:==忘记了=(找到后补充)。

3.2 之后我们仍旧需要一个初始化poker的函数:void InitPoker(HINSTANCE hIns, int nColor)。

3.3 在构造函数的初始化列表中初始化 m_vecCards(13),在析构函数中将每一个牌的指针删除,并赋值为空。

3.4 初始化 CPoker ,起始就是像 vector 类型成员中添加牌的指针。

#include "Poker.h"CPoker::CPoker(void):m_vecCards(13)
{}CPoker::~CPoker(void)
{for(int i=0; i<13; i++){delete(m_vecCards[i]);m_vecCards[i] = 0;}
}void CPoker::InitPoker(HINSTANCE hIns, int nColor)
{// 创建13个cards对象for(int i=0; i<13; i++){m_vecCards[i] = new CCards;m_vecCards[i]->InitCards(hIns, IDB_BITMAP1+nColor*13+i, i+1, nColor);       // IDB_BITMAP1 是我程序里的第一张牌位图的ID,各位需要将其换成自己的第一张牌的ID}
}

4. 完成 CCardsRank 类

4.1 因为 CCardsRank 类需要进行动态创建对象,因此其需要继承 COObject 类。

4.2 对于CCardsRank类,我们想要这个类能够进行管理poker,并且能够存储多副扑克,因此我们定义其中的成员: CPoker* m_pPoker; HBITMAP m_hBmpCardsBack; HBITMAP m_hBmpWndBack; vector<list<Node*>> m_vecRank;其中的m_hBmpCardsBack表示的是扑克牌的背面位图句柄,m_hBmpWndBack表示的是窗口的位图句柄,m_vecRank表示的是所有的牌。

4.3 对于类中的成员函数,我们考虑:一个初始化Rank的函数、一个显示Rank的函数。

4.4 对于 CCardsRank 类的构造函数,我们定义为带参数的构造函数,将传入的参数传递给 m_vecRank 进行初始化,其余赋值为0;在构造函数里对载入的位图进行删除,对扑克对象进行删除,并将vector中的所有元素进行遍历删除。

4.5 我们将初始化Rank的函数定义为纯虚函数,因为我们不知道以后的扑克游戏是蜘蛛纸牌还是纸牌,因此需要具体问题具体分析,因此在此处定义为纯虚函数;对于显示Rank的函数,首先判断有没有整体游戏的背景,若没有则进行加载,再显示背景图;判断牌背面的句柄是否为空,若是则加载牌背面位图;再遍历所有的节点,对牌进行贴图。

CCardsRank.h

#pragma once
#include "OObject.h"
#include "Poker.h"class CCardsRank :public COObject
{public:CCardsRank(int nCount);~CCardsRank(void);public:CPoker* m_pPoker;HBITMAP m_hBmpCardsBack;HBITMAP m_hBmpWndBack;vector<list<Node*>> m_vecRank;public:virtual void InitRank(HINSTANCE hIns)=0;void ShowRank(HINSTANCE hIns, HDC hdc);
};

CCardsRank.cpp

#include "CardsRank.h"CCardsRank::CCardsRank(int nCount):m_vecRank(nCount)
{m_pPoker = 0;m_hBmpCardsBack = 0;m_hBmpWndBack = 0;
}CCardsRank::~CCardsRank(void)
{// 删除图像句柄DeleteObject(m_hBmpCardsBack);DeleteObject(m_hBmpWndBack);// 删除扑克的对象delete m_pPoker;// 删除链表中所有的节点for(size_t i=0; i<m_vecRank.size(); i++){list<Node*>::iterator ite = m_vecRank[i].begin();while (ite != m_vecRank[i].end()){delete (*ite);ite = m_vecRank[i].erase(ite);}}
}void CCardsRank::ShowRank(HINSTANCE hIns, HDC hdc)
{// 1.判断是否有背景图,若无则加载if(m_hBmpWndBack == 0)m_hBmpWndBack = ::LoadBitmap(hIns, MAKEINTRESOURCE(IDB_WIN_BACK));HDC backComDC = ::CreateCompatibleDC(hdc);::SelectObject(backComDC, m_hBmpWndBack);::BitBlt(hdc, 0, 0, 850, 600, backComDC, 0, 0, SRCCOPY);::DeleteDC(backComDC);// 2.判断背景牌的句柄是否为空,若是则加载背景牌位图if(m_hBmpCardsBack == 0)m_hBmpCardsBack = ::LoadBitmap(hIns, MAKEINTRESOURCE(IDB_POKER_BACK));for(size_t i=0; i<m_vecRank.size(); i++){list<Node*>::iterator ite = m_vecRank[i].begin();while (ite != m_vecRank[i].end()){HDC cardComDC = ::CreateCompatibleDC(hdc);if((*ite)->bflag == false)::SelectObject(cardComDC, m_hBmpCardsBack);else::SelectObject(cardComDC, (*ite)->pCards->m_hBmpCards);::BitBlt(hdc, (*ite)->x, (*ite)->y, 71, 96, cardComDC, 0, 0, SRCCOPY);::DeleteDC(cardComDC);++ite;}}
}

5. 完成 CCardApp 类

5.1 CCardApp 类首先是继承 GameApp 类的,其次它需要管理poker,因此依赖于 CCardsRank 类,需要有一个CCardsRank类型的指针。

5.2 在实现CCardApp类时,首先需要动态创建一个CCardApp类对象,这个宏定义在CGameApp类中;其次完成 OnCreateGame 函数,首先需要对CCardsRank类型的指针 m_pRank 进行赋值,其值为: (CCardsRank*)COObject::Create(“CCardsRank”) ,判断 m_pRank 是否是空,若是空则表明创建失败,否则进行 m_pRank->InitRank(m_hIns) 操作;再完成重绘函数,在 OnGameDraw 函数中判断 m_pRank 是否是空,不是空则进行 m_pRank->ShowRank(m_hIns, tempDC) 操作。

CCardApp.h

#pragma once
#include "gameapp.h"
#include "CardsRank.h"class CCardsApp :public CGameApp
{public:CCardsApp(void);~CCardsApp(void);public:CCardsRank* m_pRank;   //  排列public:virtual void OnCreateGame();                 //  WM_CREATEvirtual void OnGameDraw();                   //  WM_PAINTvirtual void OnLButtonDown(POINT point);      //  WM_LBUTTONDOWNvirtual void OnLButtonUp(POINT point);        //  WM_LBUTTONUPvirtual void OnMouseMove(POINT point);        //  WM_MOUSEMOVE
};

CCardApp.cpp

#include "CardsApp.h"IMPLEMENT(CCardsApp)CCardsApp::CCardsApp(void)
{m_pRank = 0;
}CCardsApp::~CCardsApp(void)
{delete m_pRank;m_pRank = 0;
}void CCardsApp::OnCreateGame()                 //  WM_CREATE
{m_pRank = (CCardsRank*)COObject::Create("CCardsRank");if(m_pRank == 0)::MessageBox(m_hMainWnd, "游戏初始化失败", "提示", MB_OK);else{m_pRank->InitRank(m_hIns);}
}void CCardsApp::OnGameDraw()                   //  WM_PAINT
{HDC tempDC = GetDC(m_hMainWnd);if(m_pRank != 0)m_pRank->ShowRank(m_hIns, tempDC);ReleaseDC(m_hMainWnd, tempDC);
}void CCardsApp::OnLButtonDown(POINT point)      //  WM_LBUTTONDOWN
{}void CCardsApp::OnLButtonUp(POINT point)        //  WM_LBUTTONUP
{}void CCardsApp::OnMouseMove(POINT point)        //  WM_MOUSEMOVE
{}

6. 完成 CRule 类

6.1 对于 CRule 类,由5个纯虚函数和3个成员函数组成,五个虚函数都是需要具体的游戏来具体重写的,因此我们只需要完成剩余三个不管什么牌类游戏都需要用到的函数即可。

6.2 首先我们完成拿牌的函数:GetCards,这个函数需要我们传入三个参数:POINT point, CCardsRank* pCradsRank, list<Node*>& lstCursorCards。为了确定玩家是否取到了牌,我们需要遍历所有的链表(虽然很笨,但是很有效);我们需要从最下面的一张牌开始遍历,这是因为假设我们从最上面的牌开始遍历时,第一张牌和第二张牌是有重复范围的部分的,若我们从最上面一张牌开始遍历链表的话,我们无法区分玩家点击的是第一张牌还是第二张牌,为了避免这个问题,我们需要从链表的最后开始遍历链表,因此创建的是反向迭代器 reverse_iterator ,当不是 rend 时进行鼠标点击的区域判断,判断时还需判断是否是正面,也就是 bflag 的值是否为 true ,若是正面,则先将反向的迭代器进行反转,转换为正向的,此时需要注意,反转反向迭代器时会得到正向迭代器的上一个,因此需要进行 --;之后使用能否拿牌的规则 IsGetCardsRule 进行判断是否可以进行拿牌,若能拿牌则先记录链表的下标,再将这个链表放到光标的链表上。

6.3 具体的程序

void CRule::GetCards(POINT point, CCardsRank* pCradsRank, list<Node*>& lstCursorCards)
{// 1.遍历所有链表for(size_t i=0; i<pCradsRank->m_vecRank.size(); i++){// 2.从最下面一个牌开始遍历(要是从上面开始遍历的话不知道取的是哪一张牌,会有区域是重复的)list<Node*>::reverse_iterator rev_ite = pCradsRank->m_vecRank[i].rbegin();while (rev_ite != pCradsRank->m_vecRank[i].rend()){// 3.判断坐标是否点击到了牌上if( point.x >= (*rev_ite)->x && point.x <= (*rev_ite)->x+71&& point.y >= (*rev_ite)->y && point.y <= (*rev_ite)->y+96){// 4.若点击到了牌上,判断是不是正面,正面可拿起,反面不可拿起if((*rev_ite)->bflag == true){list<Node*>::iterator ite = --(rev_ite.base());       // 将牌反转过来,从当前的光标位置取牌// 5.判断能不能拿牌if( this->IsGetCardsRule(pCradsRank, i, ite) == true){// 能拿牌// 记录这个链表的下标m_nGetCardsListID = i;// 放到光标的链表上lstCursorCards.splice(lstCursorCards.end(), pCradsRank->m_vecRank[i], ite, pCradsRank->m_vecRank[i].end());}}return;}++rev_ite;}}
}

C++学习 2019-1-9相关推荐

  1. cs224n上完后会会获得证书吗_斯坦福NLP组-CS224n: NLP与深度学习-2019春全套资料分享...

    斯坦福自然语言处理小组2019年的最新课程<CS224n: NLP与深度学习>春季课程已经全部结束了,课程内容囊括了深度学习在各项NLP任务中应用的最新技术,非常值得一看.本文整理本期课程 ...

  2. html ifrme 选择器,html中iframe/css样式设置,id,class选择器的使用规则等学习2019.9.2 08:00...

    实例 html> 外部样式 I Love PHP中文网!from 赵桂福 运行实例 » 点击 "运行实例" 按钮查看在线实例 2.内部样式:用 标签 实例 html> ...

  3. pyemd资料学习 2019.1.24 https://media.readthedocs.org/pdf/pyemd/latest/pyemd.pdf

    PyEMD是经验模式分解(EMD)及其变体的Python实现.最流行的扩展之一是集成经验模态分解(EEMD),它利用了噪声辅助执行的集成. EMD的结果是得到一组具有振荡特征的分量.在普通EMD算法中 ...

  4. 西蒙购物网站学习 2019.12.9

    #西蒙购物网站 1.登录页面 输入以下内容实现登录 登录成功页面 2.注销页面 3.注册页面 输入相应的内容 注册成功页面 数据表更新成功 4.显示类别 显示成功界面 5.显示商品列表的控制程序,通过 ...

  5. python学习2019/4/25

    #2,8,10,16进制 0b 2进制 0o 8进制 0x 16进制 转2进制BIN 转8进制HEX 转10进制一般不需要如果需要用INT,INT表示整数,float 表示浮点,小数 转16进制oct ...

  6. 挥手送别 2019,翘首期待 2020

    1. 2019 年度总结 回头看看 2019 年初做的计划,发现有好多都没有实现,像管理.英语.锻炼身体等,都由于种种原因没有坚持下来,或者说都没有达到预期的效果. 英语学习 2019 年初尝试 [英 ...

  7. CVPR 2019超全论文合集新鲜出炉!| 资源帖

    整理 | 夕颜 出品 | AI科技大本营(ID: rgznai100) 实不相瞒,这是一个资源福利帖--CVPR 2019 接收论文超全合集! 此前关于 CVPR 2019 论文和合集出过不少,但是这 ...

  8. 【原创】强化学习精选资料汇总:从入门到精通,看完这些干货就够啦!

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要8分钟 Follow小博主,每天更新前沿干货 [导读]本文为大家整理了公众号之前发过的一系列强化学习资料和学习手册,包括:强化学习视频课程.经 ...

  9. 深度强化学习入门到精通--资料综述

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 人工智能是21世纪最激动人心的技术之一.人工智能,就是像人一样的智能,而人的智能包 ...

  10. 以下不属于时序逻辑电路的有_电工电子技术(不建议浪费时间学习的科目)

    (声明:本资料来自网络,侵权请告知删除.文末有全套高清版资料下载链接,敬请下载学习) 2019年7月在天津召开的土力学及岩土工程年会上,有一场青年教师的土力学讲课竞赛,由我作一些点评,其中关于土颗粒与 ...

最新文章

  1. 6月28日 cf总结
  2. 2020EC-final
  3. 号角响起!百度AI开发者实战营第二季教你用AI实现商业梦想
  4. HP MSA500 G2安装配置
  5. 78 python - 打飞机案例(让敌机移动)
  6. instant app入门和开发指南
  7. Microsoft Excel 教程:如何在 Excel 中创建新工作簿、插入或删除工作表?
  8. 去中心化通信简易方案
  9. 笔记:戴蒙德模型——参数变化的影响
  10. 转:走向自治:关于德鲁克的五个关键词
  11. 实时级嵌入式系统半实物仿真测试平台系统描述
  12. SPP (Spatial Pyramid Pooling)
  13. Python学习:批量转换图片格式-PNG转JPG
  14. 3D游戏编程 作业五 枪打恶鬼(打飞碟)
  15. 命令行测试BT,WIFI,Sensor工作状态
  16. 查询重复或不重复记录SQL语句
  17. 投影——Drop Shadow
  18. JavaScript对象的使用及存储方式的剖析
  19. flash元件做运行时共享的问题
  20. 上拉、下拉以及对应上拉电阻和下拉电阻的作用原理

热门文章

  1. org.apache.maven.plugin.MojoExecutionException: protoc failure
  2. mysql报警级别_MySQL 5.7定义日志级别新参数(log_error_verbosity)
  3. Prometheus 监控arangodb
  4. Docker Data Volume 之 bind mount
  5. 百度经验怎么赚钱?教你怎么发布文章
  6. USB - CY7C68013A 芯片
  7. mysql 10051_Zabix的10051端口无法启动如何解决?
  8. MAGCN:基于lncRNA与miRNA相互作用和图卷积网络预测miRNA与疾病的关联(Briefings in Bioinformatics)
  9. 解决Adobe Dreamweaver 2020在编程敲代码时又卡又慢延迟的问题(复制黏贴打字都卡)
  10. Windows下U盘管理程序