流沙画模拟器源码

    流沙画,在密封的玻璃镜框内,装入氧化铝、磨刚沙、无色的混合液和适量的气泡。
    当镜框倒竖时,利用氧化铝和磨刚沙的比重不同以及气泡的上浮力,使氧化铝和磨刚沙按不同速度下沉到空腔的底部,形成层次分明,跌宕有序的画面。
    装入镜框的沙粒,一般有黑色、白色、蓝色(或其它颜色),另外还可能加入一些较大的黑色颗粒。

    要用真实的物理模拟流沙画,需要给每个粒子赋予位置、速度等属性,使用流体动画,实现复杂,速度较慢。这里使用变通的方法,所有粒子沉降速度相同,这样粒子运动不会发生穿插,每一个像素上的粒子数量有限。利用粒子的颜色变化来模拟粒子沉积比例。

 可以贴到3DUI上

     //几个绘制小技巧, 左键撒沙子, 右键挖除, 每种粒子都可以调色

    //月亮:球形画刷+零重力 刷出圆形,右键挖出月亮。

    //云层:球形画刷+稀疏度+零重力 刷出云层,右键挖出云层轮廓,蓝色粒子洒在云彩上进行描边。

    //村落:方形画刷+稀疏度+零重力 刷出建筑,

    //滑坡:移动倾向+右键 挖出斜向山脊 
    
    //瀑布:右键挖空,使蓝色粒子下落形成瀑布水流

    //树木:先混合沙子撒少量树根,后撒树枝(棕色树叶代替),最后撒绿色树叶

    //小路:同色线刷子模拟路 或普降的烟尘

    //橡皮檫粒子会檫除接触到的其它粒子,树叶粒子会附着到树根粒子和其它树叶粒子。水粒子目前和沙粒子没有区别,应该具有更强的流动性。

    // 可以刷在已有沙子的内部,直接替换,刷出平滑体。可以用零重力沙子托起一堆带重力的沙子,然后檫除部分零重力沙子形成下雨或水流动画。

 源码:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/SandBox/MiniGameSandBox.h
//  @Brief:     MiniGameSandBox
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#ifndef  __MiniGameSandBox__H__
#define  __MiniGameSandBox__H__

#include "Math/MathLib.h"
#include "Render/Texture.h"
#include "Rpg/MiniGame.h"

namespace RendSys
{
	class MC_Frame;
}
class SandBoxPlayerRole;
class MiniGameSandBox:public MiniGame
{
public:
	enum ParticleType
	{
		PT_Null  = 0,
		PT_Sand ,
		PT_Water,
		PT_Stone,
		PT_Root ,  //树根在第一层,可以和沙粒混合
		PT_Tree ,  //树叶在第二层,和第一层可以重叠,其它粒子都在第一层
		PT_Wall ,
		PT_Erase,
		PT_Max  ,
	};

	//大量堆积或挖空时沙子移动倾向
	enum ParticleMove
	{
		PM_Left  = 0, //倾向左    (从右向左遍历行粒子)
		PM_Right ,    //倾向右    (从左向右遍历行粒子)
		PM_Down  ,    //左右均衡 (偶数行从左向右遍历,奇数行从右向左遍历)
		PM_Max   ,
	};

	enum BrushType
	{
		BT_Circle  = 0,
		BT_Square ,
		BT_Line,
		BT_Max  ,
	};

	//粒子移动方向
	enum Dir
	{
		UP   =0,
		DOWN ,
		LEFT ,
		RIGHT,
		UPLEFT,
		UPRIGHT,
		DOWNLEFT,
		DOWNRIGHT,
	};

	//
	class ParticleStyle
	{
	public:
		ParticleStyle();
		void SetColor(const Color& color,float hRange);
		void FreshBatchColor();   //批次间变色
		void FreshParticleColor();//批次内变色

	public:
		bool  active;
		int   weight;		
		bool  gravity; //false不动,true没帧下降1像素,没有其它速度,同一个位置粒子数量有限

		ParticleType type; 
		float hMin,hMax;
		float sMin,sMax;
		float lMin,lMax;

		//批次间变色
		float h,s,l;
		float r,g,b;
		float hSpeedBatch,sSpeedBatch,lSpeedBatch;           

		//批次内变色
		bool  particleHSL;
		float hParticle,sParticle,lParticle;
		float rParticle,gParticle,bParticle,aParticle;
		float hSpeedParticle,sSpeedParticle,lSpeedParticle;  
	};

	//
	class Particle
	{
	public:
		//int    id;        //index
		//vec2I  pos;       //位置

		//layer1
		ParticleType type;       //
		bool         gravity;
		char         color[4];

		//layer2
		ParticleType type2;       //
		bool         gravity2;
		char         color2[4];

		bool         rooted;     //树叶粒子是否生根

		//char         flag;
		Particle*    neighbour[8];
	};

	MiniGameSandBox();
	virtual ~MiniGameSandBox();

