【小Game】C++ - EGE - 躲避球小游戏

EGE躲避球小游戏

今晚想搞事情就整了,差不多 睡了睡了~
文章最后面更新了改进版本

  • 更加丝滑
  • 加入鼠标拖动方式
  • 玩法就是WASD控制白色的小球移动,尽量不要碰到别的球。初始有100个彩色小球总中间生成,小球碰撞墙体/边框反弹(在代码中也可以切换成移动到另一侧)。

  • 先放个效果图 我愿称之为作者一败涂地
    在这里插入图片描述在这里插入图片描述

  • EGE图形库的配置见我之前的笔记(这是链接)的最开是的部分

  • 【早期版本】代码在此:(自己玩的,所以有些东东没删干净哈)

/*
	SPASE 清屏+清空撞击+重新计时
	ESC   退出
	WASD  给咱速度
	E     跳过一堆帧
	和别的球相交变红
	碰到墙壁反弹
	命令窗口:(位置) - 速度 [帧数]
	屏幕左上显示:碰撞次数+计时情况
*/

#include<bits/stdc++.h>
#include<windows.h>
#include<graphics.h>

using namespace std;

#define SCR_WIDTH      800 // 窗口宽度
#define SCR_HEIGHT     600 // 窗口高度
#define MAX_BALL       501 // 球数最大值
const float ball_op_val=0.01f; // 加速参数
const float sp_go_down=0.03f;   // 减速参数
const float MAX_SP=4.1f;       // 咱的最大速度

inline void End_of_program(){
	puts("Got to the end.");
	// getch();
	cleardevice();
	// getch();
	closegraph();
	exit(0);
}

struct _Ball {
	float x,y;     // 当前位置
	float dx,dy;   // 每帧速度
	float radius;  // 半径大小
	color_t color; // 颜色
};
_Ball ball[MAX_BALL]; // 创建五百个球
unsigned game_crash=0;
float game_time=0.f;

inline void output_crash(){
	char str[102];
	sprintf(str,"已碰撞 %d 次",game_crash/10);
	// sprintf(str,"crash %d time(s)",game_crash/10);
	outtextxy(10,10,str);
	sprintf(str,"已运行 %.0f 秒",fclock()-game_time);
	// sprintf(str,"passed %d s",(int)fclock());
	outtextxy(10,40,str);
}

