今天我们继续坦克大战系列。我将沿用chapter2的代码继续为大家讲解。由于计划的修订第三节先完成我方坦克的移动。主要的操作流程如下:
(一)首先打开上一节的代码,然后在资源解决方案中头文件和主文件的地方添加程序要自己定义的坦克的类和方法。
主要操作位右键头文件->头文件->新建项->.h文件 命名为Thing
在Thing.h里面添加的代码如下 附图。
#include "stdafx.h" #include "Resource.h" #if !defined(_Thing_H_) #define _Thing_H_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class Tank { public: int HP; //黄色坦克为我方坦克 HP 0-5 初始为3 绿色为敌方坦克 HP 0-3 初始为3 红色坦克为敌方坦克 HP 0-5 初始为5 int Direct; //坦克有四个方向行走 分别为 up-1 right-2 down-3 left-4 int Speed; //坦克有行走速度 我方坦克(黄)-初始速度为10 敌方坦克红色初始为10 绿色初始为20 int Attribute; //坦克有被击中没有的属性 初始为1 当HP为0时 attribute为0 int IsPlayer; //1是我方坦克 2是敌军坦克 int Mark; //标记坦克数量(加上我方坦克最大数量为9) 0-我方坦克 1-8地方坦克 CPoint Site; //坦克有自己的位置 CBitmap Image; //坦克有自己本身的图像 HBITMAP HImage; //坦克有自己的加载图像格式 bool move; Tank(){}; //重写构造函数 ///~Tank(){}; Tank(Tank &tank){} //析构函数 public: bool InitTank(int H,int Dir,int Spe,int Attr,int IsP,int Ma,CPoint Si); //初始化坦克非图像计算的值 bool LoadImage(); //初始化坦克图像计算的值 bool Collision(CPoint *tank,int n); //碰撞检测 void ChaseMode(CPoint player); //追逐模式 void RandomMode();//随机模式 }; class Bullet { public: int Direct; //子弹有方向 为坦克初始化时候的方向 int Attribute; //子弹有属性 1为子弹显示 0为子弹消失 CPoint Site; //子弹有位置 根据发射坦克位置来初始化 int Speed; //子弹有速度 速度为10 int IsPlayer; //通过确定是否玩家发射子弹来确认子弹属性 CBitmap BImage; //用于子弹加载位图 HBITMAP HBImage; //用于装换位图格式 Bullet(){}; Bullet(Bullet &bullet){}; public: bool InitBullet(int Dir,int Attr,int Spe,int IsP,CPoint Si); bool LoadImage(); int Collision(CPoint *tank,int n); bool InitAgain(CPoint p,int Dir); bool BulletMove(); }; class Props { public: int Attribute; //道具属性1为出现 0为消失 int Mark; //道具标识 0为停止时间 1为传送任意位置 2为坦克加血 3为无敌 4为坦克全减1血 int IsPlayer; //判断是否玩家吃到道具 CBitmap PImage; //用于道具加载位图 HBITMAP HPImage; //用于装换位图格式 CPoint Site; Props(){}; Props(Props &props){}; public: bool InitProps(int Attr,int Ma,int IsP,CPoint Si); bool LoadImage(); void GetSite(CPoint *tank,int n); }; #endif // !defined(_Thing_H_)
当然 我们今天用到的只有坦克的类和方法。我写类的变量和方法的时候已经做了详细的注释相信大家都看的懂。
接下来在源文件中添加
右键单击源文件-〉添加-〉新建项-〉.cpp文件 命名为Thing
在里面添加实现的方法
在添加方法前我先导入两幅坦克的图片进去四个方向。一个我方坦克。一个敌方坦克。我用RGB(200,200,200)的tank背景。为了更好的透明处理
图片如下 像素240*60
再次声明两幅tank是网上的素材进行2次ps。只做学习之用。不做任何其它用途。
然后将两幅图片进行导入(两幅都是.bmp格式。资源导入的方法在第二节就已经进行了详细的说明。请大家参考chapter2的背景导入那儿)
然后在resources.h里面可以看到两幅图片的ID
接着可以在我们建好的thing.cpp文件中添加以下代码。代码里面只有这一节用会用到的两个方法。
#include "stdafx.h" #include "Resource.h" #include "Thing.h" #include<math.h> #include<time.h> #include<stdlib.h> bool Tank::InitTank(int H,int Dir,int Sp,int Attr,int IsP,int Ma,CPoint Si) { HP=H; Direct=Dir; Speed=Sp; Attribute=Attr; IsPlayer=IsP; Mark=Ma; Site=Si; move=false; return true; } bool Tank::LoadImage() { 1==IsPlayer?Image.LoadBitmap(IDB_BITMAP8):Image.LoadBitmap(IDB_BITMAP11); HImage=HBITMAP(Image); return true; }
当然类里面的方法没添加完。我只添加这一节我们会用到的方法。第一个是初始化tank的各项属性。第二个是加载关联的图像。
在TankGame1Dlg.h中添加红色部分。我们要引用自己写的类及方法。也就是接口函数。
接下来我们要在这里面添加几行代码
红色部分为相较于上一节进行的增加和改动。并且用红色字体进行了说明。
在TankGame1Dlg.cpp里面添加如下
DWORD WINAPI InitTank(LPVOID lpParam) { CTankGame1Dlg *c=(CTankGame1Dlg*)lpParam; CPoint p; p.x=0,p.y=650; c->Player.InitTank(3,1,8,1,1,0,p); c->Player.LoadImage(); c->KeyDown=false; c->KeyLeft=false; c->KeyUp=false; c->KeyRight=false; c->control=true; c->controlend=true; return TRUE; } BOOL CTankGame1Dlg::PreTranslateMessage(MSG* pMsg) { bool Judge=false; if (pMsg-> message == WM_KEYDOWN) { if(pMsg-> wParam== VK_UP) { KeyUp=true; } if(pMsg-> wParam== VK_DOWN) { KeyDown=true; } if(pMsg-> wParam== VK_LEFT) { KeyLeft=true; } if(pMsg-> wParam== VK_RIGHT) { KeyRight=true; } if(pMsg->wParam==VK_ESCAPE) { control=false; controlend=false; } } if(pMsg-> message == WM_KEYUP) { if(pMsg-> wParam== VK_UP) { KeyUp=false; } if(pMsg-> wParam== VK_DOWN) { KeyDown=false; } if(pMsg-> wParam== VK_LEFT) { KeyLeft=false; } if(pMsg-> wParam== VK_RIGHT) { KeyRight=false; } } return CDialog::PreTranslateMessage(pMsg); } DWORD WINAPI PlayerMove(LPVOID lpParam) { CTankGame1Dlg *c=(CTankGame1Dlg*)lpParam; while(c->controlend) { if(true==c->KeyUp) { c->Player.Direct=1; c->Player.Site.y-=c->Player.Speed; ::Sleep(40); continue; } if(true==c->KeyDown) { c->Player.Direct=3; c->Player.Site.y+=c->Player.Speed; ::Sleep(40); continue; } if(true==c->KeyLeft) { c->Player.Direct=4; c->Player.Site.x-=c->Player.Speed; ::Sleep(40); continue; } if(true==c->KeyRight) { c->Player.Direct=2; c->Player.Site.x+=c->Player.Speed; ::Sleep(40); continue; } ::Sleep(1); } return TRUE; }
上一节讲到的画图线程的改动如下同样在TankGame1.cpp里
DWORD WINAPI MyPaint(LPVOID lpParam) //贴图线程 { CTankGame1Dlg *c=(CTankGame1Dlg*)lpParam; HWND hWnd= c->GetSafeHwnd(); //获取屏幕的句柄 c->hdc = ::GetDC(hWnd); //获取屏幕的DC c->mdc =::CreateCompatibleDC(c->hdc); //关联和屏幕兼容的内存DC c->bufdc =::CreateCompatibleDC(c->hdc); //关联和屏幕兼容的缓冲DC RECT rect; ::GetWindowRect(hWnd,&rect); //获取屏幕的大小 c->hBitmap =::CreateCompatibleBitmap(c->hdc,rect.right,rect.bottom); //让内存DC关联的位图设置大小 SelectObject(c->mdc,c->hBitmap); //进行关联 c->Back.LoadBitmap(IDB_BITMAP1); //载入关卡的地图 c->BackGround=HBITMAP(c->Back); //转换光卡的地图格式 while(c->control) { SelectObject(c->bufdc,c->BackGround); //缓冲DC关联关卡1的地图 BitBlt(c->mdc,0,0,rect.right,rect.bottom,c->bufdc,0,0,SRCCOPY); //从缓冲DC贴图到内存DC if(1==c->Player.Attribute) { SelectObject(c->bufdc,c->Player.HImage); switch(c->Player.Direct) { case 1:TransparentBlt(c->mdc,c->Player.Site.x,c->Player.Site.y,60,60,c->bufdc,0,0,60,60,RGB(200,200,200));break; case 2:TransparentBlt(c->mdc,c->Player.Site.x,c->Player.Site.y,60,60,c->bufdc,60,0,60,60,RGB(200,200,200));break; case 3:TransparentBlt(c->mdc,c->Player.Site.x,c->Player.Site.y,60,60,c->bufdc,120,0,60,60,RGB(200,200,200));break; case 4:TransparentBlt(c->mdc,c->Player.Site.x,c->Player.Site.y,60,60,c->bufdc,180,0,60,60,RGB(200,200,200));break; } } BitBlt(c->hdc,0,0,rect.right,rect.bottom,c->mdc,0,0,SRCCOPY); //从内存DC贴图到屏幕DC ::Sleep(1); //休眠一个毫秒 } //::ReleaseDC(c->hdc); ::ReleaseDC(hWnd,c->hdc); ::DeleteDC(c->mdc); ::DeleteDC(c->bufdc); return TRUE; }
在初始化函数里面增加启动的两个线程
最后就能看见坦克平滑的四个方位的移动了
如下图
下一节会为大家讲解碰撞检测和AI寻找路径的问题。
附上这一节的代码。大家可以对着图文参考。不要任何下载积分。
点击打开链接