	virtual bool KeepResource(bool once,int& circle,String& nextTip);
	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual void RenderUI();
	virtual bool Update();
	virtual bool Free();
	virtual bool IsEnd();

	//处理游戏网络命令包
	virtual int  ProcessPacketCmd(PacketBase* packet);
	//virtual const char* CmdToString(const char* stream,int len);

	void  ClearTarget();
	vec2I ScreenToTarget(const vec2 &pos);

	void  UpdateInput();
	void  UpdateParticle();
	void  MapTarget();

	void  Brushing(const vec2I& pos);
	void  Digging(const vec2I& pos);

	void  FreshWeightAll();
	ParticleStyle* RandParticle();

//private:
	ParticleMove  particleMove;
	ParticleStyle Styles[PT_Max];
	int           WeightAll; //活动总概率 用于随机产生粒子

	vec2I     Size;
	Particle* m_particles;

	RectF      m_canvasRect;
	TexturePtr m_texTarget;

	Color m_backColor;

	int   m_brushSize;	
	int   m_brushSparse;	//刷子稀疏度
	bool  m_brushSparseRand;//刷子稀疏度噪声扰动
	int   m_brushShape;
	float m_brushTime;
	vec2I m_brushPos;

	SandBoxPlayerRole* m_myRolePlayer;
	//非观战时 viewside==myside
	int              m_myViewSide;
	int              m_curSide;


	bool  m_workingWithAI;
	vec2I m_brushSpeed;

};
extern MiniGameSandBox* G_SandBoxGame;
#endif 

 

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/SandBox/MiniGameSandBox.cpp
//  @Brief:     MiniGameSandBox
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#include "General/Pch.h"
#include "General/Window.h"
#include "General/Timer.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Gui/GuiControlMisc.h"
#include "Input/InputMgr.h"
#include "SandBox/SandBoxPlayer.h"
#include "SandBox/MiniGameSandBox.h"
#include "SandBox/MiSandBox_PlayGui.h"
#include "Render/RendDriver.h"
#include "Render/Shader.h"
#include "Render/MC_Misc.h"
#include "Rpg/SyncGameInfo.h"
#include "Packet/PacketMiniGame.h"
#include "Net/PacketList.h"
#include "Render/Camera.h"
#include "General/Pce.h"

const char* SandBoxCmdToString(int enumeration)
{
	switch(enumeration)
	{
	case CMD_ManMove :return "CMD_ManMove ";		
	case CMD_GameOver:return "CMD_GameOver";		
	case CMD_Restart :return "CMD_Restart ";			
	default             :return "CMD_unknow";
	}
	return "CMD_unknow";
}

static int opDir[] =
{
	MiniGameSandBox::DOWN,//UP ,
	MiniGameSandBox::UP,//DOWN ,
	MiniGameSandBox::RIGHT,//LEFT ,
	MiniGameSandBox::LEFT,//RIGHT,
	MiniGameSandBox::DOWNRIGHT,//UPLEFT,
	MiniGameSandBox::DOWNLEFT,//UPRIGHT,
	MiniGameSandBox::UPRIGHT,//DOWNLEFT,
	MiniGameSandBox::UPLEFT,//DOWNRIGHT,
};

MiniGameSandBox* G_SandBoxGame;
MiniGameSandBox::MiniGameSandBox()
:m_particles(NULL)
{
	G_SandBoxGame = this;
	CmdEnumToString = SandBoxCmdToString;
}

MiniGameSandBox::~MiniGameSandBox()
{
	G_SandBoxGame = NULL;
}

