2025年qt实现坦克大战

qt实现坦克大战前言 前一阵由于一些原因需要做一个坦克大战 想了好几天 终于算是大致实现了 由于时间紧 做得很粗糙 只能在这将一些大致的想法讲给大家 希望有所帮助 地图的实现 这一部分我建议是建立一个地图类 在类中定义一个二维数组 二维数组的行列号对应地图的行列号

大家好,我是讯享网,很高兴认识大家。

前言

前一阵由于一些原因需要做一个坦克大战,想了好几天,终于算是大致实现了,由于时间紧,做得很粗糙,只能在这将一些大致的想法讲给大家,希望有所帮助

地图的实现

这一部分我建议是建立一个地图类,在类中定义一个二维数组,二维数组的行列号对应地图的行列号,再声明并实现一个为这个数组赋值的函数,该函数带参,内部就是一个switch语句,通过参数来知道你需要绘制第几关的图像,然后在每一case里为你的数组赋值,比如0代表空地,1代表草之类,数组中数值的不同,最终地图也就不同。

class ditu { 
    public: void guankashu(int gunaka); int map1[17][16]; }; 

讯享网

关卡数的实现如下,我只实现了一关,可以进行添加

讯享网void ditu::guankashu(int guanka){ 
    switch(guanka){ 
    case 0:{ 
    int mapl[17][16]={ 
   { 
   2,0,1,1,1,1,1,1,0,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,0,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,0,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,0,0,5,0,1,1,0}, { 
   0,0,1,1,1,1,1,1,1,3,0,1,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,0,5,0,1,6,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,0,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,2,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,2,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,1,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,2,3,4,5,0,1,1,2}, { 
   0,0,1,1,1,1,1,1,2,3,4,5,0,1,1,2}}; for(int =0;<17;++){ 
    for(int ww=0;ww<16;ww++){ 
    map1[][ww]=mapl[][ww]; } } break; } } 

这之后,你可以在widget.cpp中通过类的对象来调用这个数组及这个函数(在绘图事件中)进行绘制,另外还需要一个将数组中元素转化为对应图片的函数,该函数需要引入数组对应元素,以及该元素的横纵坐标,并且在该函数中将对应图片进行绘制,该函数如下:

void Widget::ditumoxing(QPainter*p,int heng,int zong,int tuxing){ 
    QPixmap pix; switch (tuxing) { 
    case 1: pix=QPixmap(":/tuxiang/1_1.png"); break; case 2: pix=QPixmap(":/tuxiang/2_1.png"); break; case 3: pix=QPixmap(":/tuxiang/3.png"); break; case 4: pix=QPixmap(":/tuxiang/4.png"); break; case 5: pix=QPixmap(":/tuxiang/5.png"); break; case 6: pix=QPixmap(":/tuxiang/boss.png"); break; default: break; } QRect r(heng*60,zong*60,60,60); p->drawPixmap(r,pix ); } 

于是,当你的地图数组在绘图事件中得到了对应赋值后,如果不加限制,由于每次调用绘图事件都会调用地图赋值函数为地图重新赋值,所以需要添加一个if条件,使得该函数的调用全场只有一次,这样才能使之后的地图被破坏的部分得到保留,赋值完毕后就是利用上述地图模型函数在程序里进行绘画,得到地图。

关于开始界面与地图界面的切换

坦克大战有一个开始界面,点击按钮后才会进入真正的游戏画面。我的想法是做一个全局变量,程序一开始时,在绘图事件里满足这个变量,绘制开始界面。

讯享网if(iii==1){ 
    QPixmap map(":/tuxiang/start.png"); QRect q(0,0,600,408); QRect q2(0,0,1020,960); painter.drawPixmap(q2,map,q); a3=0; } 

然后,利用ui制作一个按钮,利用connect与拉姆达表达式,当按钮按下,该全局变量变成0,并且让按钮的尺寸变为0(使按钮消失)。之后重绘图像,进入地图绘制,背景图绘制(全黑即可),以及之后游戏的设计

己方坦克的实现

void Widget::tankemoxing(QPainter*p,int heng,int zong,int tuxing){ 
    QPixmap pix; switch(tuxing){ 
    case 1:{ 
    pix=QPixmap(":/tuxiang/p1tankU.png"); break; } case 2:{ 
    pix=QPixmap(":/tuxiang/p1tankD.png"); break; } case 3:{ 
    pix=QPixmap(":/tuxiang/p1tankL.png"); break; } case 4:{ 
    pix=QPixmap(":/tuxiang/p1tankR.png"); break; } default: break; } QRect r(heng*60,zong*60,60,60); p->drawPixmap(r,pix); } 

这之后,就是在键盘事件中对i1,j1进行实时修改以及对碰撞的检测了,另外,坦克在转向的过程中,比如前一步还在朝前方走,后一步改为朝右时,应该先原地转向,之后在按下右键时才会朝右前进。
下方ditu2为地图数组(其中0,3,5是可穿过单位),i2,j2用于记录上一步坦克位置以便于获得上一步炮口朝向。
具体实现如下:

讯享网void Widget::keyPressEvent(QKeyEvent *event){ 
    int i2=i1,j2=j1; //qDebug()<<event->key(); if(event->key()==Qt::Key_A&&i1>0){ 
    //qDebug()<<event->key(); if(tanke1[i2][j2]==3){ 
    if(ditu2[i1-1][j1]==0||ditu2[i1-1][j1]==3||ditu2[i1-1][j1]==5){ 
    i1=i1-1; tanke1[i1][j1]=tanke1[i2][j2]; tanke1[i2][j2]=0; } } else{ 
    tanke1[i2][j2]=3; } repaint(); } else if(event->key()==Qt::Key_W&&j1>0){ 
    //qDebug()<<event->key(); if(tanke1[i2][j2]==1){ 
    if(ditu2[i1][j1-1]==0||ditu2[i1][j1-1]==3||ditu2[i1][j1-1]==5){ 
    j1=j1-1; tanke1[i1][j1]=tanke1[i2][j2]; tanke1[i2][j2]=0; } } else{ 
    tanke1[i2][j2]=1; } repaint(); } else if(event->key()==Qt::Key_S&&j1<15){ 
    if(tanke1[i2][j2]==2){ 
    if(ditu2[i1][j1+1]==0||ditu2[i1][j1+1]==3||ditu2[i1][j1+1]==5){ 
    j1=j1+1; tanke1[i1][j1]=tanke1[i2][j2]; tanke1[i2][j2]=0; } } else{ 
    tanke1[i2][j2]=2; } repaint(); } else if(event->key()==Qt::Key_D&&i1<16){ 
    if(tanke1[i2][j2]==4){ 
    if(ditu2[i1+1][j1]==0||ditu2[i1+1][j1]==3||ditu2[i1+1][j1]==5){ 
    i1=i1+1; tanke1[i1][j1]=tanke1[i2][j2]; tanke1[i2][j2]=0; } } else{ 
    tanke1[i2][j2]=4; } repaint(); } if(event->key()==Qt::Key_J){ 
    glb[b3].fzd=1; glb[b3].hzb=i1; glb[b3].zzb=j1; if(tanke1[i1][j1]==1) glb[b3].wz=1; else if(tanke1[i1][j1]==2) glb[b3].wz=2; else if(tanke1[i1][j1]==3) glb[b3].wz=3; else if(tanke1[i1][j1]==4) glb[b3].wz=4; b3++; } } 

