DS课设【坦克大战最短路】(MummyDing)

来源:互联网 发布:青岛海关数据 编辑:程序博客网 时间:2024/05/18 03:03


DS课设【坦克大战最短路】

     还是决定写点东西简单记录下这次编码。

一、想法

    还没放假的时候只想着用C#实现,算法图论方面觉得图论方向会靠谱些,但一直没有什么好点子。C#以前也没学过,自信来源于MFC的学习经历(以前也是用它做了C语言课设)。C#应该是没有MFC那么复杂的,心想看几天应该就可以上手一些小东西了,事实证明也如此。
    寒假时间相对以前更长,也并不着急做课设。开始一段是刷题+学习Kinect+顺带了解Kinect,后来在刷题过程中遇到这题,还蛮有意思的,当即就写了个“坦克大战最短路简单设计”:

坦克大战最短路算法:优先队列+广度优先搜索用户自定义地图1.设置地图大小起点和终点 设置弹药2.设置铁墙、土墙、河水3.模式一:用户自己走模式二:自动给出最短路对比坦克方法:1.调整方向2.开枪事件:判断是否达到是否可以走是否打到墙(子弹能可以穿过河)游戏是否结束人性化:背景音乐子弹效果保存地图当前最短爆炸效果

二、实现

当时也没有十足把握能实现它,搁置了几天。期间看了一些关于C#项目开发的教学视频,也是跟着例程做了下,心里有底了,首先实现UI是没有问题的。
然后就有了下面这个详细设计文档:
一、界面1、地图大小 12*12  每个方格 边长60个像素左上角为原点(0,0)2、对象坦克(Tank)砖块(Brick)  1次打破钢墙(Steel)  2次打破河水(River)  子弹可以穿过,坦克不可以星星(Star)子弹(Bullet)3、菜单添加对象手动模式自动模式4、显示当前消耗帮助二、类设计1.游戏父类 GameObject属性:x,y,width,height,image方法:构造函数(初始化)Draw();GetRectangle();2.墙壁父类 WallFather:GameObject属性:+life方法:构造函数(初始化)重写Draw();IsOver();3.River&Star父类 RSFather:GameObject方法:构造函数(初始化)重写Draw();4.Bullet :GameObject属性:+power方法:构造函数(初始化)重写Draw();5.Tank:GameObject属性:方法:重写Draw(g);Move();Fire();6.SingleObject方法:GetSingle();Draw();Check();三、事件响应


 于是照着这个,一个一个类的实现了。在这个过程中,颇有面向对象的意思在里面,以前写MFC程序的时候感触没这么明显。


1.新建一个VC++ win32 DLL2.添加头文件"" 在头文件中加入以下代码:#ifndef DLL_EXPORT#define DECLDIR __declspec(dllimport)#else#define DECLDIR __declspec(dllexport)#endif3.添加源程序,添加以下代码:#define DLL_EXPORT //先定义宏#include "Dll.h"//这个头文件必须在#define DLL_EXPORT后面4.编写自己需要的函数:extern "C"{DECLDIR 返回值 函数名(参数...){}}5.添加必要的头文件,不需要main函数,编译即可6.建立一个C#工程,将生成的Dll文件(在Debug目录下)扔到C#工程Bin目录下。7.在C#中添加如下代码:(1). 命名空间using System.Runtime.InteropServices; (2).声明 [DllImport("CppDll.dll", SetLastError = true)] private static extern 返回值 函数名(参数...); 8.然后这个函数就可以直接在C#工程中使用了


这期间,特别要注意的是C++和C#之间数据类型的对应关系!! 这里着实费了一番功夫。
附上C++与C#数据类型对照表:
C++            C#=====================================WORD            ushortDWORD            uintUCHAR            int/byte   大部分情况都可以使用int代替,而如果需要严格对齐的话则应该用bytebyte UCHAR*            string/IntPtrunsigned char*         [MarshalAs(UnmanagedType.LPArray)]byte[]/?(Intptr)char*            stringLPCTSTR            stringLPTSTR            [MarshalAs(UnmanagedType.LPTStr)] stringlong            intulong               uintHandle            IntPtrHWND            IntPtrvoid*            IntPtrint            intint*            ref int*int            IntPtrunsigned int        uintCOLORREF                uint