bool MiniGameSandBox::Start()
{
	m_myRolePlayer = NULL;
	if(!MiniGame::Start())
		return false;

	m_workingWithAI = false;

	ParticleStyle* style;

	//todo save and load from cfg file
	style = &Styles[PT_Sand];
	style->type = PT_Sand;
	style->SetColor(Color(230/255.0f, 170/255.0f, 20/255.0f, 1),0.07f);
	style->sMin = 0.3f;
	style->sMax = 0.6f;
	style->lMin = 0.1f;
	style->lMax = 0.5f;
	style->hSpeedBatch = 0.02f;
	style->sSpeedBatch = 0.08f;
	style->lSpeedBatch = 0.08f;           //批次间变色
	style->hSpeedParticle = 0.005f;
	style->sSpeedParticle = 0.01f;
	style->lSpeedParticle = 0.01f;        //批次内变色


	style = &Styles[PT_Water];
	style->type = PT_Water;
	style->SetColor(Color(20/255.0f, 150/255.0f, 230/255.0f, 1),0.03f);
	style->sMin = 0.4f;
	style->sMax = 0.6f;
	style->lMin = 0.3f;
	style->lMax = 0.8f;
	style->hSpeedBatch = 0.005f;
	style->sSpeedBatch = 0.05f;
	style->lSpeedBatch = 0.1f;          
	style->hSpeedParticle = 0.005f;
	style->sSpeedParticle = 0.01f;
	style->lSpeedParticle = 0.01f;      

	style = &Styles[PT_Stone];
	style->type = PT_Stone;
	style->SetColor(Color(20/255.0f, 50/255.0f, 50/255.0f, 1),0.01f);
	style->sMin = 0.4f;
	style->sMax = 0.6f;
	style->lMin = 0.3f;
	style->lMax = 0.5f;
	style->hSpeedBatch = 0.002f;
	style->sSpeedBatch = 0.05f;
	style->lSpeedBatch = 0.05f;          
	style->hSpeedParticle = 0.005f;
	style->sSpeedParticle = 0.01f;
	style->lSpeedParticle = 0.01f;  

	style = &Styles[PT_Root];
	style->type = PT_Root;
	style->SetColor(Color(20/255.0f, 250/255.0f, 30/255.0f, 1),0.05f);
	style->sMin = 0.4f;
	style->sMax = 0.6f;
	style->lMin = 0.3f;
	style->lMax = 0.5f;
	style->hSpeedBatch = 0.01f;
	style->sSpeedBatch = 0.05f;
	style->lSpeedBatch = 0.05f;          
	style->hSpeedParticle = 0.005f;
	style->sSpeedParticle = 0.01f;
	style->lSpeedParticle = 0.01f;  


	style = &Styles[PT_Tree];
	style->type = PT_Tree;
	style->SetColor(Color(20/255.0f, 250/255.0f, 30/255.0f, 1),0.05f);
	style->sMin = 0.4f;
	style->sMax = 0.6f;
	style->lMin = 0.3f;
	style->lMax = 0.5f;
	style->hSpeedBatch = 0.01f;
	style->sSpeedBatch = 0.05f;
	style->lSpeedBatch = 0.05f;          
	style->hSpeedParticle = 0.005f;
	style->sSpeedParticle = 0.01f;
	style->lSpeedParticle = 0.01f;  

	style = &Styles[PT_Erase];
	style->type = PT_Erase;
	style->SetColor(Color(255/255.0f, 0/255.0f, 0/255.0f, 1),0);
	style->sMin = 0.5f;
	style->sMax = 0.5f;
	style->lMin = 0.5f;
	style->lMax = 0.5f;
	style->hSpeedBatch = 0.0f;
	style->sSpeedBatch = 0.0f;
	style->lSpeedBatch = 0.0f;          
	style->hSpeedParticle = 0.0f;
	style->sSpeedParticle = 0.0f;
	style->lSpeedParticle = 0.0f;  

	//
	for (int i=0;i<PT_Max;i++)
	{	
		style = &Styles[i];
		style->active = false;
		style->weight = 10;
		style->particleHSL  = style->hSpeedParticle>0 || style->sSpeedParticle>0 || style->lSpeedParticle>0;
	}
	style = &Styles[PT_Sand];
	style->active = true;

	style = &Styles[PT_Root];
	style->weight = 1;

	FreshWeightAll();

	particleMove = PM_Down;

	m_3dMode = false;
	m_brushSize   = 1;
	m_brushSparse = 1;
	m_brushSparseRand = false;
	m_brushShape  = 1;
	m_brushTime   = 0;

	Size = vec2I(390,300);
	const int Num = Size.x * Size.y;
	SafeDeleteArray(m_particles);

	m_texTarget = new Texture(true);
	m_texTarget->AllocTexture(Size.x,Size.y,RS_RGBA);

	m_particles = new Particle[Num];
	memset(m_particles,0,sizeof(Particle)*Num);

	//m_backColor = Color(50/255.0f, 90/255.0f, 120/255.0f, 0.3f);	
	m_backColor = Color(50/255.0f, 90/255.0f, 120/255.0f, 0.9f);

	ClearTarget();

	Particle* p = m_particles;
	int sizeX_1 = Size.x - 1;
	int sizeY_1 = Size.y - 1;
	for(int y=0;y<Size.y;++y)
	{
		for(int x=0;x<Size.x;++x,++p)
		{
			if(x>0)       p->neighbour[LEFT]  = p-1;
			if(x<sizeX_1) p->neighbour[RIGHT] = p+1;
			if(y>0)       p->neighbour[DOWN]  = p-Size.x;
			if(y<sizeY_1) p->neighbour[UP]    = p+Size.x;

			if(x>0       && y>0)       p->neighbour[DOWNLEFT]  = p-Size.x-1;
			if(x<sizeX_1 && y>0)       p->neighbour[DOWNRIGHT] = p-Size.x+1;
			if(x>0       && y<sizeY_1) p->neighbour[UPLEFT]    = p+Size.x-1;
			if(x<sizeX_1 && y<sizeY_1) p->neighbour[UPRIGHT]   = p+Size.x+1;
		}
	}

	m_curSide=SideRed;

	if (m_movieScene)
	{
		Frame frame;
		frame.SetPos(m_startPos);
		m_movieScene->SetProgramFrame(&frame);
		m_movieScene->Advance();
	}

	m_gameState  = MS_Gamming;
	m_myViewSide = SideBlack;

	
	//for(int i = 0; i < m_allPlayerNum; i++)
	//{
	//	dynamic_cast<SandBoxPlayer*>(m_miniPlayer[i])->m_side = i==0?SideRed:SideBlack;
	//	//dynamic_cast<SandBoxPlayer*>(m_miniPlayer[i])->m_side = i==0?SideBlack:SideRed;
	//}


//	if(m_myRolePlayer)
//		m_myViewSide = m_myRolePlayer->m_side; 

	//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。
	if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);

	//
	for(int i = 0; i < m_allPlayerNum; i++)
	{
		if(m_miniPlayer[i])
			m_miniPlayer[i]->Start();
	}

	//设置摄像机
	CameraCtrlerTarget* ctrler = new CameraCtrlerTarget;
	ctrler->SetDistToTar(60);
	ctrler->SetTarPos(m_startPos);
	G_Camera->PushCtrler(ctrler);
	G_Camera->SetEuler(0, -60, 0);
	//片头摄像机
	PushIntroCamera();

	return true;
}

