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

可以贴到3DUI上
//几个绘制小技巧, 左键撒沙子, 右键挖除, 每种粒子都可以调色
//月亮:球形画刷+零重力 刷出圆形,右键挖出月亮。
//云层:球形画刷+稀疏度+零重力 刷出云层,右键挖出云层轮廓,蓝色粒子洒在云彩上进行描边。
//村落:方形画刷+稀疏度+零重力 刷出建筑,
//滑坡:移动倾向+右键 挖出斜向山脊
//瀑布:右键挖空,使蓝色粒子下落形成瀑布水流
//树木:先混合沙子撒少量树根,后撒树枝(棕色树叶代替),最后撒绿色树叶
//小路:同色线刷子模拟路 或普降的烟尘
//橡皮檫粒子会檫除接触到的其它粒子,树叶粒子会附着到树根粒子和其它树叶粒子。水粒子目前和沙粒子没有区别,应该具有更强的流动性。
// 可以刷在已有沙子的内部,直接替换,刷出平滑体。可以用零重力沙子托起一堆带重力的沙子,然后檫除部分零重力沙子形成下雨或水流动画。

源码:
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/SandBox/MiniGameSandBox.h
// @Brief: MiniGameSandBox
// @Author: LouLei
// @Email: [email protected]
// @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: [email protected]
// @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;
}
边栏推荐
- Yalm 100b: 100billion parameter open source large model from yandex, Russia, allowing commercial use
- Why pass SPIF_ Sendchange flag systemparametersinfo will hang?
- Oracle/PLSQL: Lower Function
- XSS attack (note)
- Flink学习5:工作原理
- Docker deploy redis cluster
- YaLM 100B:来自俄罗斯Yandex的1000亿参数开源大模型,允许商业用途
- memcached基础14
- I earned 3W yuan a month from my sideline: the industry you despise really makes money!
- Oracle/PLSQL: Lpad Function
猜你喜欢

Mmdetection uses yolox to train its own coco data set

Don't be brainwashed. This is the truth about the wages of 90% of Chinese people

达梦数据库安装

学习太极创客 — MQTT(七)MQTT 主题进阶

Is the division of each capability domain of Dama, dcmm and other data management frameworks reasonable? Is there internal logic?

Yiwen teaches you Kali information collection

Learn Tai Chi maker mqtt (IX) esp8266 subscribe to and publish mqtt messages at the same time

Flink学习5:工作原理

Svg drag dress Kitty Cat

Learning Tai Chi Maker - mqtt (VII) advanced mqtt theme
随机推荐
Flink learning 1: Introduction
Oracle/PLSQL: Length Function
Consumers pursue the iPhone because its cost performance exceeds that of domestic mobile phones
Learn Tai Chi Maker - mqtt (VI) esp8266 releases mqtt message
达梦数据库的卸载
Oracle/PLSQL: Replace Function
YaLM 100B:来自俄罗斯Yandex的1000亿参数开源大模型,允许商业用途
TechSmith Camtasia latest 2022 detailed function explanation Download
Learn from Taiji Maker - mqtt Chapter 2 (I) QoS service quality level
memcached基础12
【数组】剑指 Offer II 012. 左右两边子数组的和相等 | 剑指 Offer II 013. 二维子矩阵的和
How to solve the problem of low applet utilization
ORM cache package for laravel
Oracle/PLSQL: HexToRaw Function
Installing the Damon database using the command line
Regular expressions: Syntax
执念斩长河暑期规划
Don't be brainwashed. This is the truth about the wages of 90% of Chinese people
memcached基础11
mmdetection 用yolox训练自己的coco数据集