stephen


私信TA

用户名:wujinpeng666

访问量:1107

签 名:

我是黑客,我的访问量永远都是双数

等  级
排  名 1660
经  验 2619
参赛次数 3
文章发表 6
年  龄 19
在职情况 学生
学  校 中山大学
专  业 计算机专业

  自我简介:

都给我低调点,渺小的人类们


#include<bits/stdc++.h>



    #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;


                break;


        case RIGHT :


                bullet [bul_num].x = tank.x+2;


                bullet [bul_num].y = tank.y;


                bullet [bul_num].direction=4;


                break;


    }


    bullet [bul_num].exist = 1;    //子弹被建立,此值为1则此子弹存在


    bullet [bul_num].initial = 1;  //子弹处于初建立状态


    bullet [bul_num].my=tank.my;   //如果是我的坦克发射的子弹bullet.my=1,否则为0


    bul_num++;


    if(bul_num==BULLET_NUM)        //如果子弹编号增长到20号,那么重头开始编号


        bul_num=0;                 //考虑到地图上不可能同时存在20颗子弹,所以数组元素设置20个


}






void BulletFly(Bullet bullet[BULLET_NUM]) //子弹移动和打击


{                                         //含有全局变量Bullet的改变


    for(int i =0; i<BULLET_NUM;i++)


    {


        if(bullet [i].exist)              //如果子弹存在


        {


            if(bullet [i].initial==0)     //如果子弹不是初建立的


            {


                if(map[bullet[i].y] [bullet[i].x]==0 || map[bullet[i].y] [bullet[i].x]==5)   //如果子弹坐标当前位置无障碍


                    ClearBullet( bullet[i].x , bullet[i].y , BulletCheak(bullet[i].x , bullet[i].y ));     //抹除子弹图形


                switch(bullet [i].direction)                                      //然后子弹坐标变化(子弹变到下一个坐标)


                {


                    case UP    :(bullet [i].y)--;break;


                    case DOWN  :(bullet [i].y)++;break;


                    case LEFT  :(bullet [i].x)--;break;


                    case RIGHT :(bullet [i].x)++;break;


                }


            }


            int collide = BulletCheak ( bullet [i].x , bullet [i].y );   //判断子弹当前位置情况,判断子弹是否碰撞,是否位于水面上。


            if( collide )                                                //如果检测到当前子弹坐标无障碍(无碰撞)(包括在地面上与在水面上)


                PrintBullet( bullet[i].x , bullet[i].y , collide);       //则打印子弹,若有碰撞则不打印


            else


                BulletHit( & bullet [i] );     //若有碰撞则执行子弹碰撞函数


            if(bullet [i].initial)             //若子弹初建立,则把初建立标记去除


                bullet [i].initial = 0;


            for(int j=0; j< BULLET_NUM ; j++)  //子弹间的碰撞判断,若是我方子弹和敌方子弹碰撞则都删除,若为两敌方子弹则无视


                if(bullet [j].exist && j!=i && (bullet[i].my || bullet[j].my) && bullet[i].x==bullet[j].x && bullet[i].y==bullet[j].y)


                {                              //同样的两颗我方子弹不可能产生碰撞


                    bullet [j].exist=0;


                    bullet [i].exist=0;


                    ClearBullet( bullet[j].x , bullet[j].y , BulletCheak(bullet[j].x , bullet[j].y ));  //抹除j子弹图形,子弹i图形已被抹除


                    break;


                }


        }


    }


}






void BulletHit(Bullet* bullet)  //含有Tank全局变量的修改,子弹间的碰撞不在本函数,子弹间碰撞已在BulletShoot中检测并处理