void MiniGameSandBox::ClearTarget()
{
	m_workingWithAI = false;
	const int Num = Size.x * Size.y;
	unsigned char BackColor[4] ={m_backColor.r*255,m_backColor.g*255,m_backColor.b*255,m_backColor.a*255};
	Particle* End = m_particles+Num;
	for(Particle* p=m_particles; p!=End; ++p)
	{
		//p->id  = i;
		p->type     = PT_Null;
		p->gravity  = true;
		p->color[0] = BackColor[0];
		p->color[1] = BackColor[1];
		p->color[2] = BackColor[2];
		p->color[3] = BackColor[3];

		p->type2     = PT_Null;
		p->gravity2  = true;
		p->color2[0] = BackColor[0];
		p->color2[1] = BackColor[1];
		p->color2[2] = BackColor[2];
		p->color2[3] = BackColor[3];
	}
}

MiniPlayer* MiniGameSandBox::CreatePlayer()
{
	return NULL;//new SandBoxPlayer;
}

MiniPlayer* MiniGameSandBox::CreateRobot()
{
	return NULL;//new SandBoxPlayerRobot;
}

MiniPlayer* MiniGameSandBox::CreateRole()
{
	m_myRolePlayer = NULL;//new SandBoxPlayerRole;
	return NULL;//m_myRolePlayer;
}


bool MiniGameSandBox::Stop()
{
	G_Camera->PopCtrler();
	//CameraCtrlerTarget* ctrlerTarget = G_Camera->IsCurCtrler<CameraCtrlerTarget>();
	//if(ctrlerTarget)
	//	ctrlerTarget->SetTarEntity(G_MyRole);

	{
		if (m_myPlayer && m_myPlayer->m_liveNum>0)
		{
			G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(true);
		}
		else
		{
			G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(false);
		}
		G_GuiMgr->PushGui("Rpg_ResultDialog",GL_DIALOGBOTTOM); 
	}
	return MiniGame::Stop();
}

//SandBoxPlayer* MiniGameSandBox::GetTurnPlayer()
//{
//	//return dynamic_cast<SandBoxPlayer*>(m_miniPlayer[m_curSide]);
//	for(int i = 0; i < m_allPlayerNum; i++)
//	{
//		SandBoxPlayer* player = dynamic_cast<SandBoxPlayer*>(m_miniPlayer[i]);
//		if (player->m_side == m_curSide)
//		{
//			return player;
//		}
//	}
//	return NULL;
//}

bool MiniGameSandBox::KeepResource(bool once,int& circle,String& nextTip)
{
	//
	char buf[256];
	if (m_movieScene == NULL)
	{
		LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true);
		m_movieScene = new RendSys::MovieClip;
		m_movieScene->LoadFromFile("data/minigame/SandBox/sandboxscene.movie", &loader);

		Frame frame;
		frame.SetPos(m_startPos);
		m_movieScene->SetProgramFrame(&frame);
		m_movieScene->Advance();
	}

	if (m_movieScene->IsLoadComplete() == false)
	{
		m_gameState = MS_End;
		return false;
	}
	return true;
}

bool MiniGameSandBox::Render()
{
	//attach target to ui3D control

	//for(int i = 0; i < m_allPlayerNum; i++)
	//{
	//	dynamic_cast<SandBoxPlayer*>(m_miniPlayer[i])->Render();
	//}

	return true;
}

void MiniGameSandBox::RenderUI()
{
	MiniGame::RenderUI();
}
bool MiniGameSandBox::Update()
{
	m_turnTime  += G_Timer->GetStepTimeLimited();
	m_brushTime += G_Timer->GetStepTimeLimited();

	MiSandBox_PlayGui* playGui = G_GuiMgr->GetGui<MiSandBox_PlayGui>();
	m_canvasRect = playGui->m_canvas->GetRectReal();
	m_canvasRect.SetPos(playGui->m_canvas->GetOffset());

	playGui->m_canvas->SetTexture(m_texTarget,GCS_NORMAL);

	m_movieScene->Advance();

	UpdateInput();
	UpdateParticle();
	MapTarget();

	//for(int i = 0; i < m_allPlayerNum; i++)
	//{
	//	dynamic_cast<SandBoxPlayer*>(m_miniPlayer[i])->Update();
	//}
	return true;
}

