互动粒子仿真效果(摩擦力、引力、击打力)

其实模仿力的作用,莫过于模仿力造成的加速度或者物体的形变,所以要模拟现实世界中的摩擦力、引力、击打力只需要根据他们作用力度给与一定的加速度去影响物体的速度即可,所以这个问题其实很简单。

互动粒子仿真的主要功能:
(1)粒子运动会受到摩擦力的影响
(2)粒子会受到鼠标引力的影响,且距离越近引力越大(加速度越大)
(3)粒子会受到鼠标单击(击打力)的影响,且距离越近力越大(加速度越大)
(4)粒子会受到鼠标移动时的扰动,类似于在水面上拿树枝搅动,搅动的越快扰动越大

互动粒子仿真的效果:
在这里插入图片描述
具体如何实现注释中已经很清晰,其实无外乎加速度:

#include <conio.h>
#include <graphics.h>
#include <time.h>
#include <math.h>
#include <stdio.h>
// 游戏画面尺寸
#define Height 768  
#define Width 1024
#define BallNum 800 //小球数量
#define FRICTION 0.96//摩擦力、阻尼系数
struct Ball{
	float x,y;
	float v_x,v_y;
	float radius;
	COLORREF color;
};
Ball BallArray[BallNum];//存放小球数据的数组
int mouse_x=0,mouse_y=0,tmp_mouse_x=0,tmp_mouse_y=0;
int isBUTTONDOWN=0;
void delay(DWORD ms){//为了让速度在不同性能的电脑上相同,定义一个绝对延时函数
	static DWORD oldtime=GetTickCount();
	while(GetTickCount()<oldtime){
		Sleep(1);
	}
	oldtime=GetTickCount();
}
void startup() // 数据初始化
{
	srand((unsigned) time(NULL));
	int i,j;
	for(i=0;i<BallNum;i++){
		BallArray[i].color=RGB(rand()%256,rand()%256,rand()%256);
		BallArray[i].v_x=float(cos(float(i)))*(rand()%34);
		BallArray[i].v_y=float(sin(float(i)))*(rand()%34);
		BallArray[i].x=rand()%Width;
		BallArray[i].y=rand()%Height;
		BallArray[i].radius=(rand()%34)/15;
	}
	initgraph(Width,Height);
	BeginBatchDraw();
}
void clean()//清除上一帧
{
	clearrectangle(0,0,Width,Height);
}
void show()  // 显示画面
{
	int i,j;
	for(i=0;i<BallNum;i++){
		setcolor(BallArray[i].color);
		setfillcolor(BallArray[i].color);
		fillcircle(int(BallArray[i].x+0.5),int(BallArray[i].y+0.5),int(BallArray[i].radius+0.5));//四舍五入
	}
	FlushBatchDraw();
	delay(5); 
}	

void updateWithoutInput()  // 与用户输入无关的更新
{	
	int i,j;
	float gravitation_range=Width*0.86;//受鼠标引力影响的范围
	float boll_range=Width*0.5;//受鼠标按下击打力影响的范围
	float stir_range=Width*0.125;//受鼠标移动时对小球扰动的范围
	//且搅动的越快搅动幅度越大(所以要计算鼠标速度,就用上一次鼠标位置减这一次来代替)
	int mouse_v_x=tmp_mouse_x-mouse_x;
	int mouse_v_y=tmp_mouse_y-mouse_y;
	tmp_mouse_x=mouse_x;
	tmp_mouse_y=mouse_y;
	for(i=0;i<BallNum;i++){
		//当前小球的信息
		float x=BallArray[i].x,y=BallArray[i].y;
		float v_x=BallArray[i].v_x,v_y=BallArray[i].v_y;
		//添加鼠标的引力(离鼠标越近引力越大)
		//当前小球到鼠标的距离
		float distance_x=x-mouse_x;
		float distance_y=y-mouse_x;
		float distance=sqrt(distance_x*distance_x+distance_y*distance_y);
		//把小球到鼠标的x、y距离分量全转换为仅表示方向
		if(distance!=0){
			distance_x=distance_x/distance;
			distance_y=distance_y/distance;
		}else{
			distance_x=0;
			distance_y=0;
		}
		if(distance<gravitation_range){
			//引力造成的加速度:
			float A_v=(1-(distance/gravitation_range))*Width*0.0014;
			v_x-=distance_x*A_v;
			v_y-=distance_y*A_v;
		}
		//鼠标点击时的击打力(离鼠标点击处越近受影响越大)
		if(isBUTTONDOWN==1&&distance<boll_range){
			float A_v=(1-(distance/stir_range))*10;
			v_x+=distance_x*A_v+0.5-float(rand())/RAND_MAX;//加入-0.5~0.5的扰动
			v_y+=distance_y*A_v+0.5-float(rand())/RAND_MAX;
		}
		//鼠标移动时对粒子的扰动且搅动的越快搅动幅度越大
		if(distance<stir_range){
			float A_v=(1-(distance/boll_range))*Width*0.00026;
			v_x+=mouse_v_x*A_v;
			v_y+=mouse_v_y*A_v;
		}

		//每帧都乘上阻尼系数模拟现实的摩擦力
		v_x*=FRICTION;
		v_y*=FRICTION;
		//为了不让小球静止,给速度过慢的小球提提速
		float V_x=abs(v_x);
		float V_y=abs(v_y);
		if(V_x<0.1){//float(rand())/RAND_MAX可以大概率让小球速度乘3
			v_x*=float(rand())/RAND_MAX*3;
		}
		if(V_y<0.1){
			v_y*=float(rand())/RAND_MAX*3;
		}
		//控制小球大小在0.4~3.5之间,速度越大小球半径越大
		float Avg_v= (V_x+V_y)*0.5;//0<=Avg_v<34;
		BallArray[i].radius=max(min(Avg_v*0.5,3.5),0.4);
		//得到小球下一帧的位置
		float next_x=x+v_x;
		float next_y=y+v_y;
		//碰到窗口边界反弹
		if(next_x>Width){
			next_x=Width;
			v_x=-v_x;
		}
		if(next_x<0){
			next_x=0;
			v_x=-v_x;
		}
		if(next_y>Height){
			next_y=Height;
			v_y=-v_y;
		}
		if(next_y<0){
			next_y=0;
			v_y=-v_y;
		}
		//更新小球信息
		BallArray[i].x=next_x;
		BallArray[i].y=next_y;
		BallArray[i].v_x=v_x;
		BallArray[i].v_y=v_y;
	}	
}		

void updateWithInput()  // 与用户输入有关的更新
{
	//鼠标交互
	MOUSEMSG m;
	if(MouseHit()){
		m=GetMouseMsg();
		if(m.uMsg==WM_MOUSEMOVE){
			mouse_x=m.x;
			mouse_y=m.y;
		}
		if(m.uMsg==WM_LBUTTONDOWN){
			isBUTTONDOWN=1;
		}
		if(m.uMsg==WM_LBUTTONUP){
			isBUTTONDOWN=0;
		}
	}
}
void gameover()//结束时调用的函数
{
	EndBatchDraw();
	getch();
	closegraph();
}
int main()
{
	startup();  // 数据初始化	
	while (1) //  游戏循环执行
	{
		clean();//清除上一帧画的
		updateWithoutInput();  // 与用户输入无关的更新
		updateWithInput();  // 与用户输入有关的更新
		show();  // 显示画面	
	}
	gameover();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值