飞机大战详解 C语言


小游戏就以飞机大战为例吧

首先说一下我对游戏的理解,游戏主要就是由动画、交互两大部分组成,
而动画则是由一帧一帧的图片组成。
所以要想在控制台中实现动画,那就要实现屏幕的刷新,就是把上一帧
的图片给清除掉,清除的方法有很多,在这里就用最简单的实现方法
system(“cls”);

首先实现屏幕的自动刷新

while (1)					
	{
		Show();					//屏幕显示画面
		InputWithData();		//执行与用户有关的数据
		InputWithoutData();		//执行与用户无关的数据
		system("cls");			//清屏函数,每次调用都将
	}							//上次的画面清除

将整个程序的主要函数放在一个死循环中,不停的调用结合清屏函数, 实现动画的显示
InputWithData();
InputWithoutData();
这两个函数后序再添加内容

显示画面
也即是Show()里面的内容

for (int i = 0; i < Heigh; i++)		//Height 为定义的高度
	{
		for (int j = 0; j < Width; j++)	//Width 宽度
		{	//PlayerPos为玩家坐标	 X、Y轴
			if (i == PlayerPosY&&j == PlayerPosX)  
			{
				cout << "*";
			}
			{
				cout << " ";
			}
		}
		cout << endl;
	}

以空格打印一个界面,在打印空格时,当横纵坐标等于玩家坐标时则打印* (这个就暂且当做玩家吧。。。)
输出之后是这样的一个界面

在这里插入图片描述

然后就是和用户的交互了

1.首先是实现用户的移动

直接上代码

void InputWithData()
{
	Movement();
}
void Movement(){
	char input;
	if (_kbhit())
	{
		input = _getch();
		switch (input)
		{
		case'W':
		case'w':
			PlayPosY--;
			break;
		case'S':
		case's':
			PlayPosY++;
			break;
		case'A':
		case'a':
			PlayPosX--;
			break;
		case'D':
		case'd':
			PlayPosX++;
			break;
		default:
			break;
		}
	}
}

通过按 WASD 键来改变玩家坐标的数值,进而实现飞机的移动。

_getch()这个函数是一个不回显函数,当用户按下某个字符时,
函数自动读取,无需按回车。
_kbhit()这个是用来检测用户是否按下键盘的函数,当有敌机移动时,
没有这个函数画面将会暂停等待你的输入了,显然这不是我们想要的

  • 到这游戏的基本原理想必你应该已经了解差不多了,无非就是下帧刷新上帧,而游戏的各种玩法就是玩家自己通过代码来实现了。。。

2.接下来就是玩家发射子弹了

空格键的ASCII值是 32

还是直接贴代码

	//将BulletX,BulletY初始化为-1,-1 使在屏幕不可见
	//当发射子弹时再执行下列代码
		case 32:
			BulletX = PlayPosX;
			BulletY = PlayPosY - 1;
			isShoot = true;
			break;

发射子弹无非就是在上面移动代码里添加个空格触发事件(也可直接看到下述优化后的子弹代码)

for (int i = 0; i < Heigh; i++)
	{
		for (int j = 0; j < Width; j++)
		{
			if (i == PlayPosY&&j == PlayPosX)  
			{
				cout << "*";
			}
			/
			else if (i == BulletY && j == BulletX)
			{
				cout << "|";
			}
			///
			else
			{
				cout << " ";
			}
		}
		cout << endl;
	}

这是Show()函数,仔细观察多了个上面标注的地方,用于子弹的显示,现在只是将子弹放在玩家前面,而没有发射移动,可以这样实现

void BulletMove()
{	
	if (BulletY  > 0)
	{
		BulletY--;
	}
}

将BulletMove( ) inputWithoutData()函数中,表示与用户输入无关的数据
下面是运行后的画面
在这里插入图片描述

这样玩家的基本功能就实现了,同样你也可以自己添加其他元素,如多发子弹、激光等高级武器



有人要看,我又回来了~

下面是对子弹的优化,上述写的子弹会发现,连续发射子弹的话,上一个子弹会被下一个子弹所“顶替”,这是因为这里用的是一个子弹的坐标,所以我们定义一个数组存储多个子弹坐标 代码如下

//   int BulletX[10], BulletY[10];  这里将子弹改为10个数组!!!

case 32:
			for (int i = 0; i < 10; i++)
			{
				if (BulletY[i] < 0)		//检测哪个子弹没有“发射”
				{				//也即是 y 坐标跑到了屏幕上方

					BulletX[i] = PlayPosX;
					BulletY[i] = PlayPosY-1;
					break;
				}
			}
			break;
	//然后是遍历需要上升的子弹
	for (int i = 0; i < 10; i++)
	{
		if (BulletY[i] >= 0)
			BulletY[i]--;
	}
//Show显示这里就是遍历子弹的显示了			z表示遍历子弹个数
for (int z = 0; z < 10; z++)
	{
		if (i == player.BulletY[z] && j == player.BulletX[z])
		{
			cout << "|";
		}
	}

这样就可以连发了。

接下来是敌人的显示
.敌人的显示和子弹差不多

		//定义敌人位置,建议定义为全局变量便于在各个函数调用
		int EnemyPosX, EnemyPosY;
		//这个也是添加到Show()函数里
		if (i == enemy.EnemyPosY && j == enemy.EnemyPosX)
		{
			cout << "!";
		}