void MiniGameSandBox::UpdateInput()
{
	if (m_brushTime < 0.1f)
	{
		return;
	}
	
	//if (m_myRolePlayer && m_curSide != m_myRolePlayer->m_side)
	//	return;

	vec2I pos;
	if (m_workingWithAI)
	{
		ParticleStyle* style;
		for (int i=0;i<PT_Max;i++)
		{	
			style = &Styles[i];
			//style->active = false;
			//style->weight = 10;
			//style->particleHSL  = style->hSpeedParticle>0 || style->sSpeedParticle>0 || style->lSpeedParticle>0;
		}

		Styles[PT_Root].active  = true;
		Styles[PT_Water].active = true;
		Styles[PT_Tree].active  = true;
		FreshWeightAll();

		m_brushSize = 7;
		m_brushSparse = 3;	
		m_brushSparseRand = true;

		m_brushSpeed.x += RandRange(-2,2);
		Clamp(m_brushSpeed.x,-5,5);

		m_brushPos.y = Size.y - m_brushSize;
		m_brushPos.x += m_brushSpeed.x;
		Clamp(m_brushPos.x,m_brushSize,Size.x-m_brushSize);

		Brushing(m_brushPos);
	}
	else if (m_3dMode)
	{
		MiSandBox_PlayGui* playGui = G_GuiMgr->GetGui<MiSandBox_PlayGui>();
		vec2 newPosI;
		if (playGui->m_groupTargetCtrl->GetMapMousePos(G_Mouse->GetMousePos(),newPosI))
		{
			m_brushPos = ScreenToTarget(newPosI);
		}
	}
	else
	{
		m_brushPos = ScreenToTarget(G_Mouse->GetMousePos());
	}

	if (G_SandBoxGame->IsButtonPressed(MOUSE_RIGHT))
	{
		Digging(m_brushPos);
	}		
	else if (G_SandBoxGame->IsButtonPressed(MOUSE_LEFT))
	{
		Brushing(m_brushPos);
	}
}
void MiniGameSandBox::Brushing(const vec2I& pos)
{
	//刷粒子
	m_brushTime = 0;

	int brushSizeSq = m_brushSize*m_brushSize;
	int minX = max(0,pos.x-m_brushSize);
	int maxX = min(Size.x-1,pos.x+m_brushSize);
	int minY = max(0,pos.y-m_brushSize);
	int maxY = min(Size.y-1,pos.y+m_brushSize);

	if(m_brushShape==BT_Line)
	{
		minX = 0;
		maxX = Size.x-1;
		minY = pos.y;
		maxY = pos.y;
	}

	int minSparse = min(0,1-m_brushSparse);
	int maxSparse = max(0,m_brushSparse-1);

	unsigned char BackColor[4] ={m_backColor.r*255,m_backColor.g*255,m_backColor.b*255,m_backColor.a*255};

	//
	ParticleStyle* style;
	for (int i=0;i<PT_Max;i++)
	{	
		style = &Styles[i];
		if (style->active)
		{
			style->FreshBatchColor();
		}
	}

	Particle* p;
	int rx,ry;
	for (int y=minY;y<=maxY;y+=m_brushSparse)
	{
		for (int x=minX;x<=maxX;x+=m_brushSparse)
		{
			if (m_brushSparseRand)
			{
				ry = y + RandRange(minSparse,maxSparse);
				rx = x + RandRange(minSparse,maxSparse);
			}
			else
			{
				ry = y;
				rx = x;
			}

			if( rx<minX || rx>maxX || ry<minY || ry>maxY)
				continue;
			if (m_brushShape==BT_Circle)
			{
				float difx = rx-pos.x;
				float dify = ry-pos.y;
				if( difx*difx + dify*dify > brushSizeSq)
					continue;
			}

			p = &m_particles[ry*Size.x + rx];

			style = RandParticle();
			if (style==NULL)
			{
				break;
			}
			if (style->particleHSL)
			{
				style->FreshParticleColor();
			}

			if (style->type==PT_Tree)
			{
				p->type2     = style->type;
				p->gravity2  = style->gravity;
				p->color2[0] = style->rParticle;
				p->color2[1] = style->gParticle;
				p->color2[2] = style->bParticle;
				p->color2[3] = style->aParticle;
			}
			else
			{
				p->type     = style->type;
				p->gravity  = style->gravity;				
				p->color[0] = style->rParticle;
				p->color[1] = style->gParticle;
				p->color[2] = style->bParticle;
				p->color[3] = style->aParticle;
			}

			p->rooted   = false;
		}
	}
}

