目录

前言

制作可以自由移动并且发射子弹的飞机

介绍第一种清屏函数system("cls")

介绍kbhit函数

介绍方便的getch()函数

添加可以自己移动、击落后会重生的障碍物

标识符的命名

介绍rand函数

加上计分板,优化频闪问题

介绍gotoxy函数

 介绍HideCursor函数

完整代码


前言

声明:本游戏参考《c语言课程设计与游戏开发实践教程》。

首先放一个小游戏视频效果(右边界有点凌乱,影响美观,但不影响效果,多多见谅😋)

game飞机2.0版

如何?这个单单用字符来完成的简略版小游戏,很适合c语言的新手锻炼实践能力(理论即可)。这个2.0版的飞机小游戏实际上是在我上次发的1.0版基础上优化的(http://t.csdn/O1jRV)相比之下,2.0版不再有画面和光标的频闪问题,发射方式从激光变成子弹,障碍物可移动并重现,有计分功能。

  • 本游戏必备知识点:printf输出,for语句,if语句,while循环,函数的自定义和引用,自增自减运算符。
  • 本游戏会介绍的知识点:标识符的命名,两种清屏函数,rand函数,方便的getch函数,kbhit函数,隐藏光标函数。(如果不知道这些小知识点并不影响,看了介绍和应用很基本就可以理解)。

制作可以自由移动并且发射子弹的飞机

介绍第一种清屏函数system("cls")

  • 该函数位于stdlib.h函数库,头文件要机上#include <stdlib.h>。
  • 作用:该函数可以在循环中清空上一次的画面,在这里实现飞机的自由移动(要不然飞机移动就跟重影一样,跟李白技能一样)
  • 使用:system("cls");

介绍kbhit函数

  • 这个函数在conio.h函数库中,头文件要加上#include <conio.h>。
  • 我们在这里是这样使用:if(kbhi())  {输入...运行...}
  • 作用:该函数可以判断是否有输入,并且防止程序运行堵塞。一般情况下,如果有输入函数出现,程序会停下来等待输入,这时候程序就堵塞住了。kbhit的作用就是不让程序这时候发生堵塞。如果有输入,那么if内相应程序会运行;如果没有输入,if外程序仍然可以运行。

介绍方便的getch()函数

  • 该函数位于conio.h函数库中,头文件要加上#include <conio.h>。
  • 作用:getch()函数只接受单字符。原本的scanf会在输入之后按下回车键才能继续运行,但是getch()函数接受单个字符之后不需要按回车键就会结束输入,继续运行。
  • 使用:a=grtch();

 直接上代码,代🐎中有详细的注释解析哦

#include <stdio.h>
#include <stdlib.h>    //system函数库 
#include <conio.h>     //getch函数库 ,kbhit函数库
//飞机可移动,有子弹 
         

//定义几个全局变量,方便所有函数使用
int x,y;               //飞机坐标
int high,width;        //画面宽度 
int billx,billy;       //子弹坐标


void start()           //第一个自定义函数,作用是使数据初始化 
{  //一个不冷不热的知识:全局变量不能在函数外赋值,能在任意函数中赋值 
	high=20;
	width=30;
	x=width/2;
	y=high/2;
	billx=x;
	billy=0;
}


void show()            //第二个函数,显示飞机和边界
{
	int i,n;
	system("cls");//这个清屏函数其实放很多地方都行 ,只要是在死循环里 
	
	for(i=0;i<high;i++)  //外层循环,用于输出回车和左右边界
	{
		printf("#");     //用于输出左侧边界
		for(n=0;n<width;n++)     //内层循环,用于输出空格、飞机、上下边界
		{if((i==y)&&(n==x))
        printf("  +");//&&两侧运算式最好都加()  
		else {
			if((i==0)||(i==19))
		    printf("#");         //划定上下边界 
		    else 
		        if((i==billy)&&(n==billx))
		        printf("   |");     //输出子弹。前面加三个空格,因为要和飞机头照齐
                else
					if((i==y+1)&&(n==x))
			        printf("+---+");
				    else
					    if((i==y+2)&&(n==x))
					    printf(" * *"); 
					    else
					    printf(" ");//没错就是套娃,这个过程是在输出整个飞机体
		}
		}
	printf("#");                 //输出右方边界
//如果飞机移动时超出界限就会消失。但飞机仅仅是看不见了,实际上还存在 
	printf("\n");
	}
	 
	
}

void unput()                    //第三个自定义函数,用于控制子弹
{
	if(billy>-1)
	billy--;                    //目的是让子弹一直往上飞 
}

void put()                      //第四个函数,输入字符控制飞机移动、放出子弹
{
	char move;
	if(kbhit())
	{
		move=getch();
		if(move=='a')x--;
		if(move=='d')x++;
		if(move=='w')y--;
		if(move=='s')y++;
		if(move==' '){
			billx=x-1;
//因为边界占一个字节位置,如果不-1会让子弹和飞机错开一个位置 
			billy=y-1;            //因为要让子弹在飞机上一行输出 
		}
	}
}

int main()
{
	start();  //第一个函数
	while(1)  //1代表正确,0代表非,所以while(1)一直满足条件,无限循环
	{
		//	system("cls");清屏函数加这也行 
		 show();    //第二个函数
		 unput();   //第三个函数
		 put();     //第四个函数
//再次引用函数的时候不需要加数据类型 
	}
	return 0;
 } 

添加可以自己移动、击落后会重生的障碍物

标识符的命名

标识符一般包括变量名、常量名、函数名...

  1. 标识符中可以有大小写字母、数字、下划线-、$。不可以有汉字和其他符号。
  2. 标识符不能以数字开头。
  3. 标识符中区分大小写。

介绍rand函数

  • 属于stdlib.h函数库,头文件要加上#include<stdlib.h>。
  • 作用:使一个东西在一定范围内随机出现。在这里就是让障碍物小时候再重现
  • 使用方式:a=rand()%rage;

(a是一个随机变量,在这里表示障碍物横坐标;rage是横坐标可以出现的宽度范围。在代码的运用中可以帮助你更好地理解作用)

来,上代码!(代码中每一步有详解)

#include <stdio.h>
#include <stdlib.h>//system函数库 
#include <conio.h>//getch函数库 
#include <windows.h>//void gotoxy(int x,int y)和HideCursor()函数库 

 
int x,y;                 //飞机的位置
int high,width;         //画面宽度
int billx,billy;       //子弹
int enermy_x,enermy_y;//敌机 。
int score;
//定义全局变量


void start() //第一个自定义函数,作用是使数据初始化
{	//一个不冷不热的知识:全局变量不能再函数外赋值,能在任意函数中赋值
	high=20;
	width=30;
	x=width/2;   
	y=high/2;
	billx=x;
	billy=0;
	enermy_x=x+5;
	enermy_y=2;
	score=0;
}

void show()//第二个函数,显示飞机
{
	int i,n;
	
	system("cls");//这个清屏函数其实加很多地方都行 ,只要是在死循环里
 
	for(i=0; i<(high); i++)
	{
		printf("#");
		for(n=0; n<width; n++)
		{	if((i==y)&&(n==x))
            printf("  +");//&&两侧运算式最好都加()。为了和身体对称,前面加空格
			else {
				if((i==0)||(i==19))
				printf("#");              //划定上下界限
				else 
					if((i==billy)&&(n==billx))
					printf("  |");
					else 
					    if((i==enermy_y)&&(n==enermy_x))
						printf("*");       //输出障碍物,障碍物长啥样都可以
					    else 
						    if((i==y+1)&&(n==x))
			                printf("+---+");
				            else
				          	    if((i==y+2)&&(n==x))
					            printf(" * *"); 
					            else
					            printf(" ");  
							  //没错这就是套娃 
			}
		}
		printf("#");
//划定左右界限,如果飞机移动时超出界限会消失,飞机仅仅是看不见,实际上还存在。
		printf("\n");
	}

}

void unput()      //第三个函数,控制子弹飞行、控制障碍物掉落和消失重现
{
	if(billy>-1)
		billy--;//目的是让子弹一直往上飞
		
		if((billx==enermy_x)&&(billy==enermy_y))
	{
		score++;
		enermy_y=0;//让障碍物从顶上掉下来 
		enermy_x=rand()%width;//意思就是在该宽度范围内随机出现 
		billx=-2;
//子弹横坐标为负,子弹就不再出现在画面内。产生了使子弹被击中后消失的效果
    }
		
	static int speed=0;  //static使得该变量作用域仅仅在当前函数内 

	if(speed==20){
		enermy_y++;
		speed=0;
	} 
	else speed++;
	//让敌机每循环20次下落一次,要不然掉的太快打不中
	//这里两种表示方法都生效 
}

void put()   //第四个函数,通过输入端控制飞机移动并发射子弹
{
	char move;
	if(kbhit())
	{
		move=getch();
		if(move=='a')x--;
		if(move=='d')x++;
		if(move=='w')y--;
		if(move=='s')y++;
		if(move==' ') {
			billx=x;
			billy=y-1;//因为要让子弹在飞机上方输出
		}
	}
}


int main()
{
	start();
	while(1)
	{
		//	system("cls");加这也行
		show();
		unput();//再次引用函数的时候不要加数据类型
		put();
        
	}
	return 0;
}

加上计分板,优化频闪问题

该游戏已经基本制作完成。这时候你会发现画面闪烁很厉害,而且光标的频闪也很影响美观。因此,这一步我们加上两个函数,分别优化画面频闪和光标频闪问题。同时加上计分板,统计击中障碍物个数。

介绍gotoxy函数

这个函数代替了上一个清屏函数system函数,解决画面频闪问题。不用管任何别的东西,直接输入下面的函数内容。

void gotoxy(int x,int y)
{
    HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(handle,pos);
}

 介绍HideCursor函数

该函数作用是隐藏光标,解决光标频闪问题。使用方法如下(直接用)

void HideCursor()
{
    CONSOLE_CURSOR_INFO cursor_info={1,0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

 加上这最后两个函数,游戏画面就会变得更加清晰稳定啦!最后给大家放上完整代码👇🏻

完整代码

#include <stdio.h>
#include <stdlib.h>//system函数库 
#include <conio.h>//getch函数库 
#include <windows.h>//void gotoxy(int x,int y)和HideCursor()函数库 
//发挥 
 
int x,y;//飞机的位置
int high,width;//画面宽度
int billx,billy; //子弹
int enermy_x,enermy_y;//敌机 。知识点标识符的用法
int score;
//定义全局变量

void gotoxy(int x,int y)    //清屏
{
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X=x;
	pos.Y=y;
	SetConsoleCursorPosition(handle,pos);
}


void start() //第一个自定义函数,作用是使数据初始化
{	//一个不冷不热的知识:全局变量不能再函数外赋值,能在任意函数中赋值
	high=20;
	width=30;
	x=width/2;
	y=high/2;
	billx=x;
	billy=0;
	enermy_x=x+5;
	enermy_y=2;
	score=0;
}

void show()//第二个函数,显示飞机
{
	int i,n;
	gotoxy(0,0);        //将清屏函数引用进来
	//system("cls");//这个清屏函数其实加很多地方都行 ,只要是在死循环里
 
	for(i=0; i<(high); i++)
	{
		printf("#");
		for(n=0; n<width; n++)
		{	if((i==y)&&(n==x))
		printf("  +");
			else {
				if((i==0)||(i==19))
				printf("#");//划定上下界限
				else 
					if((i==billy)&&(n==billx))
					printf("|");
					else 
					    if((i==enermy_y)&&(n==enermy_x))
						printf("*");
					    else 
					        if((i==y+1)&&(n==x))
					        printf("+---+");
					        else
					            if((i==y+2)&&(n==x))
					            printf(" * *"); 
					            else
						        printf(" ");//没错就是套娃 
			}
		}
		printf("#");//划定左右界限,如果飞机移动时超出界限就会消失,划定界限会提醒你自己,不然飞机怎么没了都不知道 。飞机仅仅是不见了,但是还存在
		printf("\n");
	}
	
	printf("Your's score is%d",score);   //在画面最后部分输出计分板


}

void unput()//第三个函数
{
	static int speed=0;//作用域仅仅在当前函数 
	 int replace=20;//确实有调节素的的作用,不过超过一定数字之后就不会再次显示了 
	if(billy>-1)
		billy--;//目的是让子弹一直往上飞
		
		if((billx==enermy_x)&&(billy==enermy_y))
	{
		score++;
		enermy_y=0;//让障碍物从顶上掉下来 
		enermy_x=rand()%(width);//意思就是在宽度范围内的最上方可以随机出现 
		billx=-2;//让子弹击中障碍物之后消失 
        replace--; 
}
	
//	if(speed!=10)speed++;
	if(speed==replace){
		enermy_y++;
		speed=0;
	} 
	else speed++;
	//让敌机每循环十次下落一次
	//这里两种表示方法都生效 
}

void put()//第四个函数,控制移动
{
	char move;
	if(kbhit())
	{
		move=getch();
		if(move=='a')x--;
		if(move=='d')x++;
		if(move=='w')y--;
		if(move=='s')y++;
		if(move==' ') {
			billx=x+2;
			billy=y-1;//因为要让子弹在飞机上方输出
		}
	}
}

void HideCursor()     //隐藏光标函数
{
	CONSOLE_CURSOR_INFO cursor_info={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}

int main()
{
	
	start();
	while(1)
	{
		
		show();
		unput();//再次引用函数的时候不要加数据类型
		put();
        HideCursor();  //引用隐藏光标函数
        
      
	}
	return 0;
}

 最后有2个小思考题:1.如何使用esc键暂停游戏?   2.如何使分数越高障碍物下落速度越快?

这两个问题目前我也没有解决,如果你们解决了请务必教教我🙏🏻

如果用不懂得地方可以随时评论或者私信我哦

就酱,拜拜~

更多推荐

c语言入门级小游戏·飞机(2.0版)| 激发你的编程兴趣(100~150行代码)