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;
}