上述最后的按键 j 是用来发射子弹的,可以先不管

己方子弹的实现

子弹的实现,是这个游戏的核心及难点(我这个实现的不太好,但可以给大家提供参考)
我的想法是构建一个结构体,并以数组方式实现,该结构体能够记录按下发射按键时坦克的位置以及炮口的朝向。该数组就是一个弹匣(无法弹出弹壳),按下发射按键,就往数组中空位置(已有子弹或者子弹已经发射完毕的是非空位置,这样做就限制了一局里可发射子弹的数量)添加一颗子弹,即令fzd=1
子弹结构体:

struct bullet1{ 
    int hzb; int zzb; int wz; int fzd; int kongke; QPixmap map; }; 
讯享网bullet1 glb[70]; 
if(event->key()==Qt::Key_J){ 
    glb[b3].fzd=1; glb[b3].hzb=i1; glb[b3].zzb=j1; if(tanke1[i1][j1]==1) glb[b3].wz=1; else if(tanke1[i1][j1]==2) glb[b3].wz=2; else if(tanke1[i1][j1]==3) glb[b3].wz=3; else if(tanke1[i1][j1]==4) glb[b3].wz=4; b3++; } 

计时器制作如下:

讯享网eventid1=startTimer(200); eventid2=startTimer(1000); 

