乒乓球世界杯_世界杯结束时间 - 0123838.com
首页中国篮球世界杯正文

C/C++ 趣味编程——别去撞墙(飞行躲避障碍类游戏)

2025-12-01 08:44:39

目录

一、让小球蹦跶起来——键盘输入控制小球

键盘输入—— _getch()函数

数据类型char

键盘输入—— kbhit()函数

二、虽然不想撞南墙但是南墙向我冲过来——“墙体”的制作工艺

1、总之先建墙起来

fillrectangle绘制矩形

2、让墙也动起来吧

3、小球和墙的碰撞判断

三种逻辑运算符:

4、墙体随机一点才有挑战性

rand()生成随机整数

浮点数除法、整数除法、取余运算符控制随机数的范围

类型转换

生成随机墙体

三、让他看起来有模有样——得分的计算与显示

完整代码:

四、好像还有什么问题没解决

一、让小球蹦跶起来——键盘输入控制小球

在操作小游戏的时候,我们首先得让程序收到我们按键信息,首先,让我们的程序接收字符吧。

键盘输入—— _getch()函数

_getch()——其作用是等待用户输入一个字符,当用户按下键盘的任意键之后,程序结束。

数据类型char

char定义字符型数据,printf()函数利用%c格式进行控制字符型常量变量的输出,%d输出整数,%f输出浮点数

#include

#include

#include

int main()

{

while(1)

{

char c;//定义字符型变量

c = _getch();

printf("输入的字符为:%c\n", c);//printf函数用%c控制字符型变量常量的输出

}

return 0;

}

在while循环下,可以重复输入字符

接下来想程序实现,我不按键你就别识别,按键了再分析

键盘输入—— kbhit()函数

kbhit()函数——当有键盘输入时返回1,否则返回0

#include

#include

#include

int main()

{

while(1)

{

if (_kbhit( ))

{

char input = _getch();//定义字符型变量

if (input == ' ')//此处表示空格是单引号

printf("按下了空格键.\n");

else if (input != ' ')

printf("你输入的是:%c\n", input);

}

}

return 0;

ps:在使用函数的时候会发生这种情况

表示你正在使用的函数或特性在 Visual Studio 中已经被标记为弃用(deprecated)。在这种情况下,编译器告诉你 kbhit 这个函数的名字是 POSIX 风格的,现在更推荐使用 ISO C 和 C++ 标准的名字 _kbhit。

要解决这个问题,你需要将代码中的 kbhit 替换为 _kbhit。这样,你的代码就会使用推荐的、与标准更一致的函数。

运行结果如下:

结合上面的准备,加上之前”玩的就是真实“的技巧,我们就可以做出来一个空格控制起跳的小球了

#include

#include

#include

int main()

{

float w, h, g;//窗口宽高、重力加速度

float x, y, vy, r;//小球圆心坐标\初速度和半径

w = 600;

h = 400;

g = 0.6;

initgraph(w, h);//创建一个新窗口

r = 20;

x = w / 4;

y = h - r;

vy = 0;

while(1)

{

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ')

{

vy = -16;//给小球向上初速度

}

}

//老样子,小球运动的规范

vy = vy + g;

y = y + vy;

//重力加速给小球带来的的位置改变

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

}

//如果落地,速度为0

cleardevice();//清空屏幕

fillcircle(x, y, r);//绘制小球

Sleep(10);//暂停十毫秒

}//循环结束

closegraph();

return 0;

return 0;

}

运行结果如图:

二、虽然不想撞南墙但是南墙向我冲过来——“墙体”的制作工艺

1、总之先建墙起来

小球准备完毕,接下来考虑障碍物——墙。

fillrectangle绘制矩形

fillrectangle(left,top,right,bottom)——可以绘制矩形,其中,(left,top)是矩形左上角的坐标,(right,bottom)是矩形右下角坐标

float c_x, c_y, c_w, c_h;//方块坐标和宽高

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

//注意变量们的先后顺序,先出现的才能在后面调用

fillrectangle(c_x, h-c_h, c_x + c_w, h);

带上之前小球起跳的一起:

#include

#include

#include

int main()

{

float w, h, g;//窗口宽高、重力加速度

float x, y, vy, r;//小球圆心坐标\初速度和半径

float c_x, c_y, c_w, c_h;//方块坐标和宽高

w = 600;

h = 400;

g = 0.6;

initgraph(w, h);//创建一个新窗口

r = 20;

x = w / 4;

y = h - r;

vy = 0;

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

//注意变量们的先后顺序,先出现的才能在后面调用

while(1)

{

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ')

{

vy = -16;//给小球向上初速度

}

}

//老样子,小球运动的规范

vy = vy + g;

y = y + vy;

//重力加速给小球带来的的位置改变

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

}

//如果落地,速度为0