下面是敌人的交互

		bool isEnemyDeath
		//检测与子弹的碰撞
		for (int i = 0; i < 10; i++)
			if (enemy.EnemyPosX == player.BulletX[i]
			&& enemy.EnemyPosY == player.BulletY[i])
			{
				//敌人回到屏幕上方 
				//rand() % Width表示在屏幕上方随机x轴位置出现
				enemy.EnemyPosX = rand() % Width;
				enemy.EnemyPosY =- rand() % 6;
				player.BulletX[i] = -1;	//子弹也 “销毁”
				player.BulletY[i] = -1;
				isEnemyDeath=true;
				break;
			}
		if (!isEnemyDeath)
		{
			//检测与玩家的碰撞
			if (enemy.EnemyPosX == player.PlayPosX 
			&& enemy.EnemyPosY == player.PlayPosY)
			{
				enemy.EnemyPosX = rand() % Width;
				enemy.EnemyPosY =- rand() % 6;
			}
			//这个是当敌人移动没有超出屏幕范围
			else if (enemy.EnemyPosY < Heigh)
			{
				timer = 0;
				//敌人y坐标一直向下移动
				enemy.EnemyPosY++;
			}
			//超出范围
			else
			{
				enemy.EnemyPosX = rand() % Width;
				enemy.EnemyPosY =- rand() % 6;
			}
		}

这个是一直要执行的放在InputWithoutData()中就行了。
这里是一个敌人实现,如果想加入多个敌人的话,也可以用类似子弹的方法用个数组来实现。


到这基本就结束了,这里基本详细给出了这个小游戏制作的基本流程,如果能看懂,对着代码能按自己的实现思路写出来是最好的了。

如有错误和改进,还请不吝指出

2021- 11- 27 再次更新,最近用C语言又重写了一遍, 大概思路和上面一样就不再介绍了,直接上源码

#include "stdio.h"
#include <Windows.h>		// 双缓冲技术 
#include <conio.h>			// console input output 
#include <stdlib.h>
#define amount  4


int Width = 40, Heigh = 10;
int BulletX[amount], BulletY[amount];
int PosX = 7, PosY = 5;
int EnemyX, EnemyY;

int shoot[amount];
int score = 0;

int tem = 0;

void gotoxy(int x, int y)		//  定位输入的坐标位置
{
	COORD c;
	c.X = x;
	c.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
void HideCursor() // 用于隐藏光标
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; // 第二个值为0表示隐藏光标
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void Input()
{
	if (_kbhit())				//  ctrl+ k + d     k+ c 注释   k+ u 解除注释
	{
		char tem = _getch();
		switch (tem)
		{
		case 'W':
		case 'w':
			if (PosY > 1)
			{
				PosY--;
			}
			break;
		case 'S':
		case 's':
			if (PosY < Heigh - 2)
			{
				PosY++;
			}
			break;
		case 'A':
		case 'a':
			if (PosX > 1)
				PosX--;
			break;
		case 'D':
		case 'd':
			if (PosX < Width - 2)
				PosX++;
			break;
		case 32:
			// amount 5  
			for (int i = 0; i < amount; i++)
			{
				if (shoot[i] == 0)
				{
					BulletX[i] = PosX + 1;
					BulletY[i] = PosY;
					shoot[i] = 1;
					break;
				}
			}
			break;
		default:
			break;
		}
	}
}

void Instance()
{
	EnemyX = Width;
	EnemyY = rand() % (Heigh - 2) + 1;
}

void Update()
{
	while (1)		// true,  false
	{
		tem++;
		for (int i = 0; i < amount; i++)
		{
			if (BulletX[i] != -1)				// 子弹的移动
			{
				BulletX[i] += 1;
			}
			if (BulletX[i] >= Width)			// 检测是否超出界面
			{
				BulletX[i] = -1;
				shoot[i] = 0;
			}
			if (EnemyX == BulletX[i] && EnemyY == BulletY[i])
			{
				score++;
				Instance();
			}
			if (BulletX[i] != -1)
			{
				gotoxy(BulletX[i], BulletY[i]);
				printf("0");
			}
		}

		if (tem > 3)
		{
			tem = 0;
			EnemyX--;
		}

		if (EnemyX < 0)
		{
			Instance();
		}

		//  绘制屏幕
		gotoxy(PosX, PosY);
		printf("*");
		gotoxy(EnemyX, EnemyY);
		printf("@");
		// 得分情况
		gotoxy(0, 0);
		printf(" Score is : %d", score);
		Input();
		// 如果还有闪屏的话, 在清屏函数前加个延迟函数
		Sleep(70);			// 延迟函数,   延迟 50ms   可自己调数值
		system("cls");		//清屏函数 
	}
}

int main()
{
	// 初始化子弹
	for (int i = 0; i < amount; i++)
	{
		BulletX[i] = -1;
		BulletY[i] = 0;
		shoot[i] = 0;
	}
	HideCursor();
	Instance();  //	0 -  Heigh-1   1- (heigh-1)
	Update();
	return 0;
}

代码的结构写的不是太好,就懒得改了0.0

  • 13
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值