这个很实用。
然后我把以前的代码做了简单修改就可以了,不过只能是把最短的路径长度算出来,还没有记录路径的功能。
我C++的代码中是直接调用STL提供的“优先队列”实现的BFS,这样记录路径稍微麻烦点~ 后来是想着在结点专门开个变量记录路径。最后代码被我改成了这个样子[变量名什么的不大规范]:
#include<iostream>#include<algorithm>#include<string>#include<cstring>#include<queue>#define N 15#define Max_Len 100#define DLL_EXPORT //先定义宏#include "Dll.h"//这个头文件必须在#define DLL_EXPORT后面using namespace std;int n, m, sx, sy, ex, ey, visit[N][N];int dir[][2] = {{ 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 }};char chess[N][N];enum TankAcationType{//MoveMoveStep,//Fire MoveFireOneWall,//Fire Fire MoveFireTwoWall,//Dir->Up MoveChangeTheDirToUp,//Dir->Up FireChangeToUpFireOne,//Dir->Up Fire FireChangeToUpFireTwo,//Dir->Down FireChangeToDownFireOne,//Dir->Down MoveChangeTheDirToDown,//Dir->Down Fire FireChangeToDownFireTwo,//Dir->Left MoveChangeTheDirToLeft,//Dir->Left FireChangeToLeftFireOne,//Dir->Left Fire FireChangeToLeftFireTwo,//Dir->Right MoveChangeTheDirToRight,//Dir->Right FireChangeToRightFireOne,//Dir->Right Fire FireChangeToRightFireTwo,None} TmpType;TankAcationType TmpPath[Max_Len];struct Node{int x, y, s,d;int step;TankAcationType Path[Max_Len];friend bool  operator <(Node a, Node b){return a.s>b.s;}};bool ok(int x, int y){if (x >= 0 && x<m&&y >= 0 && y<n&&chess[x][y] != 'R'&&chess[x][y] != '#')return true;return false;}extern "C"{DECLDIR int bfs( char  * Map,TankAcationType  * ActionPath,int &Count){m = 15;n = 15;for (int i = 0; i < 15; i++)for (int j = 0; j < 15; j++)chess[i][j] = '#';for (int i = 0; i < 12;i++)for (int j = 0; j < 11; j++)chess[i][j] = '.';for (int i = 0; i<n; i++)for (int j = 0; j < m; j++){if (Map[i*m + j] == '#'&&chess[i][j] == '.')continue;chess[i][j] = Map[i*m + j];}for (int i = 0; i<m; i++)for (int j = 0; j<n; j++){if (chess[i][j] == 'T'){sx = i; sy = j;   chess[i][j] = 'R';}else if (chess[i][j] == 'X'){ex = i; ey = j;chess[i][j] = '.';}}priority_queue<Node> q;memset(visit, -1, sizeof(visit));visit[sx][sy] = 0;Node head = { sx, sy, 0 ,1,0};head.d = 1;q.push(head);while (!q.empty()){Node f = q.top();q.pop();if (f.x == ex&&f.y == ey){ for (int i = 0; i < f.step; i++)ActionPath[i] = f.Path[i];Count =  f.step;return f.s; }for (int i = 0; i<4; i++){int dx = f.x + dir[i][0], dy = f.y + dir[i][1];if (ok(dx, dy) && visit[dx][dy]){visit[dx][dy] = 0;int temp = 0;if (chess[dx][dy] == 'S'){temp = 3; if (f.d==i)TmpType = FireTwoWall;else {temp++;switch (i){case 0:TmpType = ChangeToDownFireTwo;break;case 1:TmpType = ChangeToUpFireTwo;break;case 2:TmpType = ChangeToRightFireTwo;break;case 3:TmpType = ChangeToLeftFireTwo;break;}}}else if (chess[dx][dy] == 'B'){ temp = 2; if(f.d==i)TmpType = FireOneWall;else {temp++;switch (i){case 0:TmpType = ChangeToDownFireOne;break;case 1:TmpType = ChangeToUpFireOne;break;case 2:TmpType = ChangeToRightFireOne;break;case 3:TmpType = ChangeToLeftFireOne;break;}}}else if (chess[dx][dy] == '.') {temp = 1; if(f.d==i)TmpType = MoveStep;else {temp++;switch (i){case 0:TmpType = ChangeTheDirToDown;break;case 1:TmpType = ChangeTheDirToUp;break;case 2:TmpType = ChangeTheDirToRight;break;case 3:TmpType = ChangeTheDirToLeft;break;}}}for (int k = 0; k < f.step; k++)TmpPath[k] = f.Path[k];TmpPath[f.step] = TmpType;Node tmp = { dx, dy, f.s + temp};for (int k = 0; k <= f.step; k++) tmp.Path[k] = TmpPath[k];tmp.step = f.step + 1; tmp.d = i;q.push(tmp);}}}return -1;}}

70行变200行,吓尿【一些代码有点傻,懒得改了】
C#显示路径那段代码是这个样子的:
 #region AutoRun 方法        public static void AutoRun()        {            for (int i = 0; i <TotalStep; i++)            {                switch (GameObject.AcationPath[i])                {                    case TankAcationType.ChangeTheDirToUp:                        MessageBox.Show("向上");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Up;                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeTheDirToDown:                        MessageBox.Show("向下");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Down;                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeTheDirToLeft:                        MessageBox.Show("向左");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Left;                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeTheDirToRight:                        MessageBox.Show("向右");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Right;                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.FireOneWall:                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.FireTwoWall:                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                         SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.MoveStep:                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToDownFireOne:                        MessageBox.Show("向下");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Down;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToDownFireTwo:                        MessageBox.Show("向下");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Down;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToLeftFireOne:                        MessageBox.Show("向左");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Left;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToLeftFireTwo:                        MessageBox.Show("向左");                        GameObject.Cost++;                         SingleObject.GetObject().T.Dir = Direction.Left;                         MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToRightFireOne:                        MessageBox.Show("向右");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Right;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToRightFireTwo:                        MessageBox.Show("向右");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Right;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToUpFireOne:                        MessageBox.Show("向上");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Up;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                    case TankAcationType.ChangeToUpFireTwo:                        MessageBox.Show("向上");                        GameObject.Cost++;                        SingleObject.GetObject().T.Dir = Direction.Up;                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("开火");                        SingleObject.GetObject().T.Fire();                        MessageBox.Show("向前");                        SingleObject.GetObject().T.Move();                        break;                }            }        }        #endregion


这个过程中出现了好几个隐蔽的bug,大大小小——有些东西根本无法依靠debug找出来。。。。
这些东西完成之后就剩下一些细节了【“新游戏”启动界面 什么的】 之前想过的“导入地图”等功能现在还不想动了【应该可以利用文件操作实现吧】,开学再慢慢研究*_*

三、类图[在新标签页打开查看大图]




四、效果











【转载请注明出处】
 作者:MummyDing
 出处:http://blog.csdn.net/mummyding/article/details/43965923


                                                                                                                                                                                                                           2015年2月27日




0 0
原创粉丝点击