{                               //∵每次打中的坦克都不一样,不可能把所有坦克放在参数表中


    int x=bullet->x;            //∴这里的Tank使用全局变量


    int y=bullet->y;            //这里传入的值是子弹坐标,这两个值不需要改变


    int i;


    if(map[y][x]==1 || map[y][x]==2)  //子弹碰到砖块


    {


        if(bullet->direction==UP || bullet->direction==DOWN)   //如果子弹是纵向的


            for(i = -1 ; i<=1 ; i++)


                if(map[y][x+i]==1 || map[y][x+i]==2)  //如果子弹打中砖块两旁为砖块,则删除砖,若不是(一旁为坦克或其他地形)则忽略


                {


                    map[y][x+i]=0;    //砖块碎


                     GoToxy(2*x+2*i,y);


                    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED); //背景黑色


                     printf("  ");


                }


        if(bullet->direction==LEFT || bullet->direction==RIGHT)     //若子弹是横向的  (与子弹纵向实现同理)


            for(i = -1 ; i<=1 ; i++)


                if(map[y+i][x]==1 || map[y+i][x]==2)


                {


                    map[y+i][x]=0;


                     GoToxy(2*x,y+i);


                    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED); //背景黑色


                     printf("  ");


                }


        bullet->exist=0;           //这颗子弹已经不存在了


    }


    else if(map[y][x]==4 || map[y][x]==6 )  //子弹碰到边框或者不可摧毁方块


        bullet->exist=0;


    else if(bullet->my && map[y][x]>=100 && map[y][x]<104 )  //若我的子弹碰到了敌方坦克


    {


        int num = map[y][x]%100;   //map[y][x]%100 等同于 tank.num ,可通过map值读取该坦克信息


        if(AI_tank[num].model==3 && AI_tank[num].color==2)   //若为firm tank,且color==2。该坦克为绿色,表明没有受到伤害


                AI_tank[num].color=3;                        //则变成黄色,color=3为黄色


        else if (AI_tank[num].model==3 && AI_tank[num].color==3)


                AI_tank[num].color=4;                        //4为红色


        else                       //其他类型的坦克或者firm tank为红色的情况


        {


            AI_tank[num].alive=0;


            ClearTank(AI_tank[num].x , AI_tank[num].y);      //清除该坦克


        }


        bullet->exist=0;


        score+=100;


        GoToxy(102,5);             //在副屏幕上打印出分数


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);


        printf("%d ",score);


    }


    else if(map[y][x]==200 && bullet->my==0 )   //若敌方子弹击中我的坦克


    {


        my_tank.alive=0;


        ClearTank(my_tank.x , my_tank.y);


        bullet->exist=0;


        my_tank.revive++;      //我的坦克复活次数+1(∵我的坦克复活次数与生命值有关∴放在这里自减)


        score-=100;            //分数减少


        GoToxy(102,5);         //在副屏幕上打印出分数


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);


        printf("%d   ",score);


        GoToxy(102,7);         //在副屏幕打印出我的剩余生命值


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);


        printf("%d   ", MAX_LIFE-my_tank.revive);


    }


//    else if(bullet->my==0 && map[y][x]>=100 && map[y][x]<104) //敌方子弹击中敌方坦克,可以设置两种子弹运行方式,这种暂时不用


//        bullet->exist=0;


    else if(map[y][x]==9)      //子弹碰到家(无论是谁的子弹)


    {


        bullet->exist=0;


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE|FOREGROUND_RED|FOREGROUND_GREEN);


        GoToxy(38,37);     printf("      ");


        GoToxy(38,38);     printf("◢◣  ");


        GoToxy(38,39);     printf("███");


        GameOver(1);           //游戏结束,传入1代表老家被毁


    }


}






int BulletCheak (int x,int y)  //判断子弹当前位置情况,判断子弹是否碰撞,是否位于水面上。


{                              //有障碍返回0,无障碍且子弹在地面返回1,子弹在水面上返回2


    if(map[y][x]==0)


        return 1;


    else if(map[y][x]==5)


        return 2;


    else


        return 0;


}






void PrintBullet (int x,int y,int T)   //当前坐标BulletCheak 的值做参量 T


{


    if(T==1)          //  T==1 表示子弹当前坐标在陆地上


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);


    else if(T==2)     //  T==2 表示子弹当前坐标在水面上


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY|BACKGROUND_BLUE);


    GoToxy(2*x,y);


    printf("");


}






void ClearBullet(int x,int y,int T)   //当前坐标BulletCheak 的值做参量 T


{


    GoToxy(2*x,y);


    if(T==2)        //  T==2 表示子弹当前坐标在水面上


    {


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|BACKGROUND_BLUE|FOREGROUND_BLUE|FOREGROUND_GREEN);


        printf("~");


    }


    else if(T==1)   //  T==1 表示子弹当前坐标在陆地上


    {


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE);


        printf("  ");


    }


}






//position为坦克生成位置,-1为左位置,0为中间,1为右,2为我的坦克位置


void BuildAITank(int* position, Tank* AI_tank)   //执行一次该函数只建立一个坦克


{                                         //rand函数公式:0<=rand()%(a+1)<=a  0+m<=rand()%(n-m+1)+m<=n


                                          //rand函数实现1到n:1<=rand()%(n)+1<=n


       if(AIPositionCheak(*position))        //若此位置无障碍,可生成。position参数详见AIPositionCheak函数定义


    {


        AI_tank->x= 20 + 18*(*position);  //20 + 18 * position 对应三个生成位置的x假坐标


        AI_tank->y=2;


        if(AI_tank->revive==level_info[level-1].firm_tank_order)  //坦克出现(复活)次序==关卡信息(level_info)中firm tank的出现次序


        {


            AI_tank->model = 3;           //3为firm tank的模型(外观)


            AI_tank->color = 2;           //颜色参数2为绿色,具体详见函数ColorChoose


        }


        else if(AI_tank->revive==level_info[level-1].fast_tank_order)  //同上if,这里是fast_tank的


        {


            AI_tank->model = 2;


            AI_tank->color = rand()%6+1;  //若不是firm tank则随机颜色,颜色参数为1~6,分别代表不同颜色,详见函数ColorChoose


        }


        else      //普通坦克


        {


            AI_tank->model = 1;


               AI_tank->color = rand()%6+1;  //若不是firm tank则随机颜色


        }


        AI_tank->alive = 1;       //坦克变为存在


        AI_tank->direction = 2 ;  //方向朝下


        AI_tank->revive++;        //复活次数+1


        PrintTank(*AI_tank);


        (*position)++;


        remain_enemy--;


        GoToxy(102,9);            //在副屏幕上打印剩余坦克数


        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);


        printf("%d ",remain_enemy);


        if(*position==2)          //position只能为0,1,-1,这里position循环重置


            *position = -1;


             return ;                  //若生成了一辆坦克,则结束该函数


    }


}






