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