inline float ball_dis(_Ball a, _Ball b){ // 俩球心距
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

inline bool ball_cross(_Ball a, _Ball b){ // 判断两球相交
	return ball_dis(a,b)<(a.radius+b.radius);
}

bitset<256>keydown;
int keydown_cnt=0;
inline void player_ctrl(bool _using=true){
	if(!_using)return;
	
	key_msg m_msg;

	bool switch_state_E=false;
	bool switch_state_Q=false;

	thread getting_key([&](){
		while(is_run()){
			m_msg=getkey();
			switch(m_msg.msg){
				case key_msg_down:
					keydown_cnt+=!keydown[m_msg.key];
					keydown[m_msg.key]=1;
					if(m_msg.key=='E'){
						switch_state_E=!switch_state_E;
					}
					if(m_msg.key=='Q'){
						switch_state_Q=!switch_state_Q;
					}
					break;
				case key_msg_up:
					keydown[m_msg.key]=0;
					keydown_cnt--;
					break;
			}
			// printf("%d - %d\n",keydown.size(),m_msg.msg);
		}
	});


	while(is_run()){
		printf("( %5.2f , %5.2f ) - %5.2f %5.2f [ %5.2f ]\r",ball[0].x,ball[0].y,ball[0].dx,ball[0].dy,getfps());
		float aval=(MAX_SP*MAX_SP-ball[0].dx*ball[0].dx-ball[0].dy*ball[0].dy);
		ball[0].dx+=ball_op_val*aval*(keydown['D']-keydown['A']);
		ball[0].dy+=ball_op_val*aval*(keydown['S']-keydown['W']);
		if(fabs(ball[0].dx)>sp_go_down){
			ball[0].dx-=sp_go_down*(ball[0].dx>0?1:-1);
		}
		else{
			ball[0].dx=0.f;
		}
		if(fabs(ball[0].dy)>sp_go_down){
			ball[0].dy-=sp_go_down*(ball[0].dy>0?1:-1);
		}
		else{
			ball[0].dy=0.f;
		}

		if(keydown_cnt>0){
			// keystate('X') // 0/1

			// if(keydown['R']){
			// 	// operation
			// }
			if(keystate(VK_SPACE)){
				cleardevice();
				game_crash=0;
				game_time=fclock();
			}
			if(keystate(VK_ESCAPE)){
				End_of_program();
			}
			if(switch_state_E){
				// E open
			}
			if(switch_state_Q){
				// Q open
			}
		}
		api_sleep(10);
	}
	getting_key.join();
}

int main(){
	// setinitmode(INIT_NOBORDER, 100, 100);
	initgraph(SCR_WIDTH, SCR_HEIGHT, INIT_RENDERMANUAL | INIT_NOFORCEEXIT);
	setcaption("Title here ~");
	thread player_ctrl_thd(player_ctrl,1);

	
	float dir = 0.0f + 1; // 初始化方向常数
	float sp = 0.5f; // 初始化速度常数

	for(int i = 0; i < MAX_BALL; ++i){
		// 初始化球位置居屏幕正中心
		ball[i].x = SCR_WIDTH / 2;
		ball[i].y = SCR_HEIGHT / 2;
		// 生成随机数
		randomize();
		// 迭代初始化速度常数 +0.01
		sp += 0.01f;
		// 分配速度到初始化方向上
		ball[i].dx = sp * cosf(dir);
		ball[i].dy = sp * sinf(dir);
		// 随机生成大小
		ball[i].radius = randomf() * 5 + 2;
		ball[i].color = random(0xff0000) + 0xffff;
		// 迭代初始化方向常数,+0.1 rad
		dir += 0.1f;
	}
	ball[0].radius = 10;
	ball[0].x = 100;
	ball[0].y = 100;
	ball[0].color = 0xffffff;

	int n = 100; // 球的个数
	double t_rec = fclock(); // 记录当前窗口运行时间

	
	for(;is_run();delay_fps(90)){

		for(int _skip=keydown['E']*100+1;_skip;_skip--){

			if(keydown['E']||fclock()-t_rec>1.0){
				t_rec=fclock();
				n++;
				n%=500;
			}

			// cleardevice(); // 清屏
			if(!keydown['E']){
				imagefilter_blurring(NULL,0x7f,0x99,0,0,0,0);
			}
			ball[0].color=0xffffff; // 默认球为白色
			for(int i = n-1; i >= 0; i--) { // 遍历当前球数个球
				// 画球
				if(!keydown['E']){
					setfillcolor(ball[i].color); // 设置填充颜色
					setcolor(ball[i].color); // 设置边框颜色
					fillellipse(ball[i].x,ball[i].y,ball[i].radius,ball[i].radius);
				}
				// 移动球
				ball[i].x += ball[i].dx;
				ball[i].y += ball[i].dy;
				if(ball[i].x < 0.0f || ball[i].x > SCR_WIDTH){ // 在左右边界外
					// if(randomf()>0.5){
					   ball[i].dx = -ball[i].dx; // 反弹
					// }
					// else{
						// ball[i].x=SCR_WIDTH-ball[i].x; // 到另一侧
					// }
				}
				if(ball[i].y < 0.0f || ball[i].y > SCR_HEIGHT){ // 在上下边界外
					// if(randomf()>0.5){
						ball[i].dy = -ball[i].dy; //反弹
					// }
					// else{
						// ball[i].y=SCR_HEIGHT-ball[i].y; // 到另一侧
					// }
				}
				if(i!=0&&ball_cross(ball[i],ball[0])){ // 有球相交
					ball[0].color=0xff0000; // 咱变红
					game_crash++;
				}
			}
			output_crash();

		}
	}

	player_ctrl_thd.join();
	return 0;
}
  • 稍微改了一下:(画面流畅+鼠标拖动)
/*
	SPACE 清屏+清空撞击+重新计时
	ESC   退出
	WASD  给咱速度
	E     跳过一堆帧
	和别的球相交变红
	碰到墙壁反弹
	命令窗口:(位置) - 速度 [帧数]
	屏幕左上显示:碰撞次数+计时情况
	鼠标左键:拖动小球
*/

#include<bits/stdc++.h>
#include<windows.h>
#include<graphics.h>

using namespace std;

#define SCR_WIDTH      800     // 窗口宽度
#define SCR_HEIGHT     600     // 窗口高度
#define MAX_BALL       501     // 球数最大值
const float ball_op_val=0.01f; // 加速参数
const float sp_go_down=0.07f;  // 减速参数
const float MAX_SP=5.2f;       // 咱的最大速度

inline void MySleep(unsigned dms) {
	unsigned rec_time=clock();
	while(clock()-rec_time<dms);
	return ;
}

inline void End_of_program() {
	puts("Got to the end.");
	// getch();
	cleardevice();
	// getch();
	closegraph();
	exit(0);
}

struct _Ball {
	float x,y;       // 当前位置
	float dx,dy;     // 每帧速度
	float radius;    // 半径大小
	color_t color;   // 颜色
};
_Ball ball[MAX_BALL]; // 创建五百个球
unsigned game_crash=0;
float game_time=0.f;

inline void output_crash() {
	char str[102];
	sprintf(str,"已碰撞 %d 次",game_crash/10);
	// sprintf(str,"crash %d time(s)",game_crash/10);
	outtextxy(10,10,str);
	sprintf(str,"已运行 %.0f 秒",fclock()-game_time);
	// sprintf(str,"passed %d s",(int)fclock());
	outtextxy(10,40,str);
}

inline float ball_dis(_Ball a, _Ball b) { // 俩球心距
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

inline bool ball_cross(_Ball a, _Ball b) { // 判断两球相交
	return ball_dis(a,b)<(a.radius+b.radius);
}

inline void init_game() {
	game_crash=0;
	game_time=fclock();

	float dir = 0.0f + 1; // 初始化方向常数
	float sp = 0.5f; // 初始化速度常数

	for(int i = 0; i < MAX_BALL; ++i) {
		// 初始化球位置居屏幕正中心
		ball[i].x = SCR_WIDTH / 2;
		ball[i].y = SCR_HEIGHT / 2;
		// 生成随机数
		randomize();
		// 迭代初始化速度常数 +0.01
		sp += 0.01f;
		// 分配速度到初始化方向上
		ball[i].dx = sp * cosf(dir);
		ball[i].dy = sp * sinf(dir);
		// 随机生成大小
		ball[i].radius = randomf() * 5 + 2;
		ball[i].color = random(0xff0000) + 0xffff;
		// // 迭代初始化方向常数,+0.1 rad
		// dir += 0.1f;
		dir = randomf()*3.15;
	}
	ball[0].radius = 10;
	ball[0].x = 100;
	ball[0].y = 100;
	ball[0].color = 0xffffff;
	return ;
}

bitset<256>keydown;
int keydown_cnt=0;
inline void player_ctrl(bool _using=true) {
	if(!_using)return;
	
	key_msg m_msg;
	mouse_msg m_mmsg;

	bool switch_state_E=false;
	bool switch_state_Q=false;
	bool switch_mouse_left=false;
	bool switch_mouse_right=false;
	bool switch_mouse_middle=false;

	thread getting_key([&]() {
		while(is_run()) {
			m_msg=getkey();
			switch(m_msg.msg) {
				case key_msg_down:
					keydown_cnt+=!keydown[m_msg.key];
					keydown[m_msg.key]=1;
					if(m_msg.key=='E') {
						switch_state_E=!switch_state_E;
					}
					if(m_msg.key=='Q') {
						switch_state_Q=!switch_state_Q;
					}
					break;
				case key_msg_up:
					keydown[m_msg.key]=0;
					keydown_cnt--;
					break;
			}
			// printf("%d - %d\n",keydown.size(),m_msg.msg);
		}
	});


	thread getting_mouse([&]() {
		while(is_run()) {
			// putchar(0);
			m_mmsg=getmouse();
			// printf("%d %d %d %d %d\n", m_mmsg.msg, m_mmsg.x, m_mmsg.y, m_mmsg.flags, m_mmsg.wheel);
			// printf("\t\t\t\t%d %d %d %d %d %d %d\n",m_mmsg.is_move(),m_mmsg.is_down(),m_mmsg.is_up(),m_mmsg.is_left(),m_mmsg.is_mid(),m_mmsg.is_right(),m_mmsg.is_wheel());
			// printf("%d\n",switch_mouse_left);
			switch(m_mmsg.msg) {
				case 16:
					switch(m_mmsg.flags) {
						case 1:
							switch_mouse_left=true;
							break;
						case 2:
							switch_mouse_right=true;
							break;
						case 4:
							switch_mouse_middle=true;
							break;
					}
					break;
				case 32:
					switch(m_mmsg.flags) {
						case 1:
							switch_mouse_left=false;
							break;
						case 2:
							switch_mouse_right=false;
							break;
						case 4:
							switch_mouse_middle=false;
							break;
					}
					break;
			}
		}
	});


	while(is_run()) {
		// printf("( %5.2f , %5.2f ) - %5.2f %5.2f [ %5.2f ]\r",ball[0].x,ball[0].y,ball[0].dx,ball[0].dy,getfps());
		
		// float aval=max(MAX_SP-fabs(ball[0].dx+ball[0].dy),0.07f);aval*=aval;
		float aval=(MAX_SP*MAX_SP-ball[0].dx*ball[0].dx-ball[0].dy*ball[0].dy);
		int ddx=keydown['D']-keydown['A'],ddy=keydown['S']-keydown['W'];
		ball[0].dx+=ball_op_val*aval*(ddx);
		ball[0].dy+=ball_op_val*aval*(ddy);

		 if(switch_mouse_left) {
			ball[0].x=m_mmsg.x;
			ball[0].y=m_mmsg.y;
		 }

		if(fabs(ball[0].dx)>sp_go_down) {
			ball[0].dx-=sp_go_down*(ball[0].dx>0?1:-1);
		}
		else{
			ball[0].dx=0.f;
		}
		if(fabs(ball[0].dy)>sp_go_down) {
			ball[0].dy-=sp_go_down*(ball[0].dy>0?1:-1);
		}
		else{
			ball[0].dy=0.f;
		}

		if(keydown_cnt>0) {
			// keystate('X') // 0/1

			// if(keydown['R']) {
			// 	// operation
			// }
			if(keystate(VK_SPACE)) {
				cleardevice();
				init_game();
			}
			if(keystate(VK_ESCAPE)) {
				End_of_program();
			}
			if(switch_state_E) {
				// E open
			}
			if(switch_state_Q) {
				// Q open
			}
		}
		MySleep(10);
	}
	getting_key.join();
}

int n = 0; // 球的个数
inline void draw() {
	int cls_cnt=0x7fffffff;
	for(;is_run();delay_ms(10)) {
		cleardevice();
		// if(!keydown['E']&&cls_cnt>1) {
		// 	cls_cnt=0;
		// 	// 清屏
		// 	cleardevice();
		// 	// imagefilter_blurring(NULL,0x7f,0x99,0,0,0,0);
		// }
		// else{
		// 	cls_cnt++;
		// }

		for(int i = n-1; i >= 0; i--) { // 遍历当前球数个球
			// 画球
			if(!keydown['E']) {
				setfillcolor(ball[i].color); // 设置填充颜色
				setcolor(ball[i].color); // 设置边框颜色
				fillellipse(ball[i].x,ball[i].y,ball[i].radius,ball[i].radius);
			}
		}
		output_crash();
	}
	return ;
}

double t_rec=0; // 记录当前窗口运行时间
inline void refresh() {

	for(;is_run();MySleep(10)) {

		for(int _skip=keydown['E']*100+1;_skip;_skip--) {

			if(keydown['E']||fclock()-t_rec>1.0) {
				t_rec=fclock();
				n++;
				n%=500;
			}

			ball[0].color=0xffffff; // 默认球为白色
			for(int i = n-1; i >= 0; i--) { // 遍历当前球数个球
				// 移动球
				ball[i].x += ball[i].dx;
				ball[i].y += ball[i].dy;
				if(ball[i].x < ball[i].radius ) { // 在左边界外
					ball[i].dx = fabs(ball[i].dx)*(i?1.f:1.1f);
					ball[i].x=ball[i].radius;
				}
				if(ball[i].x > SCR_WIDTH-ball[i].radius) { // 在右边界外
					ball[i].dx = fabs(ball[i].dx)*(i?-1.f:-1.1f);
					ball[i].x=SCR_WIDTH-ball[i].radius;
				}
				if(ball[i].y < ball[i].radius ) { // 在上边界外
					ball[i].dy = fabs(ball[i].dy)*(i?1.f:1.1f);
					ball[i].y = ball[i].radius;
				}
				if(ball[i].y > SCR_HEIGHT-ball[i].radius) { // 在下边界外
					ball[i].dy = fabs(ball[i].dy)*(i?-1.f:-1.1f);
					ball[i].y = SCR_HEIGHT-ball[i].radius;
				}
				if(i!=0&&ball_cross(ball[i],ball[0])) { // 有球相交
					ball[0].color=0xff0000; // 咱变红
					game_crash++;
				}
			}

		}
	}
	return ;
}

int main() {
	// setinitmode(INIT_NOBORDER, 100, 100);
	initgraph(SCR_WIDTH, SCR_HEIGHT, INIT_RENDERMANUAL | INIT_NOFORCEEXIT);
	setcaption("Title here ~");
	thread player_ctrl_thd(player_ctrl,1);

	
	init_game();


	thread draw_thd(draw);
	// draw_thd.detach();
	thread refresh_thd(refresh);
	// refresh_thd.detach();

	

	player_ctrl_thd.join();
	draw_thd.join();
	refresh_thd.join();
	return 0;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值