目录
前言
声明:本游戏参考《c语言课程设计与游戏开发实践教程》。
视频效果如下:
泡泡
- 很多泡泡以不同的速度相互碰撞,或者和墙壁碰撞。碰撞之后相互交换速度,呈现出一种唯美的效果。大家记得以前电脑桌面待机时的画面吗,是不是很相似呢?
涉及基础知识:
printf和scanf,宏定义常量,运算符,定义全局变量,for循环,while循环,if语句,二维数组。
(可能的)拓展知识:
rand函数,Sleep函数,easyx的使用。
rand函数见这篇文章,目录中可以找到
Sleep函数见这篇文章,目录中可以找到
Easyx的安装类似于一个插件,官网如下
http://www.easyx.cn/downloads/
(好像vs和vc++可以装,devc++装不了。还是不清楚可以去b站查教程)
下面放代码。代码中有详细的注释说明。
完整代码
#include <stdio.h>
#include <graphics.h>
#include <math.h>
#define high 480
#define width 640
#define ball 15//小球个数
//先给五个小球进行初始化定义和赋值,绘出基本画面。
//再利用while(1)循环显示动态画面
int main()
{
float x[ball], y[ball];
float speed_x[ball], speed_y[ball];
float radius = 30;
int i, n;
//初始化赋值。用这种方法是因为让小球在不出屏幕的前提下随机出现,并且随机速度
for (i = 0; i < ball; i++)
{
y[i] = rand() % int(high - 4 * radius) + 2 * radius;
x[i] = rand() % int(width - 4 * radius) + 2 * radius;
speed_y[i] = (rand() % 2) - 1;
speed_x[i] = (rand() % 2) - 1;
}
initgraph(width, high);
BeginBatchDraw();
//批量绘图函数,配合FlushBatchDraw()和RndBatchDraw()函数使用
while (1)
{
//先画黑球,目的是盖住彩色球的运动轨迹
setcolor(BLACK);
setfillcolor(BLACK);
for (i = 0; i < ball; i++)
fillcircle(x[i], y[i], radius);
//更新圆坐标
for (i = 0; i < ball; i++)
{
x[i] += speed_x[i];
y[i] += speed_y[i];
}
//判断是否撞墙
for (i = 0; i < ball; i++)
{
if ((x[i] <= radius) || (x[i] >= width - radius))
speed_x[i] = -speed_x[i];
if ((y[i] <= radius) || (y[i] >= high - radius))
speed_y[i] = -speed_y[i];
}
float record[ball][2];
//这个二维数组的1储存原小球编号,2分别储存距离和那个小球编号
//二维数组赋值初始化
for (i = 0; i < ball; i++)
{
record[i][0] = 9999999;
record[i][1] = -1;
}
//求所有小球两两间距离平方
for (i = 0; i < ball; i++)
{
for (n = 0; n < ball; n++)
{
if (i != n)
{//勾股定理
float dist2;
dist2 = (x[i] - x[n]) * (x[i] - x[n]) +
(y[i] - y[n]) * (y[i] - y[n]);
if (dist2 < record[i][0])
{
//这类似于函数的极限。两个动态的量进行比较最终record会被赋予最小的那个数
//而这个最小的数就是第i个小球距离它最近的小球的距离的平方
record[i][0] = dist2;
record[i][1] = n;
}
}
}
}
//判断球和球之间会不会相撞
for (i = 0; i < ball; i++)
{
if (record[i][0] <= 4 * radius * radius)
{
int t = record[i][1];
//下面进行交换速度
int temp;//temp n.临时(职员)
temp = speed_x[i];
speed_x[i] = speed_x[t]; speed_x[t] = temp;
temp = speed_y[i];
speed_y[i] = speed_y[t]; speed_y[t] = temp;
//因为两个相聚最近的小球有可能归于彼此都是最近的,这种情况会发生二次交换速度
//所以给离球i最近的球重新赋初值,避免交换两次速度
record[t][0] = 9999999;
record[t][1] = -1;
}
}
//画彩色的圆,颜色自调
setfillcolor(RGB(190, 250, 255));
setcolor(RGB(50, 200, 255));
for (i = 0; i < ball; i++)
fillcircle(x[i], y[i], radius);
FlushBatchDraw();
Sleep(2);
}
EndBatchDraw();
closegraph();
return 0;
}
二维数组的含义和初值
这个二维数组的作用就是储存一个小球相聚最近的小球的距离和编号。
- record[ball][2]:ball就是球的数量对吧,这个元素就是用来储存原来小球编号。record[i][0]用来存第i个球和它距离最近球的距离平方;record[i][1]用来存第i个球和它距离最近球的编号。
- 为啥赋值9999999和-1呢,因为9999999肯定比任意两个球之间距离的平方都大,后边判断的时候就很明确。-1是因为没有小球的编号是-1,保证不跟后面要赋的值冲突。
大致思路
- while(1)之前做预处理和小球坐标的初始化。while(1)之内显示画面。
- 进入while(1)内,先画了一个黑球。这个黑球的坐标其实正好是彩色球桌标的前一个位置坐标。因为画完黑球之后xy坐标都被+1,都往前移一个坐标,所以新球(彩球)坐标比黑球领先一个,这也使得黑球能够覆盖住彩球的运动轨迹。
- 中间的碰撞等一系列操作其实是对黑球和彩球同时作用的,这样使得两个球的运动相对同步。
- 中间先判断和墙碰撞,如果装了速度就变反;再判断球球之间的碰撞,碰撞之后会借用temp变量交换速度(这个速度看作矢量)。
- 最后,彩球的位置其实放在更新坐标语句之后也可以,因为要和黑球错一个位置嘛。
其实在while(1)之内的几个语句功能是环环相扣的,不同语句按照不同顺序排列,组成了一个完整顺畅的程序。
如果有什么不懂的地方可以随时问我
就酱,拜拜~