/*怎么在帖子上插入文件?*/ /*请在tc2.0的环境下编译,运行!*/ /*提示:如果发现游戏过快或过慢请修改Pc_Delay的值(越大游戏越慢),以达到最好的运行效果*/ /*这个版本中你永远死不了(从你的分数中可以看出你死亡的情况),但可以供程序爱好者修改相应的函数达到自己不同的游戏规则*/ #include <stdio.h> #include <stdlib.h> #include <bios.h> #include <graphics.h> /*定义键盘扫描码*/ #define k_up 18432 #define k_down 20480 #define k_left 19200 #define k_right 19712 #define k_space 14624 #define k_esc 283 #define k_p 6512
#define Tk_Spd 5000 /*敌方坦克的行走速度(可升级,修改这个值可以获得不同的执行速度)*/ #define Zd_Spd 1250 /*子弹的飞行速度*/ #define Ntank_Time 50000 /*产生新坦克的间隔时间*/ #define Zd_Time 6000 /*计算机发出子弹的间隔时间(可升级,修改这个值可以获得不同的执行速度)*/ #define Pc_Delay 20 /*不同速度的计算机可能不同!如果有必要的话可以修改*/
#define M_Max 21 /*游戏框大小为21*30*/ #define N_Max 30
typedef enum {F_Begin,F_Pause,F_Exit} Fun_Flag; /*游戏操作的功能标志*/ typedef enum {Tk_No,Tk_Up,Tk_Down,Tk_Left,Tk_Right} Tk_Direct; /*坦克行进的方向标志,Tk_No表示销毁或者其他*/ typedef enum {Dt_Zero,Dt_Em,Dt_Me} Dt_Type; /*存储在游戏矩阵中的数据类*/ /*Dt_Zero表示没有数据,Dt_Em,表示敌人的坦克或者子弹,Dt_Me表示自己的坦克或子弹*/
typedef struct Tk_Node { /*坦克事件的结点定义*/ int x; int y; /*位置数据*/ Dt_Type type; /*数据类型*/ Tk_Direct drct; /*坦克的方向*/ struct Tk_Node* next; }Tk_Node,*Tk_Link;
typedef struct Zd_Node { /*子弹事件的结点定义*/ int x; int y; /*子弹的位置*/ int is_fst; /*是否是刚发射的子弹*/ Dt_Type type; /*子弹的数据类型(敌方的还是自己的)*/ Tk_Direct drct; /*子弹的飞行方向*/ struct Zd_Node* next; }Zd_Node,*Zd_Link;
Dt_Type Gm_Array[M_Max][N_Max]; /*建立游戏矩阵,游戏矩阵中的每一个点对应着屏幕上的显示*/ /*一个坦克用3*3大小的矩阵存储,用中间那个点表示坦克的位置(表示坦克的存在)*/ Tk_Link Tk_List; /*建立坦克事件链表*/ Zd_Link Zd_List; /*建立子弹事件链表*/ int cs_tks; /*游戏中所有产生的坦克数目*/ int kill_tks; /*你在玩游戏过程中杀死的敌方坦克数目*/ int Me_Deads; /*你被敌方坦克杀死的次数*/ /*cs_tks-kill_tks表示目前在屏幕上的坦克个数(用于控制屏幕中坦克的数目以防止过多的坦克同时在屏幕上出现)*/
static char ct_dx[4]={-1,1,0,0}; /*以下定义常用的检查表。它们的具体功能见程序中*/ static char ct_dy[4]={0,0,-1,1}; static char frtlbx[4][5]={{-1,-2,-2,-2,-1},{1,2,2,2,1},{-1,-1,0,1,1},{-1,-1,0,1,1}}; static char frtlby[4][5]={{-1,-1,0,1,1},{-1,-1,0,1,1},{-1,-2,-2,-2,-1},{1,2,2,2,1}}; static int rot_d[4][3]={{3,2,4},{4,1,3},{2,4,1},{1,3,2}}; /***************************************/ void opengraph(void); /*打开图形模式*/ void Draw_Node(int x,int y,Dt_Type type); /*在屏幕上画一个方块(底层函数,用于画坦克或子弹,一个坦克用6个方块组成)*/ void Draw_Tankone(int x,int y,Tk_Direct d,int who); /*在屏幕上画一个坦克,d为坦克的初始朝向,who表示是那种坦克(自己或是敌人坦克)*/ void Rot_Tank(int x,int y,int LR); /*对坦克进行旋转操作,(x,y)表示要旋转的坦克,lr表示旋转的程度(左旋,右旋,后旋),该函数用于坦克的转向*/ void Move_Tank(int x,int y,Tk_Direct type); /*移动一个坦克,type表示移动的方向*/ void Control_Tank(Tk_Link p,Tk_Direct direct); /*用于控制自己的坦克*/ void Insert_Tklink(int x,int y,Dt_Type type,Tk_Direct drct); /*将一个坦克加入坦克事件链表*/ void Insert_Zdlink(int x,int y,Dt_Type type,Tk_Direct drct); /*将一个子弹加入子弹事件链表*/ int Delete_Tklink(int x,int y); /*在坦克事件链表上删除一个坦克*/ int Delete_Zdlink(int x,int y); /*在子弹事件链表上删除一个坦克*/ void Init_Tklink(void); /*初始化坦克事件链表*/ void Init_Zdlink(void); /*初始化子弹时间链表*/ void Delete_Allt(void); /*删除全部坦克事件(用于游戏结束)*/ void Delete_Allz(void); /*删除全部子弹时间(用于游戏结束*/ void Init(void); /*初始化游戏的所有变量和数据结构*/ int Front_Ok(Tk_Link p,Tk_Direct direct); /*查看坦克的前方是否可以行进(用于坦克的行走)*/ void Mul_zd(void); /*处理子弹事件(如果有子弹事件产生的话)*/ void Kill_Em(int x,int y); /*杀死一个敌方坦克*/ void Game_Over(void); /*处理自己被敌方坦克击中的事件(&&&&&&可以修改这个函数获得不同游戏规则)*/ int Check_is_zd(int x,int y); /*查看前方是否是一个子弹(用于子弹与子弹碰撞的处理)*/ void Product_Zd(void); /*用于产生子弹事件*/ void Move_All_Tank(void); /*用于处理敌方坦克移动事件*/ int Check_f_again(Tk_Link p); /*用于坦克旋转的二次检查*/ void Create_Ntk(void); /*产生新的坦克*/ int has_a_tk(int x,int y); /*查看在(x,y)这个位置上有没有坦克(用于产生新的坦克)*/ void erase_scores(void); /*记分辅助函数(擦除并从新显示)*/
void main(void) { Fun_Flag flag_f=F_Begin; /*游戏控制的功能类型*/ int keyid; /*存放键盘扫描码*/ Tk_Direct direct; /*定义坦克的方向*/ int zdsd=Zd_Spd; /*子弹的速度*/ int zdjg=Zd_Time; /*子弹的飞行间隔时间(速度的快慢)*/ int tksd=Tk_Spd; /*坦克的移动速度*/ long int ntk=Ntank_Time; /*产生新坦克的间隔时间*/ Tk_Direct temp; /*方向暂存*/ puts("\n\n\n\n\n This Game Programed by STN_LCD! \n\n My QQ:33244197 E_Mail:dianzi8801@sina.com"); printf("\n\n\n\n\n Press anykey to start game......."); getch(); opengraph(); /*打开图形模式并注册图形驱动*/ setcolor(WHITE); /*设置为白色(用于画框)*/ rectangle(8,8,612,432); /*画游戏大方框*/ setcolor(YELLOW); /*输出游戏信息*/ settextstyle(0,0,2); outtextxy(10,450,"TANK!"); outtextxy(400,450,"Scores:"); randomize(); /*初始化随机数生成器的种子*/ Init(); /*初始化游戏数据结构和相关的变量*/ while(flag_f!=F_Exit) { /*对当前的功能类型的选择进行判断*/ if(bioskey(1)) { /*检查是否有键按下*/ keyid=bioskey(0); /*读取所按键的扫描码*/ switch(keyid) { /*对所按键的类型判断*/ case k_up: /*如果是向上的按键*/ if(flag_f==F_Begin) Control_Tank(Tk_List,Tk_Up);/*控制坦克向上移动*/ /*在函数中调用Tk_List表示自己的坦克,因为在定义坦克事件链表时总是将自己的坦克放在链表头那里*/ break; case k_down: /*如果是向下的按键*/ if(flag_f==F_Begin) Control_Tank(Tk_List,Tk_Down); /*控制坦克向下移动*/ break; case k_left: /*如果是向左的按键*/ if(flag_f==F_Begin) Control_Tank(Tk_List,Tk_Left); /*。。。。*/ break; case k_right: if(flag_f==F_Begin) Control_Tank(Tk_List,Tk_Right); break; case k_space: if(flag_f==F_Begin) { /*产生了一个子弹事件,并处理这个子弹事件*/ temp=Tk_List->drct; /*插入子弹事件队列(类型标志为我方子弹)*/ Insert_Zdlink(Tk_List->x+ct_dx[temp-1],Tk_List->y+ct_dy[temp-1],Dt_Me,temp); } break; case k_p: /*用于处理游戏暂停*/ if(flag_f!=F_Pause) flag_f=F_Pause; /*置类型标志为暂停标志*/ else flag_f=F_Begin; /*反向处理暂停*/ break; case k_esc: /*退出游戏的处理*/ setcolor(WHITE); outtextxy(70,300,"GAME OVER! Made By STN_LCD!"); flag_f=F_Exit; break; } } delay(Pc_Delay); /*设置分频基数为Pc_Delay个单位*/ if(flag_f==F_Begin) { /*如果标志为暂停是不处理下列事件*/ if(Zd_List&&!(--zdsd)) { /*如果子弹事件队列中有事件并且定时时间达到就去处理子弹事件*/ Mul_zd(); zdsd=Zd_Spd; } if(Tk_List&&Tk_List->next&&!(--zdjg)) {/*如果有坦克的话,那么让这些坦克打出子弹*/ Product_Zd(); /*产生子弹*/ zdjg=Zd_Time; } if(Tk_List&&Tk_List->next&&!(--tksd)) {/*如果有坦克(敌方坦克)的话,让这些坦克移动*/ Move_All_Tank(); /*移动所有敌方坦克*/ tksd=Tk_Spd; } if((cs_tks-kill_tks)<=15&&!(--ntk)) { /*如果屏幕中的敌方坦克数目小于15(左右),产生新的坦克*/ Create_Ntk(); /*产生新的坦克*/ ntk=Ntank_Time; } } } getch(); closegraph(); }
void erase_scores(void) { setfillstyle(SOLID_FILL,BLACK); /*刷新记分的屏幕*/ bar(517,435,630,465); setcolor(YELLOW); }
void Game_Over(void) { /*当敌人的坦克打到你,就会调用这个函数,可以编写不同的代码从而实现不同的游戏规则*/ static char format_GO[10]; ++Me_Deads; erase_scores(); /*在屏幕中显示分数*/ outtextxy(520,450,itoa(kill_tks-Me_Deads,format_GO,10)); /*当前分数的记法为:你所杀死的坦克数目-你死去的数目*/ }
void opengraph(void) {/*打开图形模式,并注册图形驱动*/ int gdriver=VGA,gmode=VGAHI; registerbgidriver(EGAVGA_driver); initgraph(&gdriver,&gmode,""); }
int has_a_tk(int x,int y) { /*判断在(x,y)位置是否有一个坦克(或其他的障碍),用于产生新的坦克*/ int i,tx,ty; int flag=1; for(i=0;i<9&&flag;i++) { /*对该点四周检查*/ tx=x+i/3-1; ty=y+(i+3)%3-1; if(Gm_Array[tx][ty]) flag=0; /*如果该点的周围有东西的话,就表示不应该在这个地方产生坦克*/ } return !flag; }
void Create_Ntk(void) { /*在屏幕的四个角产生新的坦克(每个角产生坦克的概率为1/2)*/ if(rand()%2&&!has_a_tk(1,1)) { /*判断:“1/2的概率” 且 “在(1,1)位置是否有东西”*/ Insert_Tklink(1,1,Dt_Em,Tk_Down); /*如果满足产生新坦克的条件,则产生新的坦克*/ /*产生的方法为:在坦克事件队列中插入一个坦克,并画出这个坦克*/ Draw_Tankone(1,1,Tk_Down,0); ++cs_tks; } if(rand()%2&&!has_a_tk(1,28)) { Insert_Tklink(1,28,Dt_Em,Tk_Down); Draw_Tankone(1,28,Tk_Down,0); ++cs_tks; } if(rand()%2&&!has_a_tk(19,1)) { Insert_Tklink(19,1,Dt_Em,Tk_Up); Draw_Tankone(19,1,Tk_Up,0); ++cs_tks; } if(rand()%2&&!has_a_tk(19,28)) { Insert_Tklink(19,28,Dt_Em,Tk_Up); Draw_Tankone(19,28,Tk_Up,0); ++cs_tks; } }
void Move_All_Tank(void) { /*从坦克事件队列中依次取出坦克并移动它们*/ Tk_Link p=Tk_List->next; int rot; while(p) { /*读取坦克队列中的每一个坦克*/ if(Front_Ok(p,p->drct)) { /*如果前方没有障碍的话*/ Move_Tank(p->x,p->y,p->drct); /*向前移动坦克*/ p->x+=ct_dx[p->drct-1]; p->y+=ct_dy[p->drct-1]; } else if(Check_f_again(p)) { /*如果前方有障碍,查看该坦克是否满足旋转(掉头)的条件*/ rot=rand()%3-1; /*旋转掉头的方向为随机*/ Rot_Tank(p->x,p->y,rot); /*旋转该坦克*/ p->drct=rot_d[p->drct-1][rot+1]; /*从新设置旋转的方向*/ } p=p->next; } }
int Check_f_again(Tk_Link p) { /*查看旋转是否满足条件*/ static int ck_a[4][3]={{0,2,7},{1,6,8},{0,5,6},{2,3,8}}; /*应该查看的点的位置矩阵*/ /*采用静态查表可以节约大量的时间*/ /* 0 1 2 0 1 0 坦克在矩阵中的存储顺序为: 3 4 5 如坦克:1 1 1 在处理中要进行矩阵变换 6 7 8 1 0 1 */ int tx,ty,i; int flag=1; for(i=0;i<3&&flag;i++) { /*对应该检查的点进行逐个检查*/ tx=p->x+ck_a[p->drct-1][i]/3-1; /*进行坦克相对位置到游戏矩阵(Gm_Array)的地址变换*/ ty=p->y+(ck_a[p->drct-1][i]+3)%3-1; if(Gm_Array[tx][ty]!=Dt_Zero) flag=0; } return flag; }
int Front_Ok(Tk_Link p,Tk_Direct direct) { /*对坦克前方的5个点进行检测*/ int i,flag=0,tx,ty; for(i=0;i<5&&!flag;i++) { tx=p->x+frtlbx[direct-1][i]; /*查frtlbx表(确定5个点的查找位置)*/ ty=p->y+frtlby[direct-1][i]; if(tx<0||tx>M_Max-1||ty<0||ty>N_Max-1) flag=1; else if(Gm_Array[tx][ty]!=Dt_Zero) flag=1; } return !flag; }
void Product_Zd(void) { /*产生子弹事件*/ Tk_Link p=Tk_List->next; int temp; while(p) { /*查坦克链表,对每一个坦克都有1/2的概率打出子弹*/ if(rand()%2) { temp=p->drct; /*将产生的子弹插入到子弹链表中去*/ Insert_Zdlink(p->x+ct_dx[temp-1],p->y+ct_dy[temp-1],Dt_Em,temp); } p=p->next; } }