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

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 DLL
2.添加头文件"" 在头文件中加入以下代码:
#ifndef DLL_EXPORT
#define DECLDIR __declspec(dllimport)
#else
#define DECLDIR __declspec(dllexport)
#endif
3.添加源程序,添加以下代码:
#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            ushort
DWORD            uint
UCHAR            int/byte   大部分情况都可以使用int代替,而如果需要严格对齐的话则应该用bytebyte
UCHAR*            string/IntPtr
unsigned char*         [MarshalAs(UnmanagedType.LPArray)]byte[]/?(Intptr)
char*            string
LPCTSTR            string
LPTSTR            [MarshalAs(UnmanagedType.LPTStr)] string
long            int
ulong               uint
Handle            IntPtr
HWND            IntPtr
void*            IntPtr
int            int
int*            ref int
*int            IntPtr
unsigned int        uint
COLORREF                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
{
	//Move
	MoveStep,
	//Fire Move
	FireOneWall,
	//Fire Fire Move
	FireTwoWall,

	//Dir->Up Move
	ChangeTheDirToUp,
	//Dir->Up Fire
	ChangeToUpFireOne,
	//Dir->Up Fire Fire
	ChangeToUpFireTwo,

	//Dir->Down Fire
	ChangeToDownFireOne,
	//Dir->Down Move
	ChangeTheDirToDown,
	//Dir->Down Fire Fire
	ChangeToDownFireTwo,

	//Dir->Left Move
	ChangeTheDirToLeft,
	//Dir->Left Fire
	ChangeToLeftFireOne,
	//Dir->Left Fire Fire
	ChangeToLeftFireTwo,

	//Dir->Right Move
	ChangeTheDirToRight,
	//Dir->Right Fire
	ChangeToRightFireOne,
	//Dir->Right Fire Fire
	ChangeToRightFireTwo,
	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日

时间: 2024-10-20 15:11:38

DS课设【坦克大战最短路】(MummyDing)的相关文章

JAVA课程设计(坦克大战)

2019-01-16 坦克大战游戏背景: 1. 需求分析 1.1环境要求 操作系统:Windows 7(SP1)以上 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 1.2角色设定 用户在系统中扮演的角色,以及可以执行的职责. 玩 家 操纵玩家坦克,与敌方坦克作战,同时保护本基地.敌方坦克随机移动,发射子弹. 1.3设定玩家(玩家一,玩家二,即一个人玩还是两个人玩),我方坦克的方向和子弹由用户控制,所有墙块都可以打碎,但是铁墙是打不碎的,草地不能阻止坦克和子弹的前进,河

java课程设计--坦克大战

java课程设计--坦克大战 一. 团队课程设计博客链接 https://www.cnblogs.com/zwtcyt/p/12173572.html 二.个人负责模块和任务说明 墙体类,子弹类,道具类以及音效类的编写,部分GUI的编写 三.代码的提交记录截图 四.负责模块和任务详细说明 墙体类 主墙体即不可摧毁的墙体 该类为所有障碍物的父类,子类继承时改变里面draw方法 草地类 河流类 可摧毁的墙类 音效类 子弹类 子弹与碰撞检测 利用javafx中shape的intersect方法来得出两

【Cocos2D-x 3.5实战】坦克大战(1)环境配置

前言: 最近课比较少,空闲时间比较多,一有时间就东想西想,想着想着就突然想到做手机游戏(android)了,学习下CoCos2d.看了一些CoCos2D的相关文档和教程,觉得是时候实战了,但是苦于没有什么新奇的游戏点子,只有写下被儿时玩过的坦克大战了(主要素材好找).而这个系列的文章来记录下我的开发过程. 开发环境: Win7(x64) VS2012  下载地址: http://www.itellyou.cn/ Eclipse  下载地址:http://www.eclipse.org/downl

Html 5 坦克大战(韩顺平版本)

html 5代码部分如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> </head> <body onkeydown="getCommand();"> <h1>hmtl5-经典的坦克大战</h1> <!--坦克大战的战场--> <canvas id="tankMap"

java制作简单的坦克大战

坦克大战是我们小时候玩红白机时代的经典游戏,看到有不少小伙伴都使用各种语言实现了一下,手痒痒,也使用java做的一个比较简单的坦克大战,主要面向于学过Java的人群,与学了一段时间的人,有利于面向对象思想的提高,推荐给大家. 详情请参照注释,这里就不多废话了,实现一下儿时的经典而已. Blood.java ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 3

帧同步坦克大战匹配系统

在介绍匹配系统之前,先说一下项目的整体结构. 项目主要有四个场景: start --> home --> choose --> game start_scene: 是游戏的开始场景,在此场景主要做了微信授权,获取用户的昵称,头像等信息.通过云函数获取用户的openid(不了解云函数的可以参考这篇文章:微信云开发使用教程).然后把用户的信息和用户的openid都放到全局对象Global里边,方便以后使用. home_scene: 授权成功之后,就跳转到此场景. 进入此场景之后,需要初始化M

坦克大战系列(3.0版)

无论头上是怎样的天空,我准备承受任何风暴.--拜伦 本讲内容:坦克3.0版(面向对象的思想) 要求:画出我方坦克会动并且会发射子弹.画出敌人坦克 一.同一个包下建二个文件分别为:MyTankGame.Members(负责其它成员譬如:制造坦克.子弹等) MyTankGame类 /** * 功能:坦克游戏的3.0版本 * 1:画出坦克 * 2:实现我方坦克移动并且會發子彈,并 画出敌人的坦克 */ package a; import javax.swing.*; import java.awt.*

C++代码训练之坦克大战(2)

这一篇中,我们继续继续进行我们的坦克大战. 位置信息数据结构 在游戏设计过程中,需要记录大量的位置信息,如果仅仅使用(x,y)坐标很容易出错.这一篇中,我们先定义两个简单的数据结构用来保存点和矩形的信息. 在项目中新建Model目录,创建下面四个文件: 代码如下: Point.h #ifndef __POINT_H__ #define __POINT_H__ class Point { public: Point(int x = 0, int y = 0) : m_x(x), m_y(y){};

坦克大战(版本2.5-版本2.9)

版本2.5 功能:添加“血块”步骤:        1)添加blood类        2)添加必要的方法:eat方法等        3)让blood对象固定轨迹运动, 并在一定时间后消失 具体代码实现: 新增的blood类: 1 import java.awt.Color; 2 import java.awt.Graphics; 3 import java.awt.Rectangle; 4 5 //模拟血块,坦克吃了可以补血 6 public class Blood { 7 int x, y