cleardevice();//清空屏幕

fillcircle(x, y, r);//绘制小球

fillrectangle(c_x, h-c_h, c_x + c_w, h);//注意他的地方,因为每次执行while会清空屏幕,所以放到while里面

Sleep(10);//暂停十毫秒

}//循环结束

closegraph();

return 0;

return 0;

}

结果如图:

ps:需要注意的

1、对于坐标,窗口的坐标是左上边沿为0,下右边沿为设置的高h和宽w;

2、这里需要注意因为每次while循环让小球起跳时会清除屏幕,所以方块必须放在while循环里,否则屏幕一清就看不到方块在哪儿了; 3、对于 小球坐标的运算,c_x=变量*3/4 与 c_x= 3/4*变量结果不同,后者运行结果如图:

后者c_x运算之后会直接变成0;

因为变量是整数且非零,那么这两个表达式的计算顺序可能会影响结果,因为整数除法会向下取整

2、让墙也动起来吧

虽然视觉上看起来像是小球蹦蹦跳跳去撞墙,但实际上,对于静止的窗口,小球待在那儿没动,实际上是一堵堵墙冲向小球

所以参照赋予小球运动能力的魔法,让墙也动起来

float c_x, c_y, c_w, c_h,c_vx;//方块坐标和宽高和初速度

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

c_vx = -3;

c_x = c_x + c_vx;//方块运动

if (c_x + c_w <= 0)

{

c_x = w;

}//如果运动到最左,重新从最右边出现

fillrectangle(c_x, h-c_h, c_x + c_w, h);

加上去:

#include

#include

#include

int main()

{

float w, h, g;//窗口宽高、重力加速度

float x, y, vy, r;//小球圆心坐标\初速度和半径

float c_x, c_y, c_w, c_h,c_vx;//方块坐标和宽高和初速度

w = 600;

h = 400;

g = 0.6;

initgraph(w, h);//创建一个新窗口

r = 20;

x = w / 4;

y = h - r;

vy = 0;

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

c_vx = -3;

//注意变量们的先后顺序,先出现的才能在后面调用

while(1)

{

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ')

{

vy = -16;//给小球向上初速度

}

}

//老样子,小球运动的规范

vy = vy + g;

y = y + vy;

//重力加速给小球带来的的位置改变

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

}

//如果落地,速度为0

c_x = c_x + c_vx;//方块运动

if (c_x + c_w <= 0)

{

c_x = w;

}//如果运动到最左,重新从最右边出现

cleardevice();//清空屏幕

fillcircle(x, y, r);//绘制小球

fillrectangle(c_x, h-c_h, c_x + c_w, h);//注意他的地方,因为每次执行while会清空屏幕,所以放到while里面

Sleep(10);//暂停十毫秒

}//循环结束

closegraph();

return 0;

return 0;

}

重复让一面墙跑起来,感觉就像有很多面墙一样,看起来还算是像模像样的了,但是很明显,撞墙了没有反馈,我们还需要更多不同高度的墙

3、小球和墙的碰撞判断

在之前的代码中我们成功让小球能够起跳,墙能够移动,但是小球与墙体的碰撞还需要进一步的判断。

小球和墙体的碰撞有三种情况:

1、墙的左边和小球右边碰撞

2、墙的上边和小球下边碰撞

3、墙的右边和小球左边碰撞

三种逻辑运算符:

符合三条逻辑判断的结果即可判断“小球撞上墙了”,而进行逻辑判断需要用到逻辑运算符——运用C语言提供的三种逻辑运算符,实现多种逻辑条件的组合:

!(非)输出相反&&(与)全真为真,有假即假||(或)全假为假,有真即真

现在我们可以实现小球碰撞判断,和撞上去之后我们想要的效果了

if ((c_x <= x + r) && (c_x + c_w >= x - r) && (h - c_h <= y + r))

/*

如果(墙的左边撞上小球右边)

&& (墙的右边装上小球的左边)

&& (墙的上边撞上小球下边 )

ps:因为窗口下边沿为h上边沿为0,所以这里小球下边不是惯性思维的y - r

*/

{

Sleep(1000);//慢动作效果

}

4、墙体随机一点才有挑战性

虽然现在满足了碰撞效果,也有了墙体移动,但是墙体应该随机一点才有挑战性,因此,我们需要让墙体的高度随机起来。

rand()生成随机整数

按下空格时输出一个随机整数:

但是明显这个随机整数的范围很大,我们不能让自己的墙随机的高度有好几个都超过窗口大小 ,所以下一步

浮点数除法、整数除法、取余运算符控制随机数的范围

为了得到设定范围内的随机数,我们需要利用浮点数除法、整数除法、取余运算符

#include

int main()

