C++开发游戏——坦克大战(1)


工具:vs2013,EasyX
代码来自于简书上的一位博主,理解上面的代码,并且写上一些注释,在自己电脑上跑一遍
代码来源
在这里插入图片描述

创建绘图界面

在这个工程中,用EasyX画布相关的功能创建两个文件:Graphic.h和Graphic.cpp

Graphic.h

#ifndef __GRAPHIC_H__
#define __GRAPHIC_H__

#include <graphics.h>

#define SCREEN_WIDTH    800
/*
实现创建和销毁画布的功能,还能够让其他代码随时通过这个类拿到画布的尺寸
*/
#define SCREEN_HEIGHT   600

class Graphic
{
public:
	static void Create(); //创建
	static void Destroy(); //销毁
	static int GetScreenWidth();//获取宽度
	static int GetScreenHeight();//获取高度
private:
	static int m_screen_width;//静态成员变量需要在类外定义
	static int m_screen_height;
};

#endif

Graphic.cpp

#include "Graphic.h"

int Graphic::m_screen_width = SCREEN_WIDTH;
int Graphic::m_screen_height = SCREEN_HEIGHT;

void Graphic::Create()
{
	initgraph(m_screen_width, m_screen_height); //设置画布大小
}

void Graphic::Destroy()
{
	closegraph(); //关闭绘图窗口
}

int Graphic::GetScreenWidth()
{
	return m_screen_width; //获得画布宽度
}

int Graphic::GetScreenHeight()
{
	return m_screen_height; //获得画布高度
}

坦克抽象类

所有坦克都抽象这个基类,特定坦克会继承这个基类,并且重写基类的纯虚函数。
建文件Tank.h,加入下面代码:

#ifndef __TANK_H__
#define __TANK_H__

#include "Graphic.h"

enum Dir { UP, DOWN, LEFT, RIGHT }; //定义了一个枚举类型,表示方向

class Tank
{
public:
	virtual void Display() = 0; //定义显示纯虚函数
	virtual void Move() = 0;//定义移动纯虚函数

protected:
	int m_x; //定义x坐标
	int m_y;//定义y坐标
	COLORREF m_color; //使用 RGB 函数来初始化 COLORREF

	Dir m_dir; //m_dir保存坦克的行驶方向
	int m_step;
};

#endif

玩家坦克

创建文件MainTank.h,写入下面代码:

/*
战坦克就是玩家控制的坦克,所有的坦克中,只有这个一个是可以控制的
*/
#ifndef __MAIN_TANK__
#define __MAIN_TANK__

#include "Tank.h"

class MainTank : public Tank //公有继承Tank基类
{
public:
	MainTank()
	{   //初始化主坦克的位置,颜色,移动方向,移动距离
		m_x = 400;
		m_y = 300;
		m_color = WHITE;
		m_dir = Dir::UP;
		m_step = 2;
	}

	~MainTank(){}

	// 设置行驶方向
	void SetDir(Dir dir);

	void Display();//重写基类的纯虚函数
	void Move();

protected:
	// 绘制坦克主体外观
	void DrawTankBody(int style);
};

#endif

实现,创建文件MainTank.cpp代码如下:

#include "MainTank.h"

void MainTank::SetDir(Dir dir)
{
	m_dir = dir;
}

void MainTank::DrawTankBody(int style)
{
	fillrectangle(m_x - 4, m_y - 4, m_x + 4, m_y + 4); //绘制坦克机身

	if (style == 1)
	{
		fillrectangle(m_x - 8, m_y - 6, m_x - 6, m_y + 6); //绘制坦克两条履带
		fillrectangle(m_x + 6, m_y - 6, m_x + 8, m_y + 6);
	}
	else
	{
		fillrectangle(m_x - 6, m_y - 8, m_x + 6, m_y - 6);
		fillrectangle(m_x - 6, m_y + 6, m_x + 6, m_y + 8);
	}
}

void MainTank::Display()
{
	COLORREF color_save = getfillcolor();  //获取当前设备填充颜色

	setfillcolor(m_color);  //设置当前设备填充颜色

	switch (m_dir)
	{
	case UP:
		DrawTankBody(1);
		line(m_x, m_y, m_x, m_y - 10); //绘制炮台
		break;
	case DOWN:
		DrawTankBody(1);
		line(m_x, m_y, m_x, m_y + 10);
		break;
	case LEFT:
		DrawTankBody(0);
		line(m_x, m_y, m_x - 10, m_y);
		break;
	case RIGHT:
		DrawTankBody(0);
		line(m_x, m_y, m_x + 10, m_y);
		break;
	default:
		break;
	}

	setfillcolor(color_save);
}

