近期培训期间做的基于C++的坦克小游戏,欢迎评论。
首先是主驱动部分:tankclient.h,和tankclient.cpp
tankclient.h部分
#ifndef TANKCLIENT_H
#define TANKCLIENT_H#endif // TANKCLIENT_H
tankclient.cpp部分
#include "tankclient.h"
#include
#include "tank.h"
#include "missile.h"
#include"explode.h"
TankClient::TankClient(QWidget *parent)
: QMainWindow(parent)
{
//创建窗体 ALT+/自动补全
//默认快捷方式ctrl+space
//设置标题
setWindowTitle(tr("坦克大战"));
//设置大小
setFixedSize(GAME_W,GAME_H);
//设置背景
setStyleSheet("background-color:black");
//初始化坐标
//x=200;
//y=200;
//启动定时器
startTimer(50);//参数:long(毫秒)
//初始化主站坦克
tank=new Tank(200,200,30,30,this,true);
//初始化敌军坦克
for(int i=0;i<10;++i){
Tank* t=
new Tank(30+40*i,350,30,30,this,false);
etanks.push_back(t);
}
}
//实现画图的方法
//当界面刷新的时候被系统自己调用
void TankClient::paintEvent(QPaintEvent *){
//输出
qDebug("paint...");
//创建画布对象
QPainter p(this);
//显示子弹的个数
p.setPen(Qt::white);
p.drawText(0,15,tr("子弹的个数:")+QString::number(missiles.size()));
//画出主站坦克
tank->draw(p);
//画出子弹
for(int i=0;i
Missile* m=missiles[i];
m->draw(p);
//调用hitTanks
m->hitTanks(etanks);
m->hitTank(tank);
}
//画出敌军坦克
for(int i=0;i
t->draw(p);
}
//画出爆炸效果
for(int i=0;i
e->draw(p);
}
//假设界面刷新的时候向右移动
//采用定时器或者多线程Thread
//x+=1;
}
//定义定时器的方法
void TankClient::timerEvent(QTimerEvent *){
//调用paintEvent方法
repaint();//reset+paint 重绘
}
//定义键盘事件(压下)方法
void TankClient::keyPressEvent(QKeyEvent *e){
//获取键盘的ASCII(中 日本 韩)码
//合资项目(外包项目)
//整理代码:ctrl+i
int key=e->key();
if(tank->live)
tank->keyPress(key);
}
//定义键盘事件(松开)方法
void TankClient::keyReleaseEvent(QKeyEvent *e){
int key=e->key();
//调用tank里面抬起方法
if(tank->live)
tank->keyRePress(key);
}
TankClient::~TankClient()
{
}
然后是Tank部分
tank.h部分
#ifndef TANK_H
#define TANK_H
#include
#include "pub.h"//usr/bin/include
class TankClient;
class Tank
{
public:
Tank(int x,int y,
int w,int h,TankClient *tc,bool good);
//属性
//朝某一个方向随机走的步数
int step;
//方向
Dir dir;
//炮筒的方向
Dir ptDir;
//四个按键
bool bu,bd,bl,br;
//坐标
int x,y;
//宽高(半径)
int w,h;
//颜色
bool good;
//存活
bool live;
//方法
//画
void draw(QPainter&p);
//键盘压下
void keyPress(int key);
//键盘松开
void keyRePress(int key);
//通过键盘的2个事件
//确定四个按钮的状态方法
void confimDir();
//移动
void move();
//开火
void fire(Dir ptDir);
void firePlus();
//持有TankClient
TankClient* tc;
//求出当前的外切四边形
QRect getRect();
};
#endif // TANK_H
tank.cpp部分
#include "tank.h"
#include"tankclient.h"
Tank::Tank(int x, int y,
int w, int h,TankClient* tc,bool good)
{
this->x=x;
this->y=y;
this->w=w;
this->h=h;
this->tc=tc;
this->good = good;
//初始方向默认为朝下
dir=STOP;
//初始化四个按键默认值
bu=bd=bl=br=false;
//炮筒的默认方向
ptDir=U;
live = true;
step = qrand()%15+3;//(3,17)
}
//画(成员方法 this:当前对象)
void Tank::draw(QPainter&q){
if(!live){
tc->etanks.removeOne(this);
return;
}
if(good){
//设置颜色
q.setPen(Qt::red);
//设置填充的颜色
q.setBrush(Qt::red);
}else{
//设置颜色
q.setPen(Qt::blue);
//设置填充的颜色
q.setBrush(Qt::blue);
}
//画出实心坦克 oval Iamge Rect
q.drawEllipse(x,y,w,h);
//坦克的方向发生改变,就移动dir
move();
//画出炮筒
if(dir!=STOP){
ptDir=dir;
}
//根据炮筒方向画出直线
q.setPen(Qt::white);
switch(ptDir){
case U:q.drawLine(x+w/2,y+h/2,x+w/2,y);break;
case D:q.drawLine(x+w/2,y+h/2,x+w/2,y+h);break;
case L:q.drawLine(x+w/2,y+h/2,x,y+h/2);break;
case R:q.drawLine(x+w/2,y+h/2,x+w,y+h/2);break;
case LU:q.drawLine(x+w/2,y+h/2,x,y);break;
case LD:q.drawLine(x+w/2,y+h/2,x,y+h);break;
case RU:q.drawLine(x+w/2,y+h/2,x+w,y);break;
case RD:q.drawLine(x+w/2,y+h/2,x+w,y+h);break;
default:break;
}
}
//键盘压下
void Tank::keyPress(int key){
switch(key){
case Qt::Key_Up:bu=true;break;
case Qt::Key_Down:bd=true;break;
case Qt::Key_Left:bl=true;break;
case Qt::Key_Right:br=true;break;
case Qt::Key_F:fire(ptDir);break;//开火
case Qt::Key_A:firePlus();break;
default:break;
}
confimDir();
}
void Tank::firePlus(){
for(int i=0;i<8;i++){
fire(Dir(i));
}
}
//键盘松开
void Tank::keyRePress(int key){
switch(key){
case Qt::Key_Up:bu=false;break;
case Qt::Key_Down:bd=false;break;
case Qt::Key_Left:bl=false;break;
case Qt::Key_Right:br=false;break;
default:break;
}
confimDir();
}
//通过键盘的2个事件
//确定四个按钮的状态方法
void Tank::confimDir(){
if(bu&&!bd&&!bl&&!br)dir=U;
else if(!bu&&bd&&!bl&&!br)dir=D;
else if(!bu&&!bd&&bl&&!br)dir=L;
else if(!bu&&!bd&&!bl&&br)dir=R;
else if(bu&&!bd&&bl&&!br)dir=LU;
else if(!bu&&bd&&bl&&!br)dir=LD;
else if(bu&&!bd&&!bl&&br)dir=RU;
else if(!bu&&bd&&!bl&&br)dir=RD;
else dir=STOP;
//move(); 不科学
}
#include "tankclient.h"//不建议
//移动
void Tank::move(){
switch(dir){
case U:y-=5;break;
case D:y+=5;break;
case L:x-=5;break;
case R:x+=5;break;
case LU:x-=5;y-=5;break;
case LD:x-=5;y+=5;break;
case RU:x+=5;y-=5;break;
case RD:x+=5;y+=5;break;
default:break;
}
//处理坦克遇到边界的情况
if(x<=0)x=0;//左
if(y<=5)y=5;//上
if(x>=TankClient::GAME_W-w)
x=TankClient::GAME_W-w;//右
if(y>=TankClient::GAME_H-h)
y=TankClient::GAME_H-h;//下
//让敌军坦克智能化
if(!good){
//随机开火
if(qrand()%40>37)fire(ptDir);
if(step ==0 ){
//朝一个方向走的步数剩下为0
dir = Dir(qrand()%9);
step = qrand()%15+3;
}
step--;
}
}
#include "missile.h"
//坦克开火
void Tank::fire(Dir ptDir){
//思路:F-->new Missile-->画出来(QPainter p)
Missile* m=new Missile(x+w/2,y+h/2,w/5,h/5,ptDir,tc,good);
//m应该注入到tankClient里面missiles集合
tc->missiles.push_back(m);
}
//求出当前的外切四边形
QRect Tank::getRect(){
return QRect(x,y,w,h);
}
之后是炮弹部分missile
missile.h部分
#ifndef MISSILE_H
#define MISSILE_H
#include "pub.h"
#include
class TankClient;
class Tank;
class Missile
{
public:
Missile(int x,int y,int w,int h,Dir dir,TankClient *tc,bool good);
//坐标
int x,y;
//宽高
int w,h;
//方向
Dir dir;
//存活
bool live;
//好坏
bool good;
//画图
void draw(QPainter&p);
//移动
void move();
//求出当前的外切四边形
QRect getRect();
//一枚子弹打击一辆坦克
bool hitTank(Tank *t);
TankClient *tc;
//所有的子弹去打击所有敌军坦克
void hitTanks(QList
};
#endif // MISSILE_H
missile.cpp
部分
#include "missile.h"
#include"tankclient.h"
#include"explode.h"
Missile::Missile(int x, int y, int w, int h, Dir dir,TankClient *tc,bool good)
{
//属性
this->x=x;
this->y=y;
this->w=w;
this->h=h;
this->dir=dir;
this->tc = tc;
this->live= true;
this->good = good;
}
//画图
void Missile::draw(QPainter&p){
if(!live){
//死亡
//删除集合中的子弹
tc->missiles.removeOne(this);
return;
}
if(good){
//设置画笔
p.setPen(Qt::red);
//填充颜色
p.setBrush(Qt::red);
}else{
//设置画笔
p.setPen(Qt::blue);
//填充颜色
p.setBrush(Qt::blue);
}
//画出图形
p.drawEllipse(x,y,w,h);
move();
}
//移动
//ctrl+F/ctrl+R置换
void Missile::move(){
switch(dir){
case U:y-=20;break;
case D:y+=20;break;
case L:x-=20;break;
case R:x+=20;break;
case LU:x-=20;y-=20;break;
case LD:x-=20;y+=20;break;
case RU:x+=20;y-=20;break;
case RD:x+=20;y+=20;break;
default:break;
}
//处理子弹遇到边界
if(x<=0 || y<=0
|| x>=TankClient::GAME_W-w
|| y>=TankClient::GAME_H-h)
live=false;
}
//求出当前的外切四边形
QRect Missile::getRect(){
return QRect(x,y,w,h);
}
#include"tank.h"
//一枚子弹打击一辆坦克
bool Missile::hitTank(Tank *t){
if(t->live&&this->good!=t->good&&this->getRect().intersects(t->getRect())){
//子弹和坦克都死亡
this->live = false;
t->live = false;
//创建一个爆炸效果
explode* e = new explode(x,y,w,h,tc);
//装到explodes
tc->explodes.push_back(e);
return true;
}
return false;
}
//所有的子弹去打击所有敌军坦克
void Missile::hitTanks(QList
for(int i=0;i
if(hitTank(t))
return;
}
}
之后是爆炸效果部分:
头文件:
#ifndef EXPLODE_H#endif // EXPLODE_H
cpp文件
最后就是一些定义和主函数:
#ifndef PUB_H
#define PUB_H
//定义坦克的方向
typedef enum Dir{
U,D,L,R,LU,LD,RU,RD,STOP
}Dir;
#endif // PUB_H
#include
#include "tankclient.h"
#include
int main(int argc, char *argv[])
{
//解决编码问题
//QT本地的编码是 中文繁体 big5
//GBK GB2312 中文简体 oracle/mysql/sqlite/c++
//ISO-8859-1 西欧 JAVAWEB
//utf 国际编码 Android/h5
QTextCodec::setCodecForTr(
QTextCodec::codecForLocale()
);
QApplication a(argc, argv);
TankClient w;
w.show();
return a.exec();
}
谢谢