目录
前言
一、飞机游戏的代码
二、代码解析
1、代码重构
1)主函数
2)其它函数
2、新的子弹
3、敌机
1)静止的敌机
2)敌机的移动
3)击中敌机
4、清屏功能
总结
前言
代码参考了《C语言课程设计与游戏开发实践教程》
游戏介绍:
对我之前的博客 C语言——简单的飞机小游戏 升级,玩法和之前的没有区别,只是代码的实现不同,依旧是玩家通过输入 "W S A D" 控制飞机 " * " 的上下左右移动,同时可以通过空格键来让飞机发射激光击中敌机 " @ "。
一、飞机游戏的代码
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>//定义边界,游戏边界
#define HIGH 20
#define WIDTH 30// 全局变量
int position_x, position_y; // 飞机位置
int bullet_x, bullet_y; // 子弹位置
int enemy_x, enemy_y; // 敌机位置
int score; // 得分void gotoxy(int x, int y) // 光标移动到(x,y)位置
{HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);COORD pos;pos.X = x;pos.Y = y;SetConsoleCursorPosition(handle, pos);
}void HideCursor() // 用于隐藏光标
{CONSOLE_CURSOR_INFO cursor_info = {1, 0}; // 第二个值为0表示隐藏光标SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}void startup() // 数据初始化
{position_x = HIGH / 2;position_y = WIDTH / 2;bullet_x = -2;bullet_y = position_y;enemy_x = 0;enemy_y = position_y;score = 0;HideCursor(); // 隐藏光标
}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 if (i == HIGH - 1)printf("-");else if (j == WIDTH - 1)printf("|"); // 输出边界elseprintf(" "); // 输出空格}printf("\n");}printf("得分:%d\n", score);
}void updateWithoutInput() // 与用户输入无关的更新
{if (bullet_x > -1)bullet_x--;if ((bullet_x == enemy_x) && (bullet_y == enemy_y)) // 子弹击中敌机{score++; // 分数加1enemy_x = -1; // 产生新的飞机enemy_y = rand() % WIDTH;bullet_x = -2; // 子弹无效}if (enemy_x > HIGH) // 敌机跑出显示屏幕{enemy_x = -1; // 产生新的飞机enemy_y = rand() % WIDTH;}// 用来控制敌机向下移动的速度。每隔几次循环,才移动一次敌机// 这样修改的话,用户按键交互速度还是保持很快,但我们NPC的移动显示可以降速static int speed = 0;if (speed < 20)speed++;if (speed == 20){enemy_x++;speed = 0;}
}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(); // 与用户输入有关的更新}return 0;
}
二、代码解析
1、代码重构
1)主函数
对之前只是在主函数中实现的功能,我们首先来将需要实现的功能进行拆分,让它通过一个个函数来实现,最后通过主函数来实现功能的统一(实现预期效果)。
int main()
{startup(); // 数据初始化while (1) // 游戏循环执行{show(); // 显示画面updateWithoutInput(); // 与用户输入无关的更新updateWithInput(); // 与用户输入有关的更新}return 0;
}
将我们需要达到的预期效果分成若干个函数,让需要重复实现的放在循环中。
2)其它函数
对主函数进行重构后,对之前小游戏进行功能的模块化(通过相应的函数来实现)。
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>// 定义边界,游戏边界
#define HIGH 20
#define WIDTH 30// 全局变量
int position_x, position_y; // 飞机位置void startup() // 数据初始化
{position_x = HIGH / 2;position_y = WIDTH / 2;
}void show() // 显示画面
{system("cls");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 == HIGH - 1)printf("-");else if (j == WIDTH - 1)printf("|"); // 输出边界elseprintf(" "); // 输出空格}printf("\n");}
}void updateWithoutInput() // 与用户输入无关的更新
{}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++; // 位置下移}
}int main()
{startup(); // 数据初始化while (1) // 游戏循环执行{show(); // 显示画面updateWithoutInput(); // 与用户输入无关的更新updateWithInput(); // 与用户输入有关的更新}return 0;
}
到此我们就完成了对之前代码的重构,这里我没有使用之前的飞机模型,使用的是 " * " 来代替飞机。
2、新的子弹
实现之前的功能之后我们来实现新的功能和对旧功能的优化。这一次我们让子弹发射后自动向前飞行。通过在打印飞机和边界的函数中添加新的分支来实现子弹的打印。
void show() // 显示画面
{system("cls"); //清屏函数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 == bullet_x) && (j == bullet_y))printf("|"); // 输出子弹|else if (i == HIGH - 1)printf("-");else if (j == WIDTH - 1)printf("|"); // 输出边界elseprintf(" "); // 输出空格}printf("\n");}
}
3、敌机
接下来就是敌机的实现了
1)静止的敌机
首先我们来实现敌机的出现。
依旧是在打印飞机的函数中增加新的分支来实现敌机 " @ " 的出现。(记得定义敌机相应的变量)
void show() // 显示画面
{system("cls"); //清屏函数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 if (i == HIGH - 1)printf("-");else if (j == WIDTH - 1)printf("|"); // 输出边界elseprintf(" "); // 输出空格}printf("\n");}
}
2)敌机的移动
实现敌机的出现后我们来移动敌机,为了降低敌机的移动速度而不影响玩家输入相应的频率。这里通过定义静态变量speed来让每实现20次 updateWithoutInput() 函数,敌机飞行一次。
// 用来控制敌机向下移动的速度。每隔几次循环,才移动一次敌机// 这样修改的话,用户按键交互速度还是保持很快,但我们NPC的移动显示可以降速static int speed = 0;if (speed < 20)speed++;if (speed == 20){enemy_x++;speed = 0;}
3)击中敌机
通过判断飞机和子弹的位置来判断是否击中敌机,如果击中就通过随机数来实现新敌机的出现。
void updateWithoutInput() // 与用户输入无关的更新
{if (bullet_x > -1)bullet_x--;if ((bullet_x == enemy_x) && (bullet_y == enemy_y)) // 子弹击中敌机{score++; // 分数加1enemy_x = -1; // 产生新的飞机enemy_y = rand() % WIDTH;bullet_x = -2; // 子弹无效}if (enemy_x > HIGH) // 敌机跑出显示屏幕{enemy_x = -1; // 产生新的飞机enemy_y = rand() % WIDTH;}// 用来控制敌机向下移动的速度。每隔几次循环,才移动一次敌机// 这样修改的话,用户按键交互速度还是保持很快,但我们NPC的移动显示可以降速static int speed = 0;if (speed < 20)speed++;if (speed == 20){enemy_x++;speed = 0;}
}
4、清屏功能
到这里基本已经实现了我们预期的效果,但会发现闪烁非常严重,这个时候我们只需要将通过移动光标来让画面重新画过就可以了,同时实现光标的隐藏。
void gotoxy(int x, int y) // 光标移动到(x,y)位置
{HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);COORD pos;pos.X = x;pos.Y = y;SetConsoleCursorPosition(handle, pos);
}void HideCursor() // 用于隐藏光标
{CONSOLE_CURSOR_INFO cursor_info = {1, 0}; // 第二个值为0表示隐藏光标SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
总结
我没有对这里使用到的知识点做出解释,相应的知识点请看这里
清屏函数:C语言——函数的综合运用。自定义函数,gotoxy清屏函数与HideCursor隐藏光标,防闪屏,共同制作打飞机游戏。_void hidecursor功能_冰小九的博客-CSDN博客https://blog.csdn.net/neadsc/article/details/126722743?ops_request_misc=&request_id=&biz_id=102&utm_term=C%E8%AF%AD%E8%A8%80%E6%B8%85%E5%B1%8F%E5%87%BD%E6%95%B0%E8%AF%A6%E8%A7%A3&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-126722743.142%5Ev74%5Einsert_down2,201%5Ev4%5Eadd_ask,239%5Ev2%5Einsert_chatgpt&spm=1018.2226.3001.4187
随机数:C语言随机数的生成【详解】_星空之路Star的博客-CSDN博客https://blog.csdn.net/weixin_46022083/article/details/106661495?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167911124816800217231790%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167911124816800217231790&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-106661495-null-null.142%5Ev74%5Einsert_down2,201%5Ev4%5Eadd_ask,239%5Ev2%5Einsert_chatgpt&utm_term=%E9%9A%8F%E6%9C%BA%E6%95%B0&spm=1018.2226.3001.4187