void MiniGameSandBox::Digging(const vec2I& pos)
{
	//挖除粒子
	int brushSizeSq = m_brushSize*m_brushSize;
	int minX = max(0,pos.x-m_brushSize);
	int maxX = min(Size.x-1,pos.x+m_brushSize);
	int minY = max(0,pos.y-m_brushSize);
	int maxY = min(Size.y-1,pos.y+m_brushSize);

	if(m_brushShape==BT_Line)
	{
		minX = 0;
		maxX = Size.x-1;
		minY = pos.y;
		maxY = pos.y;
	}

	int minSparse = min(0,1-m_brushSparse);
	int maxSparse = max(0,m_brushSparse-1);

	unsigned char BackColor[4] ={m_backColor.r*255,m_backColor.g*255,m_backColor.b*255,m_backColor.a*255};

	//
	Particle* p;
	int rx,ry;
	for (int y=minY;y<=maxY;y+=m_brushSparse)
	{
		for (int x=minX;x<=maxX;x+=m_brushSparse)
		{
			if (m_brushSparseRand)
			{
				ry = y + RandRange(minSparse,maxSparse);
				rx = x + RandRange(minSparse,maxSparse);
			}
			else
			{
				ry = y;
				rx = x;
			}

			if( rx<minX || rx>maxX || ry<minY || ry>maxY)
				continue;
			if (m_brushShape==BT_Circle)
			{
				float difx = rx-pos.x;
				float dify = ry-pos.y;
				if( difx*difx + dify*dify > brushSizeSq)
					continue;
			}

			p = &m_particles[ry*Size.x + rx];

			p->type     = PT_Null;
			p->gravity  = true;
			p->color[0] = BackColor[0];
			p->color[1] = BackColor[1];
			p->color[2] = BackColor[2];
			p->color[3] = BackColor[3];

			p->type2     = PT_Null;
			p->gravity2  = true;
			p->color2[0] = BackColor[0];
			p->color2[1] = BackColor[1];
			p->color2[2] = BackColor[2];
			p->color2[3] = BackColor[3];
		}
	}
}
void MiniGameSandBox::UpdateParticle()
{
	unsigned char BackColor[4] ={m_backColor.r*255,m_backColor.g*255,m_backColor.b*255,m_backColor.a*255};

	//
	const Particle* End = m_particles+Size.x*Size.y;
	for(Particle* p=m_particles; p!=End; ++p)
	{
	//	p->flag    = 0;		
		p->rooted  = false;
	}

	//
	const int LineNum  = Size.y;
	const int SizeX2a1 = Size.x*2 + 1;
	const int SizeX2_1 = Size.x*2 - 1;

	Particle* lineBegin = m_particles;
	Particle* lineEnd   = m_particles + Size.x;
	int       step      = 1;
	if (particleMove==PM_Left)
	{
		lineBegin = m_particles + Size.x - 1;
		lineEnd   = m_particles - 1;
		step      = -1;
	}

	Particle* n;	
	ParticleStyle* style;
	//(偶数行从左向右遍历  奇数行从右向左遍历,避免沙子向一侧堆时)
	//for(Particle* p=m_particles; p!=End; ++p)
	for(int _i=0; _i<LineNum;++_i)
	{
		for(Particle* p=lineBegin; p!=lineEnd; p+=step)
		{
			//style = &Styles[p->type];

			//layer2
			if (p->type2 == PT_Tree) //树叶粒子 穿透其它粒子和相框底部  附着树根和其它树叶
			{
				if (/*p->flag==0 && */p->gravity2)
				{
					n = p->neighbour[DOWN];
					if (n &&(n->type==PT_Root || (n->type2==PT_Tree&&n->rooted==true)))  
					{
						p->rooted = true;
					}
					n = p->neighbour[DOWNLEFT];
					if (n && (n->type==PT_Root || (n->type2==PT_Tree&&n->rooted==true)))  
					{
						p->rooted = true;
					}
					n = p->neighbour[DOWNRIGHT];
					if (n && (n->type==PT_Root || (n->type2==PT_Tree&&n->rooted==true)))  
					{
						p->rooted = true;
					}			

					if(p->rooted==false)
					{
						//move down
						n = p->neighbour[DOWN];
						if (n==NULL)
						{
							p->type2     = PT_Null;	//漏出底部边框
							p->gravity2  = true;			
							p->color2[0] = BackColor[0];
							p->color2[1] = BackColor[1];
							p->color2[2] = BackColor[2];
							p->color2[3] = BackColor[3];
						}
						else
						{
							n->type2     = p->type2;	//重叠下面的粒子
							n->gravity2  = p->gravity2;
							n->color2[0] = p->color2[0];
							n->color2[1] = p->color2[1];
							n->color2[2] = p->color2[2];
							p->color2[3] = p->color2[3];
							//n->flag     = 1;

							p->type2     = PT_Null;	
							p->gravity2  = true;
							p->color2[0] = BackColor[0];
							p->color2[1] = BackColor[1];
							p->color2[2] = BackColor[2];
							p->color2[3] = BackColor[3];
							p->flag = 0;
						}
					}
				}
			}

			//layer1
			{
				if (/*p->flag==0 && */p->type!=PT_Null && p->gravity)
				{
					n = NULL;

					if ( p->neighbour[DOWN] 
					     && p->neighbour[DOWN]->type==PT_Null
					)  //密度轻挤占
					{
						n = p->neighbour[DOWN];
					}
					else
					{
						//if (p->particleMove==PM_Left) //此处改变顺序, 无法改变优先移动方向 ,决定因素是x轴的遍历顺序
						//{
							if (p->neighbour[DOWNLEFT] && p->neighbour[DOWNLEFT]->type==PT_Null)
							{
								n = p->neighbour[DOWNLEFT];
							}			
							else if (p->neighbour[DOWNRIGHT] && p->neighbour[DOWNRIGHT]->type==PT_Null)
							{
								n = p->neighbour[DOWNRIGHT];
							}
						//}
					}

					if (n)
					{
						n->type     = p->type;
						n->gravity  = p->gravity;
						n->color[0] = p->color[0];
						n->color[1] = p->color[1];
						n->color[2] = p->color[2];
						n->color[3] = p->color[3];
						//n->flag     = 1;

						p->type     = PT_Null;	
						p->gravity  = true;				
						p->color[0] = BackColor[0];
						p->color[1] = BackColor[1];
						p->color[2] = BackColor[2];
						p->color[3] = BackColor[3];
						p->flag = 0;
					}

					//檫粒子
					if (p->type == PT_Erase)
					{
						n = p->neighbour[DOWN];
						if (n==NULL)
						{
							p->type    = PT_Null;	//漏出底部边框
							p->gravity = true;
						}
						else if(n->type!=PT_Null && n->type!=PT_Erase)
						{
							n->type    = PT_Null;	//檫除自己和下面的粒子,可以檫除树根 塌陷树木 不能直接檫除第二层的树叶, todo 不是立即檫除
							n->gravity = true;
							p->type    = PT_Null;	
							p->gravity = true;
						}
					}

				}
			}
		}

		if (particleMove==PM_Down)
		{
			//交换方向
			if (step==1)
			{
				lineBegin += SizeX2_1;
				lineEnd   -= 1;		
				step = -1;
			}
			else
			{
				lineBegin += 1;
				lineEnd   += SizeX2a1;		
				step = 1;
			}
		}
		else
		{
			lineBegin += Size.x;
			lineEnd   += Size.x;		
		}

	}
}

