【Dev C++坦克大战】

我来也!!

各位不充VIP的小盆友,福利来啦!!

免费的坦克大战!!

废话不多说,献上代码!

(懒得可以直接复制哈)

 
  1. 我来也!!
    
    各位不充VIP的小盆友,福利来啦!!
    
    免费的坦克大战!!
    
    废话不多说,献上代码!
    
    (懒得可以直接复制哈)
    
    #include <stdio.h>
     
    #include <windows.h>
     
    #include <time.h> 
     
                               //里规格:长39*2=78 (真坐标)(假坐标宽为39)  高39
     
                               //外规格:长41*2=82 (真坐标)(假坐标宽为41)  高41
     
    #define UP    1
     
    #define DOWN  2
     
    #define LEFT  3
     
    #define RIGHT 4
     
    #define MAX_LEVEL 8
     
    #define BULLET_NUM 20
     
    #define MAX_LIFE 4
     
     
     
    //程序中未写入函数参数表中且未说明的变量只有map二维数组,level_info数组和level   
     
     
     
    /*
          此程序中涉及的x,y类的坐标值,分为以下两种:                                 
                                                                                                      
    假坐标:这里的坐标指的是以一个■长度为单位的坐标,而不是真正的coord坐标 (用于map数组的坐标)                             
                                                                                                      
    真坐标:头文件自带的坐标结构coord中的坐标(也可以说是控制台里的真正坐标值)                                 
                                                                                                      
      区别:纵坐标y两值一致,假横坐标x值与真正coord横坐标(真坐标)关系是 x * 2 = coord 横坐标    
                                                                                                                
              coord横坐标既指GoTo函数中的x参数,因为本程序游戏界面以一个■长度为基本单位,                    
                                                                                                      
              可以说涉及的coord横坐标全是偶数。既假坐标要变真坐标(变真坐标才能发挥真正作用),横坐标须乘以2                                    
                                                               
    */
     
    typedef struct             //这里的出现次序指的是一个AI_tank变量中的次序,游戏共有四个AI_tank变量
     
    {                          //∵设定每个AI_tank每种特殊坦克只出现一次 ∴fast_tank & firm_tank 最多出现次数不超过1
     
        int fast_tank_order;   //fast_tank出现的次序(在第fast_tank_order次复活出现,从第0次开始),且每个AI_tank只出现一次
     
        int firm_tank_order;   //firm_tank出现的次序,同上
     
    } LevInfo;                 //关卡信息(准确说是该关出现的坦克信息)
     
    LevInfo level_info [MAX_LEVEL] = {
        {-1,-1},{3,-1},{-1,3},{2,3},{2,3},{2,3},{2,3},{2,3}};   //初始化,-1代表没有该类型坦克
     
     
     
     
     
    typedef struct      //子弹结构体
     
    {
     
        int x,y;        //子弹坐标,假坐标
     
        int direction;  //子弹方向变量
     
        bool exist;     //子弹存在与否的变量,1为存在,0不存在
     
        bool initial;   //子弹是否处于建立初状态的值,1为处于建立初状态,0为处于非建立初状态
     
        bool my;        //区分AI子弹与玩家子弹的标记,0为AI子弹,1为玩家(我的)子弹
     
    } Bullet;
     
    Bullet bullet [BULLET_NUM];  //考虑到地图上不太可能同时存在20颗子弹,所以数组元素设置20个
     
     
     
     
     
    typedef struct      //坦克结构体
     
    {
     
        int x,y;        //坦克中心坐标
     
        int direction;  //坦克方向
     
        int color;      //颜色参方向数,1到6分别代表不同颜色,具体在PrintTank函数定义有说明
     
        int model;      //坦克图案模型,值为1,2,3,分别代表不同的坦克图案,0为我的坦克图案,AI不能使用
     
        int stop;       //只能是AI坦克使用的参数,非0代表坦克停止走动,0为可以走动
     
        int revive;     //坦克复活次数
     
        int num;        //AI坦克编号(固定值,为常量,初始化函数中定下)0~3
     
        int CD;         //发射子弹冷却计时
     
        bool my;        //是否敌方坦克参数,我的坦克此参数为1,为常量
     
        bool alive;     //存活为1,不存活为0
     
    }  Tank;
     
    Tank AI_tank[4] , my_tank;  //my_tank为我的坦克,Ai_tank 代表AI坦克
     
     
     
    //∵所有的函数都有可能对全局变量map进行读写(改变),
     
    //∴函数中不另说明是否会对全局变量map读写
     
    //基本操作与游戏辅助函数
     
    void GoToxy(int x,int y);    //光标移动
     
    void HideCursor();           //隐藏光标
     
    void keyboard ();            //接受键盘输入
     
    void Initialize();           //初始化(含有对多个数据的读写)
     
    void Stop();                 //暂停
     
    void Getmap();               //地图数据存放与获取
     
    void Frame ();               //打印游戏主体框架
     
    void PrintMap();             //打印地图(地图既地图障碍物)(含对level的读取)
     
    void SideScreen ();          //副屏幕打印
     
    void GameCheak();            //检测游戏输赢
     
    void GameOver( bool home );  //游戏结束
     
    void ClearMainScreen();      //主屏幕清屏函数∵system("cls")后打印框架有一定几率造成框架上移一行的错误∴单独编写清屏函数
     
    void ColorChoose(int color); //颜色选择函数
     
    void NextLevel();            //下一关(含有对level全局变量的读写)
     
     
     
    //子弹部分
     
    void BuildAIBullet(Tank *tank);                //AI坦克发射子弹(含有对my_tank的读取,只读取了my_tank坐标)
     
    void BuildBullet  (Tank tank);                 //子弹发射(建立)(人机共用)(含全局变量bullet的修改)我的坦克发射子弹直接调用该函数,AI通过AIshoot间接调用
     
    void BulletFly    (Bullet bullet[BULLET_NUM]); //子弹移动和打击(人机共用),
     
    void BulletHit    (Bullet* bullet);            //子弹碰撞(人机共用)(含Tank全局变量的修改),只通过BulletFly调用,子弹间的碰撞不在本函数,子弹间碰撞已在BulletShoot中检测并处理
     
    void PrintBullet  (int x,int y,int T);         //打印子弹(人机共用)
     
    void ClearBullet  (int x,int y,int T);         //清除子弹(人机共用)
     
    int  BulletCheak  (int x,int y);               //判断子弹前方情况(人机共用)
     
     
     
    //坦克部分
     
    void BuildAITank (int* position, Tank* AI_tank); //建立AI坦克
     
    void BuildMyTank (Tank* my_tank);                //建立我的坦克
     
    void MoveAITank  (Tank* AI_tank);                //AI坦克移动
     
    void MoveMyTank  (int turn);                     //我的坦克移动,只通过keyboard函数调用,既键盘控制
     
    void ClearTank   (int x,int y);                  //清除坦克(人机共用)
     
    void PrintTank   (Tank tank);                    //打印坦克(人机共用)
     
    bool TankCheak   (Tank tank,int direction);      //检测坦克dirtection方向的障碍物,返值1阻碍,0 畅通
     
    int  AIPositionCheak (int position);           //检测AI坦克建立位置是否有障碍物AIPositionCheak
     
     
     
    //DWORD WINAPI InputX(LPVOID lpParameter); //声明线程函数,用于检查X键输入并设置X键的输入冷却时间
     
     
     
     
     
    //注意map数组应是纵坐标在前,横坐标在后,既map[y][x],(∵数组行长度在前,列长度在后)
     
    //map里的值: 个位数的值为地图方块部分,百位数的值为坦克,子弹在map上没有值(子弹仅仅是一个假坐标)
     
    //map里的值: 0为可通过陆地,1为红砖,2黄砖,5为水,100~103为敌方坦克,200为我的坦克,
     
     
     
    //全局变量
     
    int map[41][41];  //地图二维数组
     
    int key_x;        // X键是否被“读入”的变量,也是子弹是否可以发射的变,
     
    int bul_num;      //子弹编号
     
    int position;     //位置计数,对应AI坦克生成位置,-1为左位置,0为中间,1为右,2为我的坦克位置
     
    int speed=7;      //游戏速度,调整用
     
    int level=1;      //游戏关卡数
     
    int score=0;      //游戏分数
     
    int remain_enemy; //剩余敌人(未出现的敌人)
     
     
     
    char* tank_figure[4][3][4]=
     
    {
     
      {
     
        {"◢┃◣", "◢━◣", "◢┳◣", "◢┳◣"},
     
        {"┣●┫", "┣●┫", "━●┃", "┃●━"},
     
        {"◥━◤", "◥┃◤", "◥┻◤", "◥┻◤"}
     
      }, 
     
      {
     
        {"┏┃┓", "┏┳┓", "┏┳┓", "┏┳┓"},
     
        {"┣●┫", "┣●┫", "━●┫", "┣●━"},
     
        {"┗┻┛", "┗┃┛", "┗┻┛", "┗┻┛"}
     
      }, 
     
      {
     
        {"┏┃┓", "◢━◣", "┏┳◣", "◢┳┓"},
     
        {"┣●┫", "┣●┫", "━●┃", "┃●━"},
     
        {"◥━◤", "┗┃┛", "┗┻◤", "◥┻┛"}
     
      },
     
      {
     
        {"╔┃╗", "╔╦╗", "╔╦╗", "╔╦╗"},
     
        {"╠█╣", "╠█╣", "━█╣", "╠█━"},
     
        {"╚╩╝", "╚┃╝", "╚╩╝", "╚╩╝"}
     
      }
     
    };
     
     
     
     
     
     
     
    int main ()                               //主函数
     
    {
     
        int i;
     
        unsigned int interval[12]={1,1,1,1,1,1,1,1,1,1,1,1} ;  //间隔计数器数组,用于控制速度
     
        srand(time(NULL)); //设置随机数种子(若不设置种子而调用rand会使每次运行的随机数序列一致)随机数序列指:如首次调用rand得到1,第二次得2,第三次3,则此次随机数序列为1,2,3
     
        HideCursor();                         //隐藏光标
     
        system("mode con cols=112 lines=42"); //控制窗口大小
     
        Frame ();                             //打印游戏主体框架
     
        Initialize();                         //初始化,全局变量level初值便是1 
     
    //    HANDLE h1 , h2 ;                      //定义句柄变量
     
        for(;;)
     
        {
     
            if(interval[0]++%speed==0)        //速度调整用,假设interval[0]为a, 语句意为 a % 2==0,a=a+1; 
     
            {
     
                GameCheak();                  //游戏胜负检测
     
                BulletFly ( bullet );
     
                for(i=0 ; i<=3 ; i++)         //AI坦克移动循环
     
                {
     
                    if(AI_tank[i].model==2 && interval[i+1]++%2==0) //四个坦克中的快速坦克单独使用计数器1,2,3,4
     
                        MoveAITank( & AI_tank[i]);
     
                    if(AI_tank[i].model!=2 && interval[i+5]++%3==0) //四个坦克中的慢速坦克单独使用计数器5,6,7,8
     
                        MoveAITank( & AI_tank[i]);
     
                }
     
                for(i=0;i<=3;i++)                                   //建立AI坦克部分
     
                         if(AI_tank[i].alive==0 && AI_tank[i].revive<4 && interval[9]++%90==0)  //一个敌方坦克每局只有4条命
     
                    {                                               //如果坦克不存活。计时,每次建立有间隔  1750 ms
     
                           BuildAITank( &position, & AI_tank[i] );     //建立AI坦克(复活)
     
                          break;                                      //每次循环只建立一个坦克
     
                      }
     
                for(i=0;i<=3;i++)
     
                    if(AI_tank[i].alive)
     
                        BuildAIBullet(&AI_tank[i]);                 //AIshoot自带int自增计数CD,不使用main中的CD interval
     
                if(my_tank.alive && interval[10]++%2==0 )
     
                     keyboard ();
     
                if(my_tank.alive==0 && interval[11]++%30==0 && my_tank.revive < MAX_LIFE)
     
                     BuildMyTank( &my_tank );
     
            }
     
            Sleep(5);
     
        }
     
        return 0;
     
    }
     
     
     
     
     
    /*//这里的多线程暂时不用                   //x键用于子弹发射,x键的冷却时间不能和上下左右一同设置,那样就太快了
    DWORD WINAPI InputX(LPVOID lpParameter)    //如果不用多线程运行,那么在x键冷却时间内程序会因Sleep将会挂起,暂停运行
    {                                          //因为只有一个变量改变,而且变量改变先后顺序是显而易见的,所以不必设置缓冲区
        for(;;)                              
        {                                    
            if(GetAsyncKeyState( 88 )& 0x8000) //88为x键键值,当摁下x并且x键处于可输入状态
            {
                key_x=1;                       // X键是否允许被“读入”的变量,也是子弹是否可以发射的变量
                Sleep(600);                    // 子线程Sleep中,x就不能被"读入",主线程每操作完一次子弹发射,key_x会归零
            }
            Sleep(10);
        }
        return 0;
    }*/
     
     
     
     
     
    void keyboard ()
     
    {               // kbhit()   getch()  用法可用但是不好用            
     
    /* 
       函数功能:该函数判断在此函数被调用时,某个键是处于UP状态还是处于DOWN状态,及前次调用GetAsyncKeyState函数后,
       是否按过此键.如果返回值的最高位被置位,那么该键处于DOWN状态;如果最低位被置位,那么在前一次调用此函数后,此键被按过,
       否则表示该键没被按过.
       这里GetAsyncKeyState比 kbhit() + getch() 好用,操作更顺畅.   GetAsyncKeyState的返回值表示两个内容,
       一个是最高位bit的值,代表这个键是否被按下。一个是最低位bit的值,代表上次调用GetAsyncKeyState后,这个键是否被按下。
       &为与操作,&0x8000就是判断这个返回值的高位字节。如果high-order bit是1,则是按下状态,否则是弹起状态,为0
    */
     
        int count=0;
     
        if (GetAsyncKeyState(VK_UP)& 0x8000)  
     
            MoveMyTank( UP );
     
        else if (GetAsyncKeyState(VK_DOWN)& 0x8000)  
     
            MoveMyTank( DOWN );
     
        else if (GetAsyncKeyState(VK_LEFT)& 0x8000)
     
            MoveMyTank( LEFT );
     
        else if (GetAsyncKeyState(VK_RIGHT)& 0x8000)  
     
            MoveMyTank( RIGHT );
     
        else if (GetAsyncKeyState( 0x1B )& 0x8000)  // Esc键
     
            exit(0);                                //退出程序函数
     
        else if (GetAsyncKeyState( 0x20 )& 0x8000)  //空格
     
            Stop();
     
        else if (count++%7==0)            //这里添加计数器是为了防止按键粘连不能达到微调效果
     
        {
     
            if (speed>1 && GetAsyncKeyState( 0x6B )& 0x8000)   // +键
     
            {
     
                speed--;
     
                GoToxy(102,11);           //在副屏幕打印出当前速度
     
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE|FOREGROUND_RED);
     
                printf("%d ",21-speed);   //副屏幕显示的速度为1~10
     
            }
     
            else if (speed<20 && GetAsyncKeyState( 0x6D )& 0x8000)  // - 键
     
            {
     
                speed++;
     
                GoToxy(102,11);           //在副屏幕打印出当前速度
     
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE|FOREGROUND_RED);
     
                printf("%d ",21-speed);   //副屏幕显示的速度为1~10
     
            }
     
        }
     
        if(my_tank.CD==7)
     
        {
     
            if(GetAsyncKeyState( 88 )& 0x8000)
     
            {
     
                BuildBullet(my_tank);
     
                my_tank.CD=0;
     
            }
     
        }
     
        else
     
            my_tank.CD++;
     
    }
     
     
     
     
     
     
     
    void BuildAIBullet(Tank *tank)   //AI子弹发射(建立)含有对my_tank的读取
     
    {
     
        if(tank->CD==15)
     
        {
     
            if(!(rand()%11))     //冷却结束后在随后的每个游戏周期中有10分之一的可能发射子弹
     
            {
     
                BuildBullet(*tank);
     
                tank->CD=0;
     
            }
     
        }
     
        else
     
            tank->CD++;
     
        if(tank->CD >= 14)       //AI强化部分,在冷却到达一定范围即可使用
     
        {
     
            if(tank->y==38 )     //如果坦克在底部(这个最优先)
     
            {
     
                if(tank->x < 20) //在老家左边
     
                {
     
                    if(tank->direction==RIGHT)  //坦克方向朝左
     
                    {
     
                        BuildBullet(*tank);     //发射子弹
     
                        tank->CD=0;
     
                    }
     
                }
     
                else             //在老家右边
     
                    if(tank->direction==LEFT)   //坦克方向朝右
     
                    {
     
                        BuildBullet(*tank);     //发射子弹
     
                        tank->CD=0;
     
                    }
     
            }
     
            else if(tank->x==my_tank.x+1 || tank->x==my_tank.x || tank->x==my_tank.x-1)  //AI坦克在纵向上"炮口"对准我的坦克
     
            {
     
                if(tank->direction==DOWN && my_tank.y > tank->y || tank->direction==UP && my_tank.y < tank->y)
     
                {                               //若是AI朝下并且我的坦克在AI坦克下方(数值大的在下面)或者AI朝上我的坦克在AI上方
     
                    int big=my_tank.y , smal=tank->y , i; 
     
                    if(my_tank.y < tank->y)
     
                    {
     
                        big=tank->y;
     
                        smal=my_tank.y;
     
                    }
     
                    for(i=smal+2;i<=big-2;i++)  //判断AI炮口的直线上两坦克间有无障碍
     
                        if(map[i][tank->x]!=0 || map[i][tank->x]!=5)      //若有障碍
     
                            break;
     
                    if(i==big-1)                //若i走到big-1说明无障碍
     
                    {
     
                        BuildBullet(*tank);     //则发射子弹
     
                        tank->CD=0;
     
                    }
     
                }
     
            }
     
            else if(tank->y==my_tank.y+1 || tank->y==my_tank.y || tank->y==my_tank.y-1) //AI坦克在横向上"炮口"对准我的坦克
     
            {
     
                if(tank->direction==RIGHT && my_tank.x > tank->x || tank->direction==LEFT && my_tank.x < tank->x)
     
                {                  //若是AI朝右并且我的坦克在AI坦克右方(数值大的在下面)或者AI朝左我的坦克在AI左方
     
                    int big=my_tank.y , smal=tank->y , i;
     
                    if(my_tank.x < tank->x)
     
                    {
     
                        big=tank->x;
     
                        smal=my_tank.x;
     
                    }
     
                    for(i=smal+2;i<=big-2;i++)  //判断AI炮口的直线上两坦克间有无障碍
     
                        if(map[tank->y][i]!=0 || map[tank->y][i]!=5)      //若有障碍
     
                            break;
     
                    if(i==big-1)   //若i走到big-1说明无障碍
     
                    {
     
                        BuildBullet(*tank);     //则发射子弹
     
                        tank->CD=0;
     
                    }
     
                }
     
            }
     
        }
     
    }
     
     
     
     
     
     
     
    void BuildBullet(Tank tank)  //子弹发射(建立),传入结构体Tank,这里包含改变了全局变量结构体bullet
     
    {                            //∵实现方式为顺序循环建立子弹,每次调用改变的bullet数组元素都不同
     
        switch(tank.direction)   //∴为了方便,不将bullet放入参数,bullet作为全局变量使用
     
        {
     
            case UP    :
     
                    bullet [bul_num].x = tank.x;
     
                    bullet [bul_num].y = tank.y-2;
     
                    bullet [bul_num].direction=1;
     
                    break;
     
            case DOWN  :
     
                    bullet [bul_num].x = tank.x;
     
                    bullet [bul_num].y = tank.y+2;
     
                    bullet [bul_num].direction=2;
     
                    break;
     
            case LEFT  :
     
                    bullet [bul_num].x = tank.x-2;
     
                    bullet [bul_num].y = tank.y;
     
                    bullet [bul_num].direction=3;
     
           
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值