{

float a=5.0/2;

int a1 = 5.0 / 2;

printf("浮点型接收浮点除法:%f\n", a);

printf("整型接收浮点除法:%d\n", a1);

printf("整型接收浮点除法但是最后我想转回浮点型:%f\n", a1);

/*

编译时,很多编译器会发出警告,指出类型不匹配。

在运行时,由于printf期待一个浮点数(通常是双精度浮点数double),

但它接收到一个整数,所以它会从内存中错误地解释整数后面的位作为浮点数,

这可能导致输出一个随机的、无意义的浮点数。

*/

int b = 5 / 2;

float b1= 5 / 2;

printf("\n");

printf("整型接收整数除法%d\n", b);

printf("浮点型接收整型除法:%f\n", b1);

printf("浮点型接收整型除法但是最后我想转回整型:%d\n", b1);

int c=10%3 ;

printf("\n");

printf("取余运算结果:%d\n", c);

return 0;

}

运行结果:

除号“/”两边数字或变量其中有一个为浮点数时,实行浮点数除法;

除号“/”两边数字或变量均为整型,实行整数除法;

取余号“%”输出左右两整数相除得到的余数;

eg.利用rand()%10可以生成一个0~9的随机数

5 在上述编译时,很多编译器会发出警告,指出类型不匹配。在运行时,由于printf期待一个浮点数(通常是双精度浮点数double),但它接收到一个整数,所以它会从内存中错误地解释整数后面的位作为浮点数,这可能导致输出一个随机的、无意义的浮点数。

这就牵扯到了

类型转换

int a=1.1 ——把浮点数1.1自动转换为整数1,赋值给a;

float b=2——把整数2自动转换成浮点数2.0,赋值给b;这种转换方式称为自动转换。

float(),int()形式称为强制类型转换。

float(6.3/2)等于3,int(6.3)把6.3转换成6

生成随机墙体

现在我们可以开始生产我们随机的墙体了。

if (c_x + c_w <= 0)

{

c_x = w;

c_h = rand() % int(h / 4) + h / 4;//设置随机墙高重新给墙体h赋值,但是不能小于h/4

c_vx = rand() / float(RAND_MAX) * 4 - 7;//设置墙体随机速度

}//如果运动到最左,重新从最右边出现

ps.RAND_MAX存储了rand()函数所能生成的最大整数,rand()/float(RAND_MAX)可以生成0~1的随机小数

三、让他看起来有模有样——得分的计算与显示

现在我们有了墙,也有了蹦跶的小球,该让他显示得分之类的了

ps.为了方便处理越来越多的代码,我们用“工具”——>“文本编辑器”——>“所有语言”——>“显示”里的“行号”来令编辑器中显示代码行号方便阅读理解代码

1、定义整型变量记录得分:

int score=0;//定义得分

/*记得给他初始值,别int score;就结束了,

上面几句时先定义再赋值,实际上还是有初始值的

*/

2、墙成功跑到最左得分+1

if (c_x + c_w <= 0)

{

score += 1;//得分+1

c_x = w;

c_h = rand() % int(h / 4) + h / 4;//重新给墙体h赋值,但是不能小于h/4

c_vx = rand() / float(RAND_MAX) * 4 - 7;//设置墙体随机速度

}//如果运动到最左,重新从最右边出现

3、撞墙得分清零

if ((c_x <= x + r) && (c_x + c_w >= x - r) && (h - c_h <= y + r))

{

score = 0;//得分清零

Sleep(100);//慢动作效果

}

4、利用EasyX的文字输出功能,输出score得分:

TCHAR s[20];//定义字符串数组

_stprintf_s(s, _T("得分:% d"), score);//将score转换为字符串

settextstyle(40, 0, _T("黑体"));//设置文字大小字体

outtextxy(50, 30, s);//输出得分文字

完整代码:

#include

#include

#include

int main()

{

float w, h, g;//窗口宽高、重力加速度

float x, y, vy, r;//小球圆心坐标\初速度和半径

float c_x, c_y, c_w, c_h,c_vx;//方块坐标和宽高和初速度

w = 600;

h = 400;

g = 0.6;

initgraph(w, h);//创建一个新窗口

r = 20;

x = w / 4;

y = h - r;

vy = 0;

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

c_vx = -3;

//注意变量们的先后顺序,先出现的才能在后面调用

int score=0;//定义得分,记得给他初始值,别int score;就结束了

while(1)

{

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ')

{

vy = -16;//给小球向上初速度

}

}

//老样子,小球运动的规范

vy = vy + g;

y = y + vy;

//重力加速给小球带来的的位置改变

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

}

//如果落地,速度为0

c_x = c_x + c_vx;//方块运动

if (c_x + c_w <= 0)