void MiniGameSandBox::MapTarget()
{
	unsigned char* color;
	unsigned char* pixel = m_texTarget->GetImageData();
	const Particle* End  = m_particles+Size.x*Size.y;
	for(Particle* p=m_particles; p!=End; ++p,pixel+=4)
	{
		if (p->type2!=PT_Null)
		{
			pixel[0] = p->color2[0];
			pixel[1] = p->color2[1];
			pixel[2] = p->color2[2];
			pixel[3] = p->color2[3];
		}
		else
		{
			pixel[0] = p->color[0];
			pixel[1] = p->color[1];
			pixel[2] = p->color[2];
			pixel[3] = p->color[3];
		}
	}


	//画笔
	if (m_brushPos.x>=0&&m_brushPos.x<Size.x
		&&m_brushPos.y>=0&&m_brushPos.y<Size.y)
	{
		int minX = max(0,m_brushPos.x-m_brushSize);
		int maxX = min(Size.x-1,m_brushPos.x+m_brushSize);
		int minY = max(0,m_brushPos.y-m_brushSize);
		int maxY = min(Size.y-1,m_brushPos.y+m_brushSize);

		Color color(1,1,1,1);
		if(m_brushShape==BT_Circle)
		{
			m_texTarget->Circle(m_brushPos.x,m_brushPos.y,m_brushSize,m_brushSize,1,color);
		}
		else if(m_brushShape==BT_Square)
		{
			m_texTarget->Line(minX,minY,maxX,minY,1,color);
			m_texTarget->Line(minX,minY,minX,maxY,1,color);
			m_texTarget->Line(maxX,maxY,maxX,minY,1,color);
			m_texTarget->Line(maxX,maxY,minX,maxY,1,color);
		}		
		else if(m_brushShape==BT_Line)
		{
			m_texTarget->Line(0,m_brushPos.y,Size.x,m_brushPos.y,1,color);
		}
	}

	m_texTarget->RefreshFromData(m_texTarget->GetImageData(),RS_RGBA);
}

bool MiniGameSandBox::Free()
{
	MiniGame::Free();
	m_texTarget = NULL;
	SafeDeleteArray(m_particles);
	return true;
}

bool MiniGameSandBox::IsEnd()
{
	return m_gameState == MS_End;
}

int  MiniGameSandBox::ProcessPacketCmd(PacketBase* packet)
{
	int cmd;
	packet->ReadValue(cmd);
	switch(cmd)
	{
	case CMD_ManMove:
		break;
	case CMD_GameOver:
		break;
	case CMD_Restart:
	//	Free();
	//	Start();
		break;
	}
	return 0;
}

