C语言EasyX详解(小球碰撞)
首先先来认识下EasyX
EasyX 是针对 C/C++ 的图形库,可以帮助使用C/C++语言的程序员快速上手图形和游戏编程。
比如,可以用 VC + EasyX 很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。
1.静止小球
#include <conio.h>
#include <graphics.h>
int main()
{
initgraph(640,480); //初始化画布大小
setcolor(YELLOW); //圆的线条颜色
setfillcolor(GREEN); //圆内部填充颜色
fillcircle(100,100,20); //圆位置以及半径
getch(); //按任意键继续
closegraph(); //关闭图形界面
initgraph(640,256); //初始化画布
for(int y=0;y<256;y++)
{
setcolor(RGB(0,y,y));
line(0,y,640,y); //画线
}
getch();
closegraph();
return 0;
}
2.颜色渐变实现
#include <conio.h>
#include <graphics.h>
int main()
{
initgraph(640,256); //初始化画布
for(int y=0;y<256;y++)
{
setcolor(RGB(0,y,y));
line(0,y,640,y); //画线
}
getch();
closegraph();
return 0;
}
3.围棋棋盘
#include <conio.h>
#include <graphics.h>
int main()
{
initgraph(800,800);
setcolor(YELLOW);
for(int i=0;i<801;i++)
{
line(0,i,841,i);
}
setcolor(BLACK);
for(int j=40;j<761;j+=40)
{
line(40,j,760,j);
line(j,40,j,760);
}
setfillcolor(BLACK);
fillcircle(160,160,4); //在围棋的九个点上画圆
fillcircle(160,400,4);
fillcircle(160,640,4);
fillcircle(400,160,4);
fillcircle(400,400,4);
fillcircle(400,640,4);
fillcircle(640,160,4);
fillcircle(640,400,4);
fillcircle(640,640,4);
getch();
closegraph();
return 0;
}
4.国际象棋棋盘
#include <conio.h>
#include <graphics.h>
int main()
{
//国际象棋棋盘
initgraph(640,640);
for(int i=0;i<640;i+=80)
{
for(int j=0;j<640;j+=80)
{
if(j/80%2==0)
{
if(i/80%2==0)
{
setfillcolor(BLACK);
fillrectangle(j,i,j+80,i+80);
}
if(i/80%2==1)
{
setfillcolor(WHITE);
fillrectangle(j,i,j+80,i+80);
}
}
if(j/80%2==1)
{
if(i/80%2==1)
{
setfillcolor(BLACK);
fillrectangle(j,i,j+80,i+80);
}
if(i/80%2==0)
{
setfillcolor(WHITE);
fillrectangle(j,i,j+80,i+80);
}
}
}
}
getch();
closegraph();
return 0;
}
5.小球运动
#include <conio.h>
#include <graphics.h>
#include <time.h>
int main()
{
int ball_x,ball_y; //小球位置坐标
int ball_vx=1; //小球X轴与Y轴的速度
int ball_vy=1;
//随机生成小球初始位置
srand((unsigned)time(NULL));
ball_x=rand()%600+20;
ball_y=rand()%360+20;
initgraph(640,400);
BeginBatchDraw(); //这个函数用于开始批量绘图,执行后任何绘图操作都将暂时不输出到屏幕上。
while(1)
{
setcolor(YELLOW);
setfillcolor(GREEN);
fillcircle(ball_x,ball_y,20);
Sleep(2);
FlushBatchDraw(); //将之前的绘图输出,这个函数用于执行未完成的绘图人物。
setcolor(BLACK);
setfillcolor(BLACK);
fillcircle(ball_x,ball_y,20);
ball_x=ball_x+ball_vx;
ball_y=ball_y+ball_vy;
//当小球表面接触墙壁时发生碰撞反弹
if(ball_x<=20||ball_x>=620)
ball_vx=-ball_vx;
if(ball_y<=20||ball_y>=380)
ball_vy=-ball_vy;
}
EndBatchDraw(); //结束批量绘制,并执行未完成的绘图任务
closegraph();
return 0;
}
6.多个小球移动
#include <conio.h>
#include <graphics.h>
#include <time.h>
#define number 10 //小球个数
struct Ball
{
int ball_x;
int ball_y;
int ball_vx;
int ball_vy;
};
Ball balls[number];
int main()
{
//初始化所有小球位置
srand((unsigned)time(NULL));
for(int i=0;i<number;i++)
{
balls[i].ball_x=rand()%600+20;
balls[i].ball_y=rand()%360+20;
balls[i].ball_vx=1;
balls[i].ball_vy=1;
//printf("[%d,%d]\n",balls[i].ball_x,balls[i].ball_y);
}
initgraph(640,400);
BeginBatchDraw();
while(1)
{
setcolor(YELLOW);
setfillcolor(GREEN);
//绘制所有小球
for(int i=0;i<number;i++)
{
fillcircle(balls[i].ball_x,balls[i].ball_y,20);
}
Sleep(2);
FlushBatchDraw();
setcolor(BLACK);
setfillcolor(BLACK);
//改变所有小球坐标
for(i=0;i<number;i++)
{
fillcircle(balls[i].ball_x,balls[i].ball_y,20);
balls[i].ball_x=balls[i].ball_x+balls[i].ball_vx;
balls[i].ball_y=balls[i].ball_y+balls[i].ball_vy;
if(balls[i].ball_x<=20||balls[i].ball_x>=620)
balls[i].ball_vx=-balls[i].ball_vx;
if(balls[i].ball_y<=20||balls[i].ball_y>=380)
balls[i].ball_vy=-balls[i].ball_vy;
}
}
EndBatchDraw();
closegraph();
}
7.多个小球碰撞
从上面可以看出,多个小球运动是有相互交错的部分,我们可以增加碰撞功能
#include <conio.h>
#include <graphics.h>
#include <time.h>
#define number 10 //小球个数
struct Ball
{
int ball_x;
int ball_y;
int ball_vx;
int ball_vy;
int distance[2]; //记录某个小球,距离它最近的小球的距离,以及这个小球的下标
};
Ball balls[number];
int main()
{
void get_distance(struct Ball balls[number]);
void knock(struct Ball balls[number]);
//初始化所有小球位置
srand((unsigned)time(NULL));
for(int i=0;i<number;i++)
{
balls[i].ball_x=rand()%600+20;
balls[i].ball_y=rand()%360+20;
for(int j=0;j<number;j++)
if(i!=j) //不用和自己比
{
//初始化让小球不会轻易重叠
if((balls[i].ball_x>=balls[j].ball_x-20)&&(balls[i].ball_x<=balls[j].ball_x+20)&&
(balls[i].ball_y>=balls[j].ball_y-20)&&(balls[i].ball_y<=balls[j].ball_y+20))
{
balls[i].ball_x=rand()%600+20;
balls[i].ball_y=rand()%360+20;
}
}
balls[i].ball_vx=1;
balls[i].ball_vy=1;
//printf("[%d,%d]\n",balls[i].ball_x,balls[i].ball_y);
}
for (i=0;i<number;i++)
{
balls[i].distance[0] = 99999999;
balls[i].distance[1] = -1;
}
initgraph(640,400);
BeginBatchDraw();
while(1)
{
setcolor(YELLOW);
setfillcolor(GREEN);
//绘制所有小球
for(int i=0;i<number;i++)
{
fillcircle(balls[i].ball_x,balls[i].ball_y,20);
}
get_distance(balls);
knock(balls);
Sleep(2);
FlushBatchDraw();
setcolor(BLACK);
setfillcolor(BLACK);
//改变所有小球坐标
for(i=0;i<number;i++)
{
fillcircle(balls[i].ball_x,balls[i].ball_y,20);
balls[i].ball_x=balls[i].ball_x+balls[i].ball_vx;
balls[i].ball_y=balls[i].ball_y+balls[i].ball_vy;
if(balls[i].ball_x<=20||balls[i].ball_x>=620)
balls[i].ball_vx=-balls[i].ball_vx;
if(balls[i].ball_y<=20||balls[i].ball_y>=380)
balls[i].ball_vy=-balls[i].ball_vy;
}
}
EndBatchDraw();
closegraph();
return 0;
}
int i,j;
void get_distance(struct Ball balls[number])
{
// 求解所有小球两两之间的距离平方
for (i=0;i<number;i++)
{
for (j=0;j<number;j++)
{
if (i!=j) // 自己和自己不需要比
{
int dist2;
dist2 = (balls[i].ball_x - balls[j].ball_x)*(balls[i].ball_x - balls[j].ball_x)
+(balls[i].ball_y - balls[j].ball_y)*(balls[i].ball_y - balls[j].ball_y);
if (dist2<balls[i].distance[0])
{
balls[i].distance[0] = dist2;
balls[i].distance[1] = j;
}
}
}
}
}
void knock(struct Ball balls[number])
{
// 判断球之间是否碰撞
for (i=0;i<number;i++)
{
if (balls[i].distance[0]<=4*(20*20)) // 最小距离小于阈值,发生碰撞
{
j = balls[i].distance[1];
// 交换速度
int temp;
temp = balls[i].ball_vx; balls[i].ball_vx = balls[j].ball_vx; balls[j].ball_vx = temp;
temp = balls[i].ball_vy; balls[i].ball_vy = balls[j].ball_vy; balls[j].ball_vy = temp;
balls[j].distance[0] = 99999999; // 避免交换两次速度,将两个小球重新赋值
balls[j].distance[1] = -1;
balls[i].distance[0] = 99999999;
balls[i].distance[1] = -1;
}
}
}