流沙画,在密封的玻璃镜框内,装入氧化铝、磨刚沙、无色的混合液和适量的气泡。
当镜框倒竖时,利用氧化铝和磨刚沙的比重不同以及气泡的上浮力,使氧化铝和磨刚沙按不同速度下沉到空腔的底部,形成层次分明,跌宕有序的画面。
装入镜框的沙粒,一般有黑色、白色、蓝色(或其它颜色),另外还可能加入一些较大的黑色颗粒。
要用真实的物理模拟流沙画,需要给每个粒子赋予位置、速度等属性,使用流体动画,实现复杂,速度较慢。这里使用变通的方法,所有粒子沉降速度相同,这样粒子运动不会发生穿插,每一个像素上的粒子数量有限。利用粒子的颜色变化来模拟粒子沉积比例。
可以贴到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;
- }