vec2I MiniGameSandBox::ScreenToTarget(const vec2 &pos_)
{
	vec2 pos(pos_);
	pos -= m_canvasRect.GetPos();
	pos = pos / m_canvasRect.GetExtent();
	pos.y = 1 - pos.y;
	pos.x *= Size.x;				
	pos.y *= Size.y;
	return vec2I(pos.x,pos.y);
}

MiniGameSandBox::ParticleStyle* MiniGameSandBox::RandParticle()
{
	ParticleStyle* style;
	if (WeightAll==0)
	{
		return NULL;
	}
	int weight = (Rand()%WeightAll) + 1;

	for (int i=0;i<PT_Max;i++)
	{	
		style = &Styles[i];
		if (style->active)
		{
			weight -= style->weight;
			if (weight <=0)
			{
				return style;
			}
		}
	}
	return &Styles[0];
}

void MiniGameSandBox::FreshWeightAll()
{
	ParticleStyle* style;
	WeightAll = 0;
	for (int i=0;i<PT_Max;i++)
	{	
		style = &Styles[i];
		if (style->active)
		{
			WeightAll += style->weight;
		}
	}
}

MiniGameSandBox::ParticleStyle::ParticleStyle()
{
	type = PT_Null;
	SetColor(Color(230/255.0f, 170/255.0f, 20/255.0f, 1),0.07f);
	sMin = 0.3f;
	sMax = 0.6f;
	lMin = 0.1f;
	lMax = 0.5f;
	hSpeedBatch = 0.02f;
	sSpeedBatch = 0.08f;
	lSpeedBatch = 0.08f;           //批次间变色
	hSpeedParticle = 0.005f;
	sSpeedParticle = 0.01f;
	lSpeedParticle = 0.01f;        //批次内变色

	active = false;
	weight = 1;
	particleHSL  = hSpeedParticle>0 || sSpeedParticle>0 || lSpeedParticle>0;
}

void MiniGameSandBox::ParticleStyle::SetColor(const Color& color,float hRange)
{
	rgb2hsl(color.r,color.g,color.b,h,s,l);

	hMin = h - hRange;
	hMax = h + hRange;

	Clamp(hMin,0.0f,1.0f);
	Clamp(sMin,0.0f,1.0f);
}

void MiniGameSandBox::ParticleStyle::FreshBatchColor()
{
	h += RandRange(-1.0f,1.0f)*hSpeedBatch;//批次间变色
	s += RandRange(-1.0f,1.0f)*sSpeedBatch;
	l += RandRange(-1.0f,1.0f)*lSpeedBatch;

	Clamp(h,hMin,hMax);
	Clamp(s,sMin,sMax);
	Clamp(l,lMin,lMax);

	hsl2rgb(h,s,l,r,g,b);
	r *=255;
	g *=255;
	b *=255;

	hParticle = h;//批次内变色
	sParticle = s;
	lParticle = l;
	rParticle = r;
	gParticle = g;
	bParticle = b;
	aParticle = 255;
}

void MiniGameSandBox::ParticleStyle::FreshParticleColor()
{
	hParticle += RandRange(-1.0f,1.0f)*hSpeedParticle;//批次内变色
	sParticle += RandRange(-1.0f,1.0f)*sSpeedParticle;
	lParticle += RandRange(-1.0f,1.0f)*lSpeedParticle;
	Clamp(hParticle,hMin,hMax);
	Clamp(sParticle,sMin,sMax);
	Clamp(lParticle,lMin,lMax);
	hsl2rgb(hParticle,sParticle,lParticle,rParticle,gParticle,bParticle);
	rParticle *=255;
	gParticle *=255;
	bParticle *=255;
	//aParticle = 255;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
applet模拟器码是指一种用来模拟运行Java applet程序的代码,其主要功能是将Java applet程序在普通计算机上运行,并模拟出类似于浏览器的显示环境。 applet模拟器码的实现方式可以根据具体需求和平台来选择,下面是一种常见的实现方式: 1. 创建一个Java类,命名为AppletSimulator,作为applet模拟器的主类。 2. 在主类中定义必要的属性和方法,包括模拟器的窗口、布、鼠标事件等。 3. 在主类的构造方法中初始化窗口和布,并设置相关的事件监听器。 4. 在主类中定义加载applet程序的方法loadApplet,该方法参数为applet程序的URL地址。 5. 在loadApplet方法中,使用NetBeans等工具进行Java applet程序代码的编译和加载。 6. 在主类中重写paint方法,将applet程序的内容绘制到模拟器布上。 7. 在主类中处理鼠标事件,根据事件类型执行相应的操作,如点击、拖拽等。 8. 在主类中定义启动方法start,用来启动applet模拟器,将窗口可见并进入事件监听状态。 通过以上步骤,我们可以实现一个简单的applet模拟器码。使用该码,我们可以在普通计算机上模拟运行Java applet程序,测试和验证其功能和效果。当然,根据实际需求,我们还可以进一步丰富和完善applet模拟器的功能,例如增加键盘事件、支持多线程等。 注意:以上只是一种简单的实现方式,实际的applet模拟器码可能还需要根据具体需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值