eventid1,id2都是int型

计时器事件如下:


讯享网

void Widget::timerEvent(QTimerEvent *event){ 
    if(event->timerId()==eventid1){ 
    enemyappear(); for(int y=0;y<70;y++){ 
    if(glb[y].fzd==1){ 
    //glb[y].fzd=0; if(glb[y].wz==1&&glb[y].zzb>=0){ 
    glb[y].zzb=glb[y].zzb-1; defeatjianzhu(glb[y].hzb,glb[y].zzb,y); if(glb[y].zzb<0){ 
    glb[y].kongke=-1; glb[y].fzd=0; } repaint(); } else if(glb[y].wz==2&&glb[y].zzb<=15){ 
    glb[y].zzb=glb[y].zzb+1; defeatjianzhu(glb[y].hzb,glb[y].zzb,y); if(glb[y].zzb>15){ 
    glb[y].kongke=-1; glb[y].fzd=0; } repaint(); } else if(glb[y].wz==3&&glb[y].hzb>=0){ 
    glb[y].hzb=glb[y].hzb-1; defeatjianzhu(glb[y].hzb,glb[y].zzb,y); if(glb[y].hzb<0){ 
    glb[y].kongke=-1; glb[y].fzd=0; } repaint(); } else if(glb[y].wz==4&&glb[y].hzb<=16){ 
    glb[y].hzb=glb[y].hzb+1; defeatjianzhu(glb[y].hzb,glb[y].zzb,y); if(glb[y].hzb>16){ 
    glb[y].kongke=-1; glb[y].fzd=0; } repaint(); } } } 

子弹碰撞函数如下(heng,zong为该发子弹此时坐标,danshu为判断是哪一发子弹)最后的for是用来击毁敌方坦克的,先不用管:

讯享网void Widget::defeatjianzhu(int heng,int zong,int danshu){ 
    if(ditu2[heng][zong]==1){ 
    ditu2[heng][zong]=0; glb[danshu].kongke=-1; glb[danshu].fzd=0; } else if(ditu2[heng][zong]==2){ 
    glb[danshu].kongke=-1; glb[danshu].fzd=0; } for(int y=0;y<10;y++){ 
    if(etank[y].nowhzb==heng&&etank[y].nowzzb==zong&&etank[y].cunhuo&&etank[y].zwz!=0){ 
    if(etank[y].ming>0){ 
    etank[y].ming--; glb[danshu].kongke=-1; glb[danshu].fzd=0; } if(etank[y].ming<=0){ 
    etank[y].cunhuo=false; etank[y].siwang=1; a3--; } } } } 

己方子弹的绘图(只要弹匣中该子弹还未移动完毕,即kongke!=-1,就让它继续放):

for(int y=0;y<70;y++){ 
    if(glb[y].kongke!=-1){ 
    //defeatjianzhu(glb[y].hzb,glb[y].zzb,y); QRect r3(glb[y].hzb*60,glb[y].zzb*60,60,60); painter.drawPixmap(r3,glb[y].map); } } 

敌方坦克的实现

条件:敌方共有十个坦克,开局出现三个,每死一个再出现一个,十个都死后,游戏胜利。
由于敌方坦克的出生地点是随机的,等级,出生时炮口朝向都是随机的,所以,我们也可以建立一个敌方坦克结构体,这个结构体能够记录坦克出生时的位置以及之后在地图中移动的位置,出生时炮口朝向,该坦克等级,生命值,是否还存活,以及该坦克的弹匣。
敌方坦克结构体构建如下:

讯享网struct enemy{ 
    int starthzb;//随机出生横坐标 int startzzb;//随机出生纵坐标 int nowhzb;//当前位置横坐标 int nowzzb;//当前位置纵坐标 int zwz;//炮口朝向 int life;//等级 bool cunhuo;//是否存活 int ming;//生命值 int siwang;//用于记录坦克死亡时间,坦克死亡那一瞬间,其值为1,在之后的0.6秒内,它会最终变为4,目的是实现0.6秒爆炸特效 bullet1 ebullet[50];//弹匣 }; 
enemy etank[10];//构建十个坦克 

敌方坦克出现函数(其中,a3为全局变量,开始为0,用于记录当前地图中一共有多少敌方坦克还存活,一个地图中同时出现的坦克最大为3,zwz为0时,代表了该位置还未出现坦克,因为坦克炮口朝向只有1,2,3,4,对应上下左右,其为0时,代表无坦克,可以存放):

讯享网void Widget::enemyappear(){ 
    srand((unsigned)time(NULL)); for(int y=0;y<10;y++){ 
    if(a3!=3&&etank[y].zwz==0){ 
    int xheng=rand()%17+0; int xzong=rand()%2+0; int zwz=rand()%4+1; int life=rand()%3+1; etank[y].starthzb=xheng;//获得开始位置 etank[y].startzzb=xzong;//获得开始位置 etank[y].zwz=zwz;//获得开始炮口朝向 etank[y].life=life;//获得等级 if(life==1){ 
    etank[y].ming=1;//每个等级对应一种生命值 } else if(life==2){ 
    etank[y].ming=2; } else if(life==3){ 
    etank[y].ming=3; } a3++; } } } 

敌方坦克有了开始位置,有了炮口朝向后就可以开始绘图了,同样,也需要一个坦克模型函数,每种等级的坦克,有不同的图形,每种等级坦克也有四个方向图片
敌方坦克模型函数如下:

void Widget::enemymoxing(QPainter*p,int heng,int zong,int zwz,int life){ 
    QPixmap pix; if(life==1){ 
    switch(zwz){ 
    case 1:{ 
    pix=QPixmap(":/tuxiang/enemy1U.png"); break; } case 2:{ 
    pix=QPixmap(":/tuxiang/enemy1D.png"); break; } case 3:{ 
    pix=QPixmap(":/tuxiang/enemy1L.png"); break; } case 4:{ 
    pix=QPixmap(":/tuxiang/enemy1R.png"); break; } default: break; } } else if(life==2){ 
    switch(zwz){ 
    case 1:{ 
    pix=QPixmap(":/tuxiang/enemy2U.png"); break; } case 2:{ 
    pix=QPixmap(":/tuxiang/enemy2D.png"); break; } case 3:{ 
    pix=QPixmap(":/tuxiang/enemy2L.png"); break; } case 4:{ 
    pix=QPixmap(":/tuxiang/enemy2R.png"); break; } } } else if(life==3){ 
    switch(zwz){ 
    case 1:{ 
    pix=QPixmap(":/tuxiang/enemy3U.png"); break; } case 2:{ 
    pix=QPixmap(":/tuxiang/enemy3D.png"); break; } case 3:{ 
    pix=QPixmap(":/tuxiang/enemy3L.png"); break; } case 4:{ 
    pix=QPixmap(":/tuxiang/enemy3R.png"); break; } } } QRect r(heng*60,zong*60,60,60); p->drawPixmap(r,pix ); } 

接下来就需要让敌方坦克动起来,一是让坦克的位置能在计时器事件里被实时更改,二是制定敌方坦克移动的规则,即它每一步前进或者转向的概率

以下是敌方坦克移动函数,第一个为移动判断(向前还是转向,向前的概率为0.7,炮口的位置决定了坦克的前方是哪方,转向概率为0.3,),第二个为转向函数(该转向函数是坦克已经决定向前,但是前方无法通行时进行转向,直接转向无障碍物的一方)

讯享网void Widget::yidongpanduan(int y){ 
   //输入的y代表是第几辆坦克 int xheng=rand()%10+1; int xzong=rand()%4+1; if(xheng<=7){ 
    if(etank[y].zwz==1){ 
   //根据其炮口朝向确定其直行前进方向 if(ditu2[etank[y].nowhzb][etank[y].nowzzb-1]==1||ditu2[etank[y].nowhzb][etank[y].nowzzb-1]==2||ditu2[etank[y].nowhzb][etank[y].nowzzb-1]==4){ 
    zhuanxiang(xzong,y);//前路不通,转向 } else{ 
    if(etank[y].nowzzb>0) etank[y].nowzzb--;//前路通,前进 } } else if(etank[y].zwz==2){ 
    if(ditu2[etank[y].nowhzb][etank[y].nowzzb+1]==1||ditu2[etank[y].nowhzb][etank[y].nowzzb+1]==2||ditu2[etank[y].nowhzb][etank[y].nowzzb+1]==4){ 
    zhuanxiang(xzong,y); } else{ 
    if(etank[y].nowzzb<=15) etank[y].nowzzb++; } } else if(etank[y].zwz==3){ 
    if(ditu2[etank[y].nowhzb-1][etank[y].nowzzb]==1||ditu2[etank[y].nowhzb-1][etank[y].nowzzb]==2||ditu2[etank[y].nowhzb-1][etank[y].nowzzb]==4){ 
    zhuanxiang(xzong,y); } else{ 
    if(etank[y].nowhzb>0) etank[y].nowhzb--; } } else if(etank[y].zwz==4){ 
    if(ditu2[etank[y].nowhzb+1][etank[y].nowzzb]==1||ditu2[etank[y].nowhzb+1][etank[y].nowzzb]==2||ditu2[etank[y].nowhzb+1][etank[y].nowzzb]==4){ 
    zhuanxiang(xzong,y); } else{ 
    if(etank[y].nowhzb<=16) etank[y].nowhzb++; } } } else if(xheng>7){ 
   //转向 if(ditu2[etank[y].nowhzb][etank[y].nowzzb-1]!=1&&ditu2[etank[y].nowhzb][etank[y].nowzzb-1]!=2&&(etank[y].nowzzb-1)>=0&&ditu2[etank[y].nowhzb][etank[y].nowzzb-1]!=4){ 
    etank[y].zwz=1; } else if(ditu2[etank[y].nowhzb][etank[y].nowzzb+1]!=1&&ditu2[etank[y].nowhzb][etank[y].nowzzb+1]!=2&&(etank[y].nowzzb+1)<16&&ditu2[etank[y].nowhzb][etank[y].nowzzb+1]!=4){ 
    etank[y].zwz=2; } else if(ditu2[etank[y].nowhzb-1][etank[y].nowzzb]!=1&&ditu2[etank[y].nowhzb-1][etank[y].nowzzb]!=2&&(etank[y].nowhzb-1)>=0&&ditu2[etank[y].nowhzb-1][etank[y].nowzzb]!=4){ 
    etank[y].zwz=3; } else if(ditu2[etank[y].nowhzb+1][etank[y].nowzzb]!=1&&ditu2[etank[y].nowhzb+1][etank[y].nowzzb]!=2&&(etank[y].nowhzb+1)<17&&ditu2[etank[y].nowhzb+1][etank[y].nowzzb]!=4){ 
    etank[y].zwz=4; } } } void Widget::zhuanxiang(int x,int y){ 
    if(x==1){ 
    etank[y].zwz=1; } else if(x==2){ 
    etank[y].zwz=2; } else if(x==3){ 
    etank[y].zwz=3; } else if(x==4){ 
    etank[y].zwz=4; } } 
eventid2=startTimer(1000); 
讯享网else if(event->timerId()==eventid2){ 
    if(f==1){ 
    zhuangdan();//敌方子弹装弹函数,之后解释 } srand((unsigned)time(NULL)); if(f==1){ 
    for(int y=0;y<10;y++){ 
    if(etank[y].cunhuo&&etank[y].zwz!=0)//判断当前位置是否有坦克在地图上 yidongpanduan(y); } } } 

一切完毕后,就在绘图函数里,将坦克绘制出来,我下述这一部分代码实际上包含了三部分,第一个for循环是用来给刚出生的敌方坦克赋予位置和生命,因为敌方坦克需要一个初始位置,之后的位置变化都是在这基础上加减,故nowhzb,nowzzb的用处就是记录当前坐标,cunhuo表示该坦克活了,之后就可以绘制他了
第二个for是用来绘制爆炸特效的,上述已经提过,siwang最初为0,只有当该坦克死后,其变为1,之后才通过计时器在0.6秒内一直绘制爆炸图像(可以是多张)以实现爆炸特效。
最后的enemymoxing才是绘制当前坦克图像的

for(int y=0;y<10;y++){ 
    if(etank[y].nowhzb==-2&&etank[y].zwz!=0&&!etank[y].cunhuo){ 
    enemymoxing(&painter,etank[y].starthzb,etank[y].startzzb,etank[y].zwz,etank[y].life); etank[y].nowhzb=etank[y].starthzb; etank[y].nowzzb=etank[y].startzzb; etank[y].cunhuo=true; //qDebug()<<etank[y].starthzb; } } for(int y=0;y<10;y++){ 
    if(etank[y].siwang>0&&etank[y].siwang<=3){ 
    if(etank[y].siwang==1){ 
    QRect Q(0,0,28,28); QRect Q2(etank[y].nowhzb*60,etank[y].nowzzb*60,60,60); QPixmap MAP2(":/tuxiang/Explode1.bmp"); painter.drawPixmap(Q2,MAP2,Q); } else{ 
    QRect Q(0,0,64,64); QRect Q2(etank[y].nowhzb*60,etank[y].nowzzb*60,60,60); QPixmap MAP2(":/tuxiang/Explode2.bmp"); painter.drawPixmap(Q2,MAP2,Q); } } if(etank[y].cunhuo){ 
    enemymoxing(&painter,etank[y].nowhzb,etank[y].nowzzb,etank[y].zwz,etank[y].life); } 

敌方子弹的实现

讯享网void Widget::zhuangdan(){ 
    srand((unsigned)time(NULL)); for(int y=0;y<10;y++){ 
    int xheng=rand()%11;//装弹概率为0-4,只有这几个数能装弹 int bb=0; if(etank[y].zwz!=0){ 
   //该位置有坦克(无论死活) while(true){ 
    if(etank[y].ming>0&&xheng<5&&etank[y].ebullet[bb].kongke!=-1&&etank[y].ebullet[bb].fzd!=1&&etank[y].cunhuo){ 
   //细化条件,坦克要存活,该坦克的该位置弹匣为空 etank[y].ebullet[bb].fzd=1; etank[y].ebullet[bb].hzb=etank[y].nowhzb; etank[y].ebullet[bb].zzb=etank[y].nowzzb; etank[y].ebullet[bb].wz=etank[y].zwz; break; }//循环,直到找到空位置装上子弹。 bb++; if(bb>49){ 
    break; } } } } } 

敌方子弹碰撞函数,与己方子弹极度类似

void Widget::enemydefeat(int heng,int zong,int tankshu,int danshu){ 
    if(ditu2[heng][zong]==1){ 
    ditu2[heng][zong]=0; etank[tankshu].ebullet[danshu].kongke=-1; etank[tankshu].ebullet[danshu].fzd=0; } else if(ditu2[heng][zong]==2){ 
    etank[tankshu].ebullet[danshu].kongke=-1; etank[tankshu].ebullet[danshu].fzd=0; } if(etank[tankshu].ebullet[danshu].hzb==i1&&etank[tankshu].ebullet[danshu].zzb==j1){ 
    sh1=i1; sz1=j1; i1=5; j1=15; sishu++; siqu=1; } } 

同样的,敌方子弹也放入0.2秒的计时器中,让其不断改变位置,再在绘图事件中进行绘制,该步骤与己方子弹相同,不再重复。

敌方与己方坦克的死去与复活以及特效

胜利与失败条件

结语

这个坦克大战实现完毕之后,我觉得核心就是两个结构体,一个子弹结构体,一个敌方坦克结构体,只要能把这两个结构体理解以及完善,坦克游戏的实现就可以成功(我的想法中有很多不足之处,也希望大家指出,共同学习,共同进步)

小讯
上一篇 2025-03-14 10:01
下一篇 2025-01-28 16:53

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/25669.html