为期两周的实训结束了,写一篇飞机大战纪念一下,因为之前对于编程可能也没有太深入系统的学习,这个实训应该标志着编程学习的由浅入深,也代表着我们学习正式开始。(所以说之前一年我们学了点什么。。。) 在拿到我们最后的要求时我其实还是有些犹豫,毕竟之前刚做过链表,写起贪吃蛇来相比飞机大战可能会比较容易,但后来又想到老师会给我们一些提示,于是我理所当然的飘了。。。。认为写出来的飞机大战应该会是这样的: 但是在提示给出来之后是这样的: 。。。。。。。。。。。 只能说菜给的太多了,喝成了这个样子
话不多说,还是脚踏实地一步一步写的好。
一、游戏要求:
按照一定的规则排列的“*”模拟玩家飞机,向下移动的“@”符号表示敌机,由下至上间断显示的“|”模拟子弹,界面下方显示飞机的生命值,的分情况等等。 每当玩家飞机撞上敌机生命值减1,程序自动生成另一架位置随机的飞机继续游戏,直到生命值为0游戏结束。 通过wasd键控制飞机移动,通过空格键发射激光子弹,要求:采用多文件结构实现。
二、实验设计
程序应该主要涉及到两个模块,分别为主模块mainfighter 和子模块fighter,子模块主要包含初始化功能函数init(),绘制游戏界面函数drawpitcure(),电脑操作子界面与敌机函数pcoperate(),玩家控制飞机函数operatefighter()。 主模块只有mainfighter这一个文件,以下为框架:
void main(){
init();
while(1);{
drawpicture();
pcoperate();
operatefighter();
}
system("pause");
}
相应的功能在具体的函数中实现。
三 函数调用思路
绘制游戏界面函数drawpicture() 外层循环变量x控制行输出,内层循环变量y控目列输出,内层循环语句不断判断当前坐标与玩家飞机、敌机、激光束子弹位置是否重叠,前坐标值(x,y)为(fighter. x, fighter. y)时向屏幕输出玩家飞机“*”,当前坐标值为(enemyenemy_ y)时向屏幕输出敌机“@”,当前坐标值为(bullet x, bullet y)时向屏幕输出激光子弹否则输出空格,从而实现了在屏幕上看到玩家飞机、敌机、激光束子弹的效果。
此时实现的游戏界面上的玩家飞机、敌机、激光子弹等是静止的,要想实现动态效需要不断改变玩家飞机、敌机、激光東子弹坐标值实现动态效果。
3)电脑操作子弹与敌机函数pcOperate0
pcOperate()函数相对简单,调用flatBaullet)函数实现激光束子弹向上漂浮效果,调用enemyfighter()实现敌机移动,被击落后随机生成敌机的视觉效果等。 eneyfighter(函数实现敌机移动、被击落后随机生成放机的视觉效果等) 4控制飞机operateFighter()
该西数主要实现玩家飞机移动、发射激光束子弹,通过按W5. 2小建控朝元家飞机上下左右移动,通过按下空格键发射激光子弹。
判断当前按键改变相应坐标值实现飞机移动、发射激光束子弹功能。当按下”键时表示向.上移动,玩家飞机纵向坐标减1横向坐标不变,即fighter X–;当按下“d”键时表不向右移动,玩家飞机横向坐标加1纵向坐标不变,即fighter y++。当按下空格键时表示发射激光束子弹,则在飞机正上方生成子弹,即将激光束子弹坐标值为(ighter_ x- 1, fighter y)。 五、编码实现 将游戏画面尺寸、玩家飞机位置、激光束子弹位置、敌机位置等定义为全局变量:
int height,width;
int fighter_x,fighter_y;
int bullet_x,bullet_y;
int enemy_x;enemy_y;
string difficulty
init 函数要实现对上述全局变量赋值的功能,一般将玩家飞机显示在画面中间的位置,敌机显示在第一行,飞机坐标(fighter_x,fighter_y)设置为(height/2,width/2),敌机坐标为(enemy_x,enemy_y),设置为(0,rand()%(width-5)+2)。 drawpicture函数实现 通过双层函数循环控制光标移动,当坐标值(x,y)满足特定的条件时向屏幕输出玩家飞机,敌机,光束子弹。
cout << setfill('#') << setw(width + 6) << "#" << endl;
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width + 1; y++)
{
if (y == 0)
cout << "#";
else if (y == width)
{
if (x == fighter_x)
cout << "#";
else if (x == fighter_x + 1)
cout << setfill(' ') << "#";
else if (x == fighter_x + 2)
cout << setfill(' ') << "#";
else cout << setfill(' ') << setw(6) << "#";
}
else if ((x == fighter_x) && (y == fighter_y))
cout << setfill(' ') << setw(6) << "* ";
else if ((x == fighter_x + 1) && (y == fighter_y))
cout << setfill('*') << setw(6) << " ";
else if ((x == fighter_x + 2) && (y == fighter_y))
cout << setfill(' ') << setw(6) << "* * ";
else if ((x == bullet_x) && (y == bullet_y))
cout << "|";
else if (x == enemy_x && y == enemy_y)
cout << "@";
else cout << " ";
}
cout << endl;
}
cout << setfill('#') << setw(width + 6) << "#" << endl;
cout << "难度:" << difficulty << endl;
cout << "生命:" << fighter << endl;
cout << "得分:" << score << endl;
operatefighter编码实现 调用floatbullet 函数处理子弹移动,调用enemyfighter函数实现生成敌机、移动等等。 bullet_x–实现子弹移动 要想设置难度层次,就要设法控制敌机向下移动的速度。因此设置静态变量speed,每执行几次,敌机就移动一次。
static int speed = 10;
difficulty = "简单";
if (score > 5) {
speed++;
difficulty = "普通";
}
if (score > 15) {
speed++;
difficulty = "困难";
}
if (speed < 10) {
speed += 2;
}
else {
enemy_x++;
speed = 0;
最后,是击中敌机。在enemyfighter中增加判断,当子弹和敌机位置相同时就击中敌机,并增加变量score记录得分,击中敌机后+1;敌机被击中后会消失,然后在随机位置出现
if((bullet_x==enemy_x)&&(bullet_y==enemy_y))
{
score++;
enemy_x=-1;
enemy_y=rand()%(width-5)+2;
bullet_x=-2;
思路大致如下,但是在操作过程中,由于飞机体型较大,在击中敌机过程中无法准确被击毁,此外还存在着敌机在移动过程的瞬间子弹击中敌机无效的情况,因此更改判断条件,使得飞机任何位置碰到敌机都会被击毁;子弹能够准确的击毁敌机。
if (((bullet_x == enemy_x) && (bullet_y == enemy_y)) || ((bullet_x + 1 == enemy_x) &&
(bullet_y == enemy_y)) || ((bullet_x - 1 == enemy_x) && (bullet_y == enemy_y)))
{
score++;
enemy_x = -1;
enemy_y = rand() % (width - 5) + 3;
bullet_x = -2;
}
if ((enemy_x == fighter_x) && ((enemy_y == fighter_y) ||
(enemy_y == fighter_y + 1) || (enemy_y == fighter_y + 3) ||
(enemy_y == fighter_y + 4)) || ((enemy_x == fighter_x) &&
(enemy_y == fighter_y + 2)))
{
fighter--;
fighter_x = rand() % (height - 5) + 2;
fighter_y = rand() % (width - 5) + 2;
enemy_x = -1;
enemy_y = rand() % width;
lose();
}
if (enemy_x > height) {
score--;
enemy_x = -1;
enemy_y = rand() % width;
lose();
}
目前屏幕的闪烁严重,还存在光标,因此需要一个函数实现清屏效果,这里直接调用了windows.库函数来实现
void zeroXy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
void hidecursor() {
CONSOLE_CURSOR_INFO consor_info = { 1,0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consor_info);
}
最后就是要时刻判断游戏的输赢情况,当生命值为0时或者得分小于0时则游戏失败,再定义一个函数来实现
void lose() {
if (fighter < 0 || score < 0) {
cout << endl;
cout << "**********************你输了!*********************" << endl;
system("pause");
exit(0);
}
}
至此飞机大战全部内容就完成了,生成代码如下(包含一个头文件,一个子模块和一个主模块)
#ifndef _fighter_h
#define _fighter_h
void drawPicture();
void init();
void OperateFighter();
void pcOperate();
void floatBullet();
void enemyFighter();
void zeroXy(int x, int y);
void hidecursor();
void lose();
#endif
#include<iostream>
#include<conio.h>
#include<Windows.h>
#include<iomanip>
#include"fighter.h"
using namespace std;
int height = 20;
long width = 30;
int fighter_x, fighter_y;
int bullet_x, bullet_y;
int enemy_x, enemy_y;
int score;
int fighter;
string difficulty;
void drawPicture() {
zeroXy(0, 0);
cout << setfill('#') << setw(width + 6) << "#" << endl;
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width + 1; y++)
{
if (y == 0)
cout << "#";
else if (y == width)
{
if (x == fighter_x)
cout << "#";
else if (x == fighter_x + 1)
cout << setfill(' ') << "#";
else if (x == fighter_x + 2)
cout << setfill(' ') << "#";
else cout << setfill(' ') << setw(6) << "#";
}
else if ((x == fighter_x) && (y == fighter_y))
cout << setfill(' ') << setw(6) << "* ";
else if ((x == fighter_x + 1) && (y == fighter_y))
cout << setfill('*') << setw(6) << " ";
else if ((x == fighter_x + 2) && (y == fighter_y))
cout << setfill(' ') << setw(6) << "* * ";
else if ((x == bullet_x) && (y == bullet_y))
cout << "|";
else if (x == enemy_x && y == enemy_y)
cout << "@";
else cout << " ";
}
cout << endl;
}
cout << setfill('#') << setw(width + 6) << "#" << endl;
cout << "难度:" << difficulty << endl;
cout << "生命:" << fighter << endl;
cout << "得分:" << score << endl;
}
void init() {
fighter_x = height / 2;
fighter_y = width / 2;
enemy_x = 0;
enemy_y = fighter_y;
bullet_x = -2;
bullet_y = fighter_y;
score = 0;
fighter = 3;
hidecursor();
}
void OperateFighter() {
char input;
if (_kbhit()) {
input = _getch();
if (input == 'a') {
if (fighter_y > 1)
fighter_y--;
}
else if (input == 'd') {
if (fighter_y < width - 1)
fighter_y++;
}
else if (input == 'w') {
if (fighter_x > 0)
fighter_x--;
}
else if (input == 's') {
if (fighter_x < height)
fighter_x++;
}
if (input == ' ') {
bullet_x = fighter_x - 1;
bullet_y = fighter_y + 2;
}
}
}
void pcOperate() {
floatBullet();
enemyFighter();
}
void floatBullet() {
if (bullet_x > -1)
bullet_x--;
}
void enemyFighter() {
static int speed = 0;
difficulty = "简单";
if (score > 5) {
speed++;
difficulty = "普通";
}
if (score > 15) {
speed++;
difficulty = "困难";
}
if (speed < 10) {
speed += 2;
}
else {
enemy_x++;
speed = 0;
}
if (((bullet_x == enemy_x) && (bullet_y == enemy_y)) || ((bullet_x + 1 == enemy_x) &&
(bullet_y == enemy_y)) || ((bullet_x - 1 == enemy_x) && (bullet_y == enemy_y)))
{
score++;
enemy_x = -1;
enemy_y = rand() % (width - 5) + 3;
bullet_x = -2;
}
if ((enemy_x == fighter_x) && ((enemy_y == fighter_y) ||
(enemy_y == fighter_y + 1) || (enemy_y == fighter_y + 3) ||
(enemy_y == fighter_y + 4)) || ((enemy_x == fighter_x) &&
(enemy_y == fighter_y + 2)))
{
fighter--;
fighter_x = rand() % (height - 5) + 2;
fighter_y = rand() % (width - 5) + 2;
enemy_x = -1;
enemy_y = rand() % width;
lose();
}
if (enemy_x > height) {
score--;
enemy_x = -1;
enemy_y = rand() % width;
lose();
}
}
void zeroXy(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
void hidecursor() {
CONSOLE_CURSOR_INFO consor_info = { 1,0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consor_info);
}
void lose() {
if (fighter < 0 || score < 0) {
cout << endl;
cout << "**********************你输了!*********************" << endl;
system("pause");
exit(0);
}
}
#include<iostream>
#include<conio.h>
#include<Windows.h>
#include<iomanip>
#include"fighter.h"
using namespace std;
int main() {
init();
while (1) {
drawPicture();
pcOperate();
OperateFighter();
}
system("pause");
}
运行截图如下:
|