当前位置: 首页 > news >正文

[C/C++学习] 6.弹跳小球(B)

参考文献: 童晶. C和C++游戏趣味编程[M].人民邮电出版社.2021.

上节课的程序:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 2;//重力加速度设置为2initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆while( 1 ){y = y +vy;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆Sleep(100);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = -vy ; }}getch();closegraph();return 0;
}

一.实现无反弹的小球

检测小球位置,当小球到达窗口下边界时,强制将y轴速度设置为0;

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 2;//重力加速度设置为2initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆while( 1 ){y = y +vy;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆Sleep(10);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }}getch();closegraph();return 0;
}

二.键盘按键控制小球弹跳

当有键盘按键按下时,kbhit( )返回1,否则返回0;

1.1 使用kbhit( )检测按键 实现小球弹跳

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆while( 1 ){        if( kbhit() ){ /* 检测按键 */getch(); /* 等待输入按键 */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}y = y +vy;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

思考:如何设置弹跳按键为固定的某个按键呢?

1.2 字符与编码

使用<conio.h>的函数kbhit( )检测键盘按键输入;
每个键盘按钮输入的字符不同;
通过getch( )函数读取缓冲区字符。

示例

#include <conio.h>
#include <stdio.h>
int main(){char n = 0;while(1){if( kbhit( ) == 1 ){//判断按键是否按下n = getch( );//获取缓冲区输入的按键 存储到n中printf("The Key is %c\n",n);//以字符格式打印nprintf("The Key is %d\n",n);//以整数格式打印n}}return 0;
}

按下键盘上的a按键时,输出结果:
在这里插入图片描述
上述程序中,变量n是一个字符型变量( char )。
字符型变量也属于整数类型变量,由于char类型变量只占用1个字节的存储空间,它所能存储的数据范围比int小得多( 64位系统中 int 为 4 字节),只能表示 -128~127 范围的数值。

在计算机中,字符是通过特定的编码表示的。

英文字符的编码中使用较多的属于ASCII码,它们的对应关系如下:

https://c.biancheng.net/c/ascii/

可以看到,a对应的acsii码为97,这正好与上述程序中用%d(整数)格式输出变量n的值对应。
在这里插入图片描述

编码数值与字符的等效

示例1:赋值整数 输出字符 则字符是整数对应的ACSII编码的字符
我们可以将上述ACSII码表中的值拿来使用,例如表示字符’b’,对应的ACSII编码值为98;
建立一个char(字符型)变量x,给其初值98,然后用字符型格式(%c)打印x

#include <stdio.h>
int main(){char x = 98;printf("%c\n", x);//以字符格式输出xreturn 0;
}

输出结果为: b

示例2:赋值字符 输出字符
给变量x赋值字符b ;
注: 字符常量使用单引号 ’ ’ 表示。

#include <stdio.h>
int main(){char x = 'b';printf("%c\n", x);//以字符格式输出xreturn 0;
}

输出结果为: b

示例3: 赋值字符 输出整数 整数是对应ACSII编码表字符的整数
给变量x赋值字符b ;

#include <stdio.h>
int main(){char x = 'b';printf("%d\n", x);//以整数格式输出xreturn 0;
}

输出结果为: 98

示例4: 赋值整数 输出整数 - char变量也可以作为整数型变量使用
给变量x赋值字符b ;
注: 字符常量使用单引号 ’ ’ 表示。

#include <stdio.h>
int main(){char x = 98;printf("%d\n", x);//以字符格式输出xreturn 0;
}

输出结果为: 98

1.3 使用键盘按键w控制小球弹跳

使用if条件语句检查getch( )的值,如果是字符’w’,则控制小球弹跳。

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆char input;while( 1 ){        if( kbhit() ){ /* 检测按键 */input = getch(); /* 等待输入按键 */if( input = 'w' ){/* 如果输入字符为w */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}}y = y +vy;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

三. 生成移动的方块

使用easyx库函数fillrectangle生成方块。
fillrectangle( )函数的输入参数如下:

fillrectangle(<矩形左上角的点的X坐标>,<矩形左上角点的Y坐标>,
矩形右下角点的X坐标,矩形右下角点的Y坐标  )

3.1 在窗口右下角绘制方块

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸int Rectangle_W = 20,Rectangle_H = 30;/* 矩形宽度、高度 */float Rectangle_X=Width-Rectangle_W;float Rectangle_Y = High - Rectangle_H; /* 矩形的x、y坐标设定为矩形左上角的坐标 */float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆char input;while( 1 ){        if( kbhit() ){ /* 检测按键 */input = getch(); /* 等待输入按键 */if( input = 'w' ){/* 如果输入字符为w */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}}y = y +vy;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆fillrectangle(Rectangle_X            , Rectangle_Y,Rectangle_X+Rectangle_W, Rectangle_Y+Rectangle_H);/* 绘制矩形: */Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

3.2 移动的方块

设定矩形的速度 float RVx = -10 ;
并在每次循环时更新矩形的x位置;

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸int Rectangle_W = 20,Rectangle_H = 30;/* 矩形宽度、高度 */float Rectangle_X=Width-Rectangle_W;float Rectangle_Y = High - Rectangle_H; /* 矩形的x、y坐标设定为矩形左上角的坐标 */float RVx = -10; /*矩形速度*/float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆char input;while( 1 ){        if( kbhit() ){ /* 检测按键 */input = getch(); /* 等待输入按键 */if( input = 'w' ){/* 如果输入字符为w */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}}y = y +vy;Rectangle_X = Rectangle_X + RVx;cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆fillrectangle(Rectangle_X            , Rectangle_Y,Rectangle_X+Rectangle_W, Rectangle_Y+Rectangle_H);/* 绘制矩形: */Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

3.3 重置方块位置

当方块的x坐标到达窗口最左侧时(即小于0),重置方块位置到窗口最右侧。

if( Rectangle_X < 0 ){ Rectangle_X = Width;}

完整代码:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸int Rectangle_W = 20,Rectangle_H = 30;/* 矩形宽度、高度 */float Rectangle_X=Width-Rectangle_W;float Rectangle_Y = High - Rectangle_H; /* 矩形的x、y坐标设定为矩形左上角的坐标 */float RVx = -10; /*矩形速度*/float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆char input;while( 1 ){        if( kbhit() ){ /* 检测按键 */input = getch(); /* 等待输入按键 */if( input = 'w' ){/* 如果输入字符为w */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}}y = y +vy;Rectangle_X = Rectangle_X + RVx;if( Rectangle_X < 0 ){ Rectangle_X = Width;}cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆fillrectangle(Rectangle_X            , Rectangle_Y,Rectangle_X+Rectangle_W, Rectangle_Y+Rectangle_H);/* 绘制矩形: */Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

四.碰撞检测

碰撞检测本质是判断小球与方块的区域是否存在重叠。

在这里插入图片描述

什么情况下小球与方块位置发生重叠呢?
我们先来关注一下什么时候不重叠:(注意y轴正方向朝下)
此处用(x,y)表示小球中心点坐标,用(Rx,Ry)表示矩形左上角的点的坐标;
r表示小球半径;RW、RH分别表示矩形宽度、高度

4.1 不重叠的情况

(1)小球的右边界<方块的左边界 这时不相交

在这里插入图片描述

 (x+r)<(Rx)

(2)小球左边界>矩形右边界时 不相交

在这里插入图片描述

(x-r)>(Rx+RW)

(3)小球下边界>矩形上边界时 不相交

在这里插入图片描述

(y+r)<(Ry)

(4)小球上边界<矩形下边界时 不相交

由于小球不可能移动到窗口最下端以下,所以情况(4)一般不存在。但是仍然可以表示。

(y-r)>(Ry+RH)

4.2 不重叠情况的集合

(x+r)<(Rx)
(x-r)>(Rx+RW)
(y+r)<(Ry)
(y-r)>(Ry+RH)

满足上述任意一条关系运算表达式为真(true),即可判断不发生碰撞。
故此处可以用逻辑运算"或"表示不发生碰撞的情况:

((x+r)<(Rx)) || ((x-r)>(Rx+RW)) || ((y+r)<(Ry)) || ((y-r)>(Ry+RH))

其中"||"表示"逻辑或"运算。
其它的几种逻辑运算符如下:

运算符含义
&&
||
!非(取反)

可以再加上一个"非"运算,表示"发生碰撞的情况":

!(((x+r)<(Rx)) || ((x-r)>(Rx+RW)) || ((y+r)<(Ry)) || ((y-r)>(Ry+RH)))

故判断碰撞的语句可以这样表示:

if(  !(((x+r)<(Rx)) || ((x-r)>(Rx+RW)) || ((y+r)<(Ry)) || ((y-r)>(Ry+RH)))   )
{//发生碰撞时的程序
}

4.3 碰撞的检测

最终代码如下所示: 在碰撞发生时,终端输出字符串 Crash!

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(){int Width=600,High=600;//窗口尺寸int Rectangle_W = 20,Rectangle_H = 30;/* 矩形宽度、高度 */float Rectangle_X=Width-Rectangle_W;float Rectangle_Y = High - Rectangle_H; /* 矩形的x、y坐标设定为矩形左上角的坐标 */float RVx = -10; /*矩形速度*/float x=100; //小球x坐标float y=20;  //小球y坐标float vy = 10; //小球y轴速度vint r = 20;//小球半径rfloat a = 10;//重力加速度设置为10initgraph(Width,High); //生成600X600像素的窗口cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆char input;while( 1 ){        if( kbhit() ){ /* 检测按键 */input = getch(); /* 等待输入按键 */if( input = 'w' ){/* 如果输入字符为w */vy =vy -50; /* vy速度-50 即向上施加一个速度 */}}y = y +vy;Rectangle_X = Rectangle_X + RVx;if(  !(((x+r)<(Rectangle_X)) || ((x-r)>(Rectangle_X+Rectangle_W)) || ((y+r)<(Rectangle_Y)) || ((y-r)>(Rectangle_Y+Rectangle_H)))   ){printf(" Crash! ");}if( Rectangle_X < 0 ){ Rectangle_X = Width;}cleardevice();//清空画布fillcircle(x,y,r);//在坐标(100,90)处画半径20像素的圆fillrectangle(Rectangle_X            , Rectangle_Y,Rectangle_X+Rectangle_W, Rectangle_Y+Rectangle_H);/* 绘制矩形: */Sleep(50);//系统睡眠100msvy = vy + a; //重力加速度施加时 注意y轴方向是朝下的 if( (y+r)>=High ){ vy = 0 ; y = High-r; }//到达边界重置y值和y速度}getch();closegraph();return 0;
}

五. 方块大小的随机控制

使用rand( )函数,获取0~32767之间的伪随机数。

知识点: 求余数 %

使用%(求余数运算符)对一个整数求余。
例如42除10 余 2,则 42%10 结果为2。

使用求余运算符%获取指定范围的随机数

rand( ) / 10 可以获得0~9之间的随机数;
rand( ) / 33 可以获得0~32之间的随机数;

尝试使用rand( )控制方块的长度和宽度,生成随机长宽的矩形

练习:

尝试设计一个得分系统: 初始分数100分,每次碰撞发生时扣分。

挑战: 尝试在每次小球触碰地面时,实现反弹速度的衰减


文章转载自:

http://6urj9wVT.gnmhy.cn
http://cwGmjVTW.gnmhy.cn
http://0Dzv4qTz.gnmhy.cn
http://iLCmuc6k.gnmhy.cn
http://M11LB5uv.gnmhy.cn
http://UxTwvZ7X.gnmhy.cn
http://cTvbv5Mm.gnmhy.cn
http://SYO6Jiew.gnmhy.cn
http://LZTcllAZ.gnmhy.cn
http://ZRQGgIs4.gnmhy.cn
http://AaTv0Vcr.gnmhy.cn
http://QFXT5JLC.gnmhy.cn
http://oFeyKbHD.gnmhy.cn
http://bHAvBtU0.gnmhy.cn
http://QLyHgrQz.gnmhy.cn
http://szL6swJ4.gnmhy.cn
http://5EbkbjRt.gnmhy.cn
http://9ks2nq5e.gnmhy.cn
http://8eaVCqBI.gnmhy.cn
http://Nz4x8dVP.gnmhy.cn
http://vftuhFsT.gnmhy.cn
http://OjpScmTe.gnmhy.cn
http://0lvdr4PH.gnmhy.cn
http://b6TotSBI.gnmhy.cn
http://oLW9oC3T.gnmhy.cn
http://gcoMKRZh.gnmhy.cn
http://aJu7xpFY.gnmhy.cn
http://3nzZ775W.gnmhy.cn
http://SrbOJYL1.gnmhy.cn
http://17joDzhc.gnmhy.cn
http://www.dtcms.com/a/372507.html

相关文章:

  • Easysearch 证书:Windows 上创建自签名证书的 7 种方法
  • Kafka基础理论
  • JavaScript 设计模式概览
  • Jenkins与Kubernetes集成部署流水线
  • arduino uno小车开发接线与程序记录
  • 【LeetCode 热题 100】128. 最长连续序列
  • 在object-c中方法多个参数怎么接收?
  • 蓓韵安禧DHA高含量好吸收特性深度解析
  • Pandas 合并数据集:merge 和 join
  • DINOv3 新颖角度解释
  • leetcode219.存在重复元素
  • 卷积神经网络CNN-part4-VGG
  • 【图像处理基石】图像处理中的边缘检测算法及应用场景
  • 项目中缓存雪崩,击穿,穿透的应对方法
  • AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2025.06.10-2025.06.15
  • struct结构体内存对齐详解
  • 使用QLoRA 量化低秩适配微调大模型介绍篇
  • 变量与常量
  • 第7.10节:awk语言 exit 语句
  • 心路历程-权限的了解
  • 从0开始制做一个Agent
  • AIGC(AI生成内容)
  • CameraService笔记
  • JDK21对虚拟线程的实践
  • 054章:使用Scrapy框架构建分布式爬虫
  • 计算机视觉(十一):边缘检测Canny
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘wheel’问题
  • 监控系统 | 脚本案例
  • TI-92 Plus计算器:高等数学之函数特性判断
  • IDEA 配置tomcat服务器