目录
制作准备
1.所需头函数
#include<stdio.h> #include<stdlib.h> #include<conio.h> #include<windows.h>
2.自定义函数
①在变量中,我们必须进行定义赋值初始化后,才能在程序中使用,所以需要一个“地方”,整理好这些变量,在程序中整洁一些
void startup() //数据初始化
②打出画面中所显示的所需代码,也给一个函数
void show() //显示画面
③在游戏运行中,飞机的移动,发射等操作必须使用键盘,此时就要进行输入判断,给出相应的函数,实行不同的命令 ,其中分为两种,一种是程序运行时对输入做出变化,另一种是不变化
void updateWithoutInput() //与用户输入无关的更新 void updateWithInput() //与用户有关的更新
最后,必不可少的主函数,把它们全部包起来
int main() { startup(); while(1) { show(); updateWithoutInput(); updateWithInput(); HideCursor(); } return 0; }
3.设置全局变量
首先我们先理解控制台的xy轴方位,这与我们平时所学的数学正方向坐标轴不同,命令提示符窗口
竖方向为X轴,横方向为Y轴。
其中向下为X轴正方向,向右为Y轴正方向
编辑
知道这一点后我们便开始考虑所需要的变量
- 窗口大小(高度宽度)
- 飞机位置
- 子弹位置
- 敌机位置
- 分数统计
大概有以上几种基本内容,所以我们进行定义
int position_x,position_y; //飞机位置 int high,width; //游戏画面尺寸 int bullet_x,bullet_y; //子弹位置 int enemy_x,enemy_y; //敌机位置 int score; //分数
定义后,便在startup()函数中进行初始化
void startup() //数据初始化 { high = 20; width = 30; position_x = high/2; //飞机 position_y = width/2; bullet_x = -2; //子弹 bullet_y = position_y; enemy_x = 0; //敌机 enemy_y = position_y; score = 0; //分数 }
4.清屏函数
第一种是使用清屏函数system("cls");实现屏幕的刷新
(需要配上#include<stdlib.h>使用)
优点:无需太多代码,简单易懂
缺点:屏幕闪烁严重,影响视觉
第二种使用gotoxy()函数。
void gotoxy(int x,int y) //将光标移动到(x,y)位置 { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出设备句柄 COORD pos={x,y}; //坐标位置 SetConsoleCursorPosition(handle,pos); //设置控制台光标位置 } void HideCursor() { CONSOLE_CURSOR_INFO cursor_info={1,0}; //0表示隐藏光标 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info); }
优点:屏幕无闪动,轨迹清晰
缺点:仍有光标不停移动(由于过于高级,所以不需要特意背诵,需要时调用出来就好)
此时可上面的HideCursor()进行光标的隐藏
5.画面布置
一个游戏,总得有点画面出现吧,总不能是一块黑布,啥也没有,所以呢,我们得把飞机,敌机,计数得分,子弹等等都printf()出来
这里呢,则是使用的for和else-if的嵌套使用⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇放到了我们之前预备好的自定义show函数里
void show() //显示画面 { gotoxy(0,0); //光标移动到原点位置,以下重画清屏 int i,j; for(i=0;i<high;i++) { for(j=0;j<width;j++) { if((i==position_x)&&(j==position_y)) printf("*"); //输出飞机* else if((i==enemy_x)&&(j==enemy_y)) printf("@"); //输出敌机 else if((i==bullet_x)&&(j==bullet_y)) printf("||"); //输出子弹 else printf(" "); //输出空格 } printf("\n"); } printf("得分:%d\n",score); }
在上文说到,有两种状态,一种在输入时(即敲打键盘移动、发射)要随之更新,另一种则后台自动更新(敌机的自动移动,分数的自动统计)
很重要的一点,控制飞机的速度,我们使用了if循环,十次循环更新一次敌机位置
(其实还是快了点)
void updateWithoutInput() //与用户输入无关的更新 { if(bullet_x>-1) bullet_x--; // 用来控制敌机移动速度 // 这样修改,虽然用户按键的交互速度还是很快, // 但NPC移动速度降低 static int speed = 0; if(speed<10) { speed++; } if(speed==10) { enemy_x++; speed = 0; } //击中飞机时:加分 if((bullet_x==enemy_x)&&(bullet_y==enemy_y)) { score++; //分数加1 enemy_x = -1; //产生新的飞机 enemy_y = rand()%width; bullet_x = -2; //子弹无效 } //未击中飞机时;飞机离开 if(enemy_x>high) //敌机跑出显示屏幕 { enemy_x = -1; //产生新的飞机 enemy_y = rand()%width; } }
这时就要注意末尾的一个代码,需要特别重视,在我的另一篇博客的末尾有提及(一丢丢)
C语言程序入门——if-else及switch分支结构与for、do-while循环1.1.2
不废话,就是这个rand()%width,让系统自动调用一个随机数,从而在循环中达到随机位置输出敌机的作用
这是与用户输入无关的更新,那接下来就是与用户输入有关的更新了
即游戏四键 “上上下下左右左右(BABA)”(doge保命)还有一个发射子弹(此处使用空格)
正常代码中进行下一步时,需使用回车确认,很明显,我们打游戏总不能走一步用一次回车嘛,由此我们引申出——kbhit()
kbhit是一个无阻碍函数,可以在输入时直接进入后续代码而不卡位置,实现输入即反馈
而与之相反,我们使用阻碍函数getch()实现输入WSAD后进行相应的上下左右移动
6.成果
到了最后,串起来的完整代码附在文末
#include<stdio.h> #include<stdlib.h> #include<conio.h> #include<windows.h> void gotoxy(int x,int y) //将光标移动到(x,y)位置 { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出设备句柄 COORD pos={x,y}; //坐标位置 SetConsoleCursorPosition(handle,pos); //设置控制台光标位置 } void HideCursor() { CONSOLE_CURSOR_INFO cursor_info={1,0}; //0表示隐藏光标 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info); } //全局变量 int position_x,position_y; //飞机位置 int high,width; //游戏画面尺寸 int bullet_x,bullet_y; //子弹位置 int enemy_x,enemy_y; //敌机位置 int score; void startup() //数据初始化 { high = 20; width = 30; position_x = high/2; //飞机 position_y = width/2; bullet_x = -2; //子弹 bullet_y = position_y; enemy_x = 0; //敌机 enemy_y = position_y; score = 0; //分数 } void show() //显示画面 { gotoxy(0,0); //光标移动到原点位置,以下重画清屏 int i,j; for(i=0;i<high;i++) { for(j=0;j<width;j++) { if((i==position_x)&&(j==position_y)) printf("*"); //输出飞机* else if((i==enemy_x)&&(j==enemy_y)) printf("@"); //输出敌机 else if((i==bullet_x)&&(j==bullet_y)) printf("||"); //输出子弹 else printf(" "); //输出空格 } printf("\n"); } printf("得分:%d\n",score); } void updateWithoutInput() //与用户输入无关的更新 { if(bullet_x>-1) bullet_x--; // 用来控制敌机移动速度 // 这样修改,虽然用户按键的交互速度还是很快, // 但NPC移动速度降低 static int speed = 0; if(speed<10) { speed++; } if(speed==10) { enemy_x++; speed = 0; } //击中飞机时:加分 if((bullet_x==enemy_x)&&(bullet_y==enemy_y)) { score++; //分数加1 enemy_x = -1; //产生新的飞机 enemy_y = rand()%width; bullet_x = -2; //子弹无效 } //未击中飞机时;飞机离开 if(enemy_x>high) //敌机跑出显示屏幕 { enemy_x = -1; //产生新的飞机 enemy_y = rand()%width; } } void updateWithInput() //与用户有关的更新 { char input; if(kbhit()) //根据用户的不同输入来移动,不必输入回车 { input = getch(); if(input=='a') position_y--; if(input=='d') position_y++; if(input=='w') position_x--; if(input=='s') position_x++; if(input==' ') { bullet_x = position_x-1; //从飞机正上方发生子弹 bullet_y = position_y; } } } int main() { startup(); while(1) { show(); updateWithoutInput(); updateWithInput(); HideCursor(); //隐藏光标 } return 0; }
学艺不精,多多包涵