QT之坦克大战
目录
设计思路
首先使用二维数组绘制存放地图信息,并在主界面绘制地图,然后通过主界面中的定时器进行地图刷新绘制。
初始状态下,绘制一辆己方的坦克、随机生成三辆敌方坦克。使用W、S、A、D、空格键,控制我方坦克的移动和子弹发射。检测坦克碰撞类型,并作出相应的限制和操作。
子弹发射后,创建一个子弹对象,记录子弹的方向、当前所在位置,加入容器。检测子弹碰撞类型,并做出对应的操作。
效果展示
使用的类
程序主要分为地图类、坦克类、子弹类以及游戏主界面
地图类:使用2626的二维int数组。基本单位是1515像素的小地图块。
计时器:每5ms刷新一次。
坦克类:坦克为30*30像素的图片,分为我方坦克和敌方坦克。
成员变量:横纵坐标、坦克方向、生命值
敌对方坦克被子弹击中一次后消失
子弹类:子弹为6*6像素的图片
成员变量:横纵坐标、子弹方向、子弹存活状况
游戏主界面:包含绘制的地图、坦克、子弹
程序概述
地图绘制
重写绘画事件(paintEvent),定义画家来绘制地图、坦克和子弹,由计时器(timer)激发绘画事件,呈现出坦克和子弹移动的动态效果。
坦克移动
我方坦克
设置四个bool型数据,分别代表上下左右。如果某一数据为true,则表示向该方向移动。重写键盘按压事件(mouseEvent),捕捉键值来改变这四个bool类型的值。
每当计时器(timer)运行一次,就对捕捉的键值进行判断。当只有这四个数据中的某一个数据为true时,我方坦克就根据在该方向上的移动规则移动。
移动判断:
首先判断坦克是否越界,即横纵坐标是否满足整个坦克在游戏界面。
坦克与地图块的碰撞分为以下情况:地图为空、地图为墙壁。
地图为空:正常前进;
地图为墙壁:不前进;
碰撞检测:将坦克横纵坐标转换成对应的地图数组坐标,判断即将前进的地图类型是否空,为空就可以前进,否则不前进。判断地图时类型时,有两种情况:1、坦克刚好在两个小地图块。2、坦克在三个小地图块中间。
敌方坦克
设置四个bool型数据,分别代表上下左右。如果某一数据为true,则表示向该方向移动。生成随机数,判断随机数的范围,进而控制敌方坦克的移动方向,30%的概率转向,70%的概率直行。
每当计时器(timer)运行一次,就对随机数范围进行判断。当只有这四个数据中的某一个数据为true时,敌方坦克就根据在该方向上的移动规则移动。
移动判断:
首先判断坦克是否越界,即横纵坐标是否满足整个坦克在游戏界面。
坦克与地图块的碰撞分为以下情况:地图为空、地图为墙壁。
地图为空:正常前进;
地图为墙壁:不前进;
碰撞检测:将坦克横纵坐标转换成对应的地图数组坐标,判断即将前进的地图类型是否空,为空就可以前进,否则不前进。判断地图时类型时,有两种情况:1、坦克刚好在两个小地图块。2、坦克在三个小地图块中间。
子弹移动
设置int类型的数据,分别表示子弹的横纵坐标、方向和存活状况。子弹的方向一旦产生,就固定不变。
每当计时器(timer)运行一次,就对子弹进行移动判断,满足条件即改变依次坐标,进行移动;不满足条件,做出相应的操作。
移动判断:
首先判断子弹是否越界,即横纵坐标是否子弹在游戏界面。
子弹与地图块的碰撞分为以下情况:地图为空、地图为墙壁。
地图为空:子弹移动;
地图为墙壁:子弹消失,土墙消失,铁墙不变;
子弹与坦克的的碰撞:敌方坦克消失、子弹消失( vector.remove() )。
碰撞检测:将子弹的横纵坐标转换成对应的地图数组坐标,判断即将前进的地图类型是否空,为空就可以前进,否则子弹和对应的地图都消失。判断地图时类型时,有两种情况:1、子弹刚好在一个小地图块。2、子弹在两个小地图块中间。
子弹发射
重写键盘按压事件(mouseEvent),捕捉键值,为空格键发射子弹。
首先定义一个子弹类型的容器(vector),每发射一颗子弹,便用子弹类创建一个对象,记录该时刻横纵坐标、方向,然后将该对象加入容器中( vector.append() )。
每当计时器(timer)运行一次,就对容器里的子弹用for循环遍历( vector.count() ),进行移动和碰撞检测。
相关代码
buttle.h
#ifndef BULET_H
#define BULET_H
#include <QPixmap>
class bulet
{
public:
QPixmap *bulet_pic;
bulet();
void set_pos(int x, int y ,int dir);
int bulet_dir;
int bulet_x;
int bulet_y;
void move();
private:
int bulet_blood = 1;
};
#endif // BULET_H
map.h
#ifndef MAP_H
#define MAP_H
#include <QWidget>
#include <QVector>
#include <QLabel>
#include <QPixmap>
#include <QPaintEvent>
#include <QPainter>
class map : public QWidget
{
Q_OBJECT
public:
explicit map(QWidget *parent = nullptr);
int mapbuf[26][26]={{0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,3,3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,3,3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,3,3,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,0,0,2,2,2,2,2,2,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,2,2,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}}; //26*26的数组,一小块代表15*15像素
void display();
void paintEvent(QPaintEvent *event);
QPixmap *q;
signals:
public slots:
private:
};
#endif // MAP_H
tank.h
#ifndef TANK_H
#define TANK_H
#include <QWidget>
#include <QPixmap>
#include "bulet.h"
class tank : public QWidget
{
Q_OBJECT
public:
explicit tank(int b,QWidget *parent = nullptr);
void way_key(int);
bool test_blood();
void move();
int old_y;
int old_x;
int jiaodu;
int t_dir = 0;
QPixmap *d_tank;
void set(int x, int y){
old_x = x;
old_y = y;
}
bool up = false; //向前
bool back = false; //向后
bool right = false; //向右
bool left = false; //向左
QVector<bulet *> buletlist;
signals:
public slots:
private:
int blood; //血量
};
#endif // TANK_H
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include "map.h"
#include "tank.h"
#include <QWidget>
#include <QPaintEvent>
#include <QTimerEvent>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QMatrix>
#include "bulet.h"
#include <QtGlobal>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *event);
void mousePressEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
bool move_t(int direct);
void my_move();
void d_move(tank *);
void bulet_move(int i);
bool d_move_t(int drect, tank *t);
private:
//QPainter *p;
int jiaodu = 0;
int old_y; //
int old_x;
QPixmap *back;
//我方坦克的类
tank *mytank;
QPixmap *my; //坦克图片
// QPixmap *new_my;
//地方坦克的类(20个)
QVector<tank *> tanklist;
int k = 999;
//地图的类
map *mymap;
//计数时间
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
buttle.cpp
#include "bulet.h"
bulet::bulet()
{
}
void bulet::set_pos(int x, int y,int dir)
{
bulet_x = x;
bulet_y = y;
bulet_dir = dir;
}
void bulet::move()
{
}
map.cpp
#include "map.h"
#include <QDebug>
map::map(QWidget *parent) : QWidget(parent)
{
qDebug() << "dasdmmmm";
}
void map::paintEvent(QPaintEvent *event)
{
}
void map::display()
{
update();
}
tank.cpp
#include "tank.h"
#include <QDebug>
tank::tank(int b,QWidget *parent) : QWidget(parent), blood(b)
{
}
void tank::way_key(int key)
{
qDebug() << key;
switch (key) {
case 65 :left = true; break;
case 83 :back = true; break;
case 87 :up = true; break;
case 68 :right = true; break;
}
}
bool tank::test_blood()
{
if(blood == 0){ //表示死亡
return false;
}else{
return true; //表示存货
}
}
void tank::move()
{
}
widget.cpp
#include "widget.h"
#include "QDebug"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//setFixedSize(800,800);
//定义地图类的对象
setFixedSize(600,390);
mymap = new map;
//设置地图
mymap->q = new QPixmap(390,390);
mymap->q->fill(Qt::black);
//定义坦克类的对象(我方与敌方)
mytank = new tank(3);
my = new QPixmap;
my->load(":/mytamke.png");
old_x = 120;
old_y = 360;
startTimer(5);
}
void Widget::paintEvent(QPaintEvent *event) //写的代码过多,此处以流程代写
{
//绘制地图
/*绘制我方坦克
坦克移动判断(包含碰撞)*/
/*绘制敌方坦克
坦克移动判断(包含碰撞)*/
/*绘制子弹
子弹移动判断(包含碰撞)*/
}
//我方坦克碰撞检测
bool Widget::move_t(int drect)
{
}
//敌方坦克碰撞检测
bool Widget::d_move_t(int drect, tank *t)
{
}
//我方坦克移动
void Widget::my_move()
{
}
//敌方坦克移动
void Widget::d_move(tank * t)
{
}
//重写键盘按压事件
void Widget::keyPressEvent(QKeyEvent *event)
{
}
//主界面的析构函数
Widget::~Widget()
{
}