int AIPositionCheak( int position )    //position为坦克生成位置2为我的坦克位置,其余为AI位,-1为左位,0为中间位

{


    int    x,y;


    if(position==2)                    //2为我的坦克位置,现在暂时用不到


        x=15,y=38;


    else


        y=2 , x= 20 + 18 * position ;  //20 + 18 * position 对应三个生成位置的x假坐标


    for(int i=0;i<3;i++)


        for(int j=0;j<3;j++)


            if( map[y+j-1][x+i-1]!=0)  //如果遍历的九宫格里有障碍物


                return 0;              //则返回0,表示此生成位置有阻碍


    return 1;                          //否则生成1,表示此生成位置无阻碍


}






void MoveAITank(Tank* AI_tank) //AI专用函数,该函数主要为AI加强


{


       if(AI_tank->alive)         //如果坦克活着


    {


        if(AI_tank->stop!=0)   //坦克是否停止运动的判断,若stop参数不为0


        {


            AI_tank->stop--;   //则此坦克本回合停止运动


            return;


        }


        if( !(rand()%23) )     //22分之1的概率执行方向重置


        {


            AI_tank->direction = rand()%4+1;


            if( rand()%3 )     //在方向重置后有2分之1的概率停止走动3步的时间


            {


                AI_tank->stop=2;


                return;


            }


        }


        ClearTank (AI_tank->x , AI_tank->y);


        if(TankCheak ( *AI_tank , AI_tank->direction))   //如果前方无障碍


            switch ( AI_tank->direction )


            {


                   case UP   : AI_tank->y--; break;  //上前进一格


                case DOWN : AI_tank->y++; break;  //下前进一格


                 case LEFT : AI_tank->x--; break;  //左前进一格


                case RIGHT: AI_tank->x++; break;  //右前进一格


            }


        else                     //前方有障碍


        {


            if(!(rand()%4))      //3分之1的概率乱转


            {


                AI_tank->direction=rand()%4+1;


                AI_tank->stop=2; //乱转之后停止走动3步的时间


                PrintTank(*AI_tank);


                return;          //∵continue会跳过下面的打印函数,∴这里先打印


            }


            else                 //另外3分之2的几率选择正确的方向


            {


                int j;


                for(j=1;j<=4;j++)


                    if(TankCheak ( *AI_tank , j ))  //循环判断坦克四周有无障碍,此函数返值1为可通过


                        break;


                if(j==5)         //j==5说明此坦克四周都有障碍物,无法通行


                {


                    PrintTank(*AI_tank);


                    return;      //则跳过下面的while循环以防程序卡死


                }


                while(TankCheak ( *AI_tank , AI_tank->direction) == 0)  //如果前方仍有障碍


                    AI_tank->direction=(rand()%4+1);                    //则换个随机方向检测


            }


        }


        PrintTank(*AI_tank);     //打印AI坦克


    }


}






void BuildMyTank (Tank* my_tank) //建立我的坦克


{


    my_tank->x=15;


       my_tank->y=38;


       my_tank->stop=NULL;


       my_tank->direction=1;


    my_tank->model=0;


    my_tank->color=1;


    my_tank->alive=1;


    my_tank->my=1;


    my_tank->CD=7;


    PrintTank (*my_tank) ;   //打印我的坦克


}






void MoveMyTank(int turn )   //玩家专用函数,turn为keyboard函数里因输入不同方向键而传入的不同的值


{


    ClearTank(my_tank.x , my_tank.y);        //map 数组中“我的坦克”参数清除工作已在此函数中完成


    my_tank.direction=turn;                  //将键盘输入的方向值传入我的坦克方向值


    if(TankCheak ( my_tank , my_tank.direction ))  //若此时我的坦克当前方向上无障碍


        switch (turn)


        {


            case UP   : my_tank.y--; break;  //上前进一格


            case DOWN : my_tank.y++; break;  //下前进一格


            case LEFT : my_tank.x--; break;  //左前进一格


            case RIGHT: my_tank.x++; break;  //右前进一格


    }                                        //若坦克当前方向上有障碍则跳过坐标变化直接打印该转向的坦克


    PrintTank (my_tank);


}






bool TankCheak(Tank tank,int direction)  //检测坦克前方障碍函数,参量为假坐标。返值1为可通过,返值0为阻挡(人机共用)


{


    switch(direction)                    //direction变量   1上,2下,3左,4右


    {


        case UP:


            if (map[tank.y-2][tank.x]==0 && map[tank.y-2][tank.x-1]==0 && map[tank.y-2][tank.x+1]==0)


                return 1;


            else


                return 0;


        case DOWN:


            if (map[tank.y+2][tank.x]==0 && map[tank.y+2][tank.x-1]==0 && map[tank.y+2][tank.x+1]==0)


                return 1;


    &nbs

 

0.0分

17 人评分

  评论区