void MainTank::Move()
{
	switch (m_dir)
	{
	case UP:
		m_y -= m_step; //移动距离
		if (m_y < 0)
			m_y = Graphic::GetScreenHeight() - 1; //超出屏幕边沿时,从另一侧重新出现
		break;
	case DOWN:
		m_y += m_step;
		if (m_y > Graphic::GetScreenHeight())
			m_y = 1;
		break;
	case LEFT:
		m_x -= m_step;
		if (m_x < 0)
			m_x = Graphic::GetScreenWidth() - 1;
		break;
	case RIGHT:
		m_x += m_step;
		if (m_x > Graphic::GetScreenWidth())
			m_x = 1;
		break;
	default:
		break;
	}
}

主函数

根据键盘上的方向键,监听按键,实现坦克的方向移动

#pragma warning(disable:4996)

#include <iostream>
#include <conio.h>
#include <time.h>

#include "Graphic.h"
#include "MainTank.h"

using namespace std;

void main()
{
	Graphic::Create();

	MainTank mainTank;

	bool loop = true;
	bool skip = false;
	while (loop)
	{
		/*
		通过kbhit()捕捉键盘动作,该函数是一个非阻塞函数,不管有没有按键被按下,该函数都会立即返回
		之后再通过getch()得到按下键的码值
		使用_getch读取字符时,读取一次就行;在读取方向键和功能键的时候,需要读取两次
		*/
		if (kbhit())  //检测到用户按下某键时就会返回真
		{
			int key = _getch(); //返回用户按键

			switch (key)
			{
				// Up
			case 72:
				mainTank.SetDir(Dir::UP);
				break;
				// Down
			case 80:
				mainTank.SetDir(Dir::DOWN);
				break;
				// Left
			case 75:
				mainTank.SetDir(Dir::LEFT);
				break;
				// Right
			case 77:
				mainTank.SetDir(Dir::RIGHT);
				break;
			case 224: // 方向键高8位
				break;
				// Esc
			case 27: //退出
				loop = false;
				break;
				// Space
			case 32:
				break;
				// Enter
			case 13:  //暂停功能
				if (skip)
					skip = false;
				else
					skip = true;
				break;
			default:
				break;
			}
		}

		if (!skip) //默认为flase
		{
			cleardevice(); //清空绘图设备
			mainTank.Display();
			mainTank.Move();
		}

		Sleep(200); //休眠时间,相当于设置坦克的速度
	}

	Graphic::Destroy();
}
游戏分里外两个部分组成,里部分(用户不可见) 通过里部分执行判断,地图数组更改,和各种值的改变。更改完里部分再根据相应变化更改表部分。(用户可视部分)表部分的打印通过gotoxy去到相应坐标再printf打印出字符,通过文本函数改变文字字体颜色与文字背景颜色与字符组合实现图形界面。 程序通过 计数器+循环判断 的思想,类似单核cpu的多线程实现(单线程在不同程序/函数间来回执行)省去了多线程。(具体过程在功能设计与描述有详细描述) 另AI实现与加强依赖于rand随机函数的运用,进一步强化AI,增加游戏乐趣 功能方面,游戏参考于80年代任天堂红白机(FC/FamilyComputer)上的游戏坦克大战(Battle City),包括地图,游戏模式等等(当时的游戏直接烧在电路板上)。所以游戏平衡方面已经有了很好的参考,无需再花大量时间测试平衡性。 但诸如地图中的树林元素,随机道具等没有实现。但较之原版,该游戏由C/C++编写PC运行,由字符界面实现游戏画面。原版一辆坦克的子弹未消失之前不能发射第二颗。导致子弹打击远处CD长,近处CD短。该游戏每个子弹都有相同CD,子弹未消失只要CD达到即可发射第二颗,第三颗…增加了真实性,相较于原版是个改进。且考虑到PC性能不一内置了游戏速度调整。玩家可根据PC性能调整至合适的速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值