{

score += 1;//得分+1

c_x = w;

c_h = rand() % int(h / 4) + h / 4;//重新给墙体h赋值,但是不能小于h/4

c_vx = rand() / float(RAND_MAX) * 4 - 7;//设置墙体随机速度

}//如果运动到最左,重新从最右边出现

if ((c_x <= x + r) && (c_x + c_w >= x - r) && (h - c_h <= y + r))

/*

如果(墙的左边撞上小球右边)

&& (墙的右边装上小球的左边)

&& (墙的上边撞上小球下边 ) ps:因为窗口下边沿为h上边沿为0,所以这里不是惯性思维的y - r

*/

{

score = 0;

Sleep(100);//慢动作效果

}

cleardevice();//清空屏幕

fillcircle(x, y, r);//绘制小球

fillrectangle(c_x, h-c_h, c_x + c_w, h);//注意他的地方,因为每次执行while会清空屏幕,所以放到while里面

TCHAR s[20];//定义字符串数组

_stprintf_s(s, _T("得分:% d"), score);//将score转换为字符串

settextstyle(40, 0, _T("黑体"));//设置文字大小字体

outtextxy(50, 30, s);//输出得分文字

Sleep(10);//暂停十毫秒

}//循环结束

closegraph();

return 0;

return 0;

}

运行结果如图:

四、好像还有什么问题没解决

在最后的示例里有个问题还没解决——可以一直起跳,如果一直高高地跳在天上,那么就不会撞到墙。所以我们进一步限制小球“只能在地上起跳”

增加“在地面”的判定:

int ballonfloor = 1;//判断小球是否在地面,1在,0不在

按下空格时,只有在地面才能起跳:

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ' && ballonfloor == 1)//如果小球在地面,输入空格

{

vy = -16;//给小球向上初速度

ballonfloor = 0;//小球离开地面

}

}

回到地面 时:

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

ballonfloor = 1;//小球回到地面

}

//如果落地,速度为0,可重起跳

最后完整的全部代码:

#include

#include

#include

int main()

{

float w, h, g;//窗口宽高、重力加速度

float x, y, vy, r;//小球圆心坐标\初速度和半径

float c_x, c_y, c_w, c_h,c_vx;//方块坐标和宽高和初速度

w = 600;

h = 400;

g = 0.6;

initgraph(w, h);//创建一个新窗口

r = 20;

x = w / 4;

y = h - r;

vy = 0;

c_w = 20;

c_h = 100;

c_x = w * 3 / 4;

c_y = h - c_h;

c_vx = -3;

//注意变量们的先后顺序,先出现的才能在后面调用

int score=0;//定义得分,记得给他初始值,别int score;就结束了,上面几句时先定义再赋值,实际上还是有初始值的

int ballonfloor = 1;//判断小球是否在地面,1在,0不在

while(1)

{

if (_kbhit( ))//按键时

{

char input = _getch();// 获得输入字符

if (input == ' ' && ballonfloor == 1)//如果小球在地面,输入空格

{

vy = -16;//给小球向上初速度

ballonfloor = 0;//小球离开地面

}

}

//老样子,小球运动的规范

vy = vy + g;

y = y + vy;

//重力加速给小球带来的的位置改变

if (y >= h - r)

{

vy = 0;

y = h - r;//规范坐标避免落到地面下

ballonfloor = 1;//小球回到地面

}

//如果落地,速度为0,可重起跳

c_x = c_x + c_vx;//方块运动

if (c_x + c_w <= 0)

{

score += 1;//得分+1

c_x = w;

c_h = rand() % int(h / 4) + h / 4;//重新给墙体h赋值,但是不能小于h/4

c_vx = rand() / float(RAND_MAX) * 4 - 7;//设置墙体随机速度

}//如果运动到最左,重新从最右边出现

if ((c_x <= x + r) && (c_x + c_w >= x - r) && (h - c_h <= y + r))

/*

如果(墙的左边撞上小球右边)

&& (墙的右边装上小球的左边)

&& (墙的上边撞上小球下边 ) ps:因为窗口下边沿为h上边沿为0,所以这里不是惯性思维的y - r

*/

{

score = 0;

Sleep(100);//慢动作效果

}

cleardevice();//清空屏幕

fillcircle(x, y, r);//绘制小球

fillrectangle(c_x, h-c_h, c_x + c_w, h);//注意他的地方,因为每次执行while会清空屏幕,所以放到while里面

TCHAR s[20];//定义字符串数组

_stprintf_s(s, _T("得分:% d"), score);//将score转换为字符串

settextstyle(40, 0, _T("黑体"));//设置文字大小字体

outtextxy(50, 30, s);//输出得分文字

Sleep(10);//暂停十毫秒

}//循环结束

closegraph();

return 0;

return 0;

}

运行结果:

2025,如何制定一个高质量的年度规划? 举报处理一般需要几天:2025最新各平台3-7天处理时效
相关内容