9日,醒来有点早,继续热水饺。
这是个3D版的大鱼吃小鱼游戏,可以骑着一条大鱼去吃比自己小的鱼,还是相同的小游戏架构,可以嵌入RPG中做为任务。游戏场景同样是随机生成的,鱼群的游动有flocking的效果。.
如果碰到比自己大的鱼会被吃掉
这次场景的随机生成使用的是marching cube算法,不像普通高度地形的单层效果,marching cube可以做出溶洞的效果。先生成随机的高度图来挖出溶洞的主体,再配合迷宫算法挖出细小的通道。溶洞山石的纹理展开是先使用大致的map,然后再使用类似布料的弹簧质点做拉伸。
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/FishEat/MiniGameFish.h
// @Brief: MiniGameFish
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#ifndef __MiniGameFish__H__
#define __MiniGameFish__H__
#include "Rpg/MiniGame.h"
enum FishSize;
class FishEntity;
class FishFlock;
class FishRole;
enum MiniFishCmd
{
CMD_PlayerMove,
CMD_FishMove ,
CMD_EatFish ,
CMD_GameOver ,
CMD_Restart ,
};
const char* FishCmdToString(int enumeration);
//随机生成地图
class MarchingCubeSys;
namespace RendSys
{
class Mesh;
};
class FishScene
{
public:
FishScene();
~FishScene();
void Free();
//倒置溶洞的室内场景
void GenRacingRoad2();
//穿山隧道的室外场景
void GenRacingRoad3();
void Render();
void SaveToCollide(RendSys::Mesh* mesh);
//
TexturePtr m_texture;
MarchingCubeSys* m_marchingCubeSys;
};
//水下 雾比较大 有光线刻蚀 有气泡和扭曲 岩壁碰撞
class MiniGameFish:public MiniGame
{
public:
MiniGameFish();
virtual~MiniGameFish();
virtual bool Start();
virtual bool Stop();
virtual bool Render();
virtual void RenderUI();
virtual bool Update();
virtual bool Free();
virtual bool KeepResource(bool once,int& circle,String& nextTip);
//三种类型结构
virtual MiniPlayer* CreatePlayer();
virtual MiniPlayer* CreateRobot ();
virtual MiniPlayer* CreateRole ();
//处理游戏网络命令包
virtual int ProcessPacketCmd(PacketBase* packet);
//virtual const char* CmdToString(const char* stream,int len);
RectF m_groundRect;
//todo fish flock
static const int AIFISHNUM = 15;
FishEntity* m_fishEntitys[AIFISHNUM];
FishRole* m_myRolePlayer;
#define MaxFlocks 32
FishFlock* m_fishFlocks[MaxFlocks];
};
extern MiniGameFish* G_FishGame;
#endif
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/FishEat/MiniGameFish.cpp
// @Brief: MiniGameFish
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#include "General/Pch.h"
#include "General/General.h"
#include "General/StringUtil.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "AI/Navigation/SteeringSystem.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "MiniGameFish.h"
#include "Render/Camera.h"
#include "Render/Font.h"
#include "Render/RendDriver.h"
#include "Render/SceneMgr.h"
#include "Render/Water.h"
#include "Rpg/SyncGameInfo.h"
#include "Rpg/RpgGame.h"
#include "Sound/SoundListener.h"
#include "Sound/SoundManager.h"
#include "FishEat/FishEntity.h"
#include "FishEat/FishCharacter.h"
#include "FishEat/MiFishEat_PlayGui.h"
#include "Render/FishFlock.h"
#include "FishCharacter.h"
#include "Net/PacketList.h"
#include "Render/Shader.h"
#include "Render/Terrain.h"
#include "Render/Maze.h"
#include "Math/MarchingCubes.h"
#include "Render/MC_Misc.h"
#include "General/Pce.h"
#define InWaterDis 1
#define UndeadTime 4
MiniGameFish* G_FishGame;
//关于镜头://摄像机tarpos 1驾驶员
class CameraCtrlerFishing: public CameraCtrlerTarget
{
public:
CameraCtrlerFishing();
virtual void Update();
Mode mode;
};
CameraCtrlerFishing::CameraCtrlerFishing()
:mode(ThirdPerson)
{
m_distToTar = 70;
}
void CameraCtrlerFishing::Update()
{
if(G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
if(G_Keyboard->IsKeyUping(DIK_V))
{
mode = (mode==FirstPerson)?ThirdPerson:FirstPerson;
}
}
if (G_FishGame==NULL)
{
m_toBeRemove = true;
return;
}
FishCharacter* role = G_FishGame->m_myRolePlayer;
if (role)
{
Camera* camera = G_Camera;
//if (mode==FirstPerson)
//{
// vec3 tarPos = role->GetPos();
// vec3 head = role->m_rot*vec3(0,0,1);//car->GetHeading();
// float DisWheelH = role->GetStyle()->DisWheelH;
// camera->SetTarPos(tarPos+head*(DisWheelH*0.5f));
// vec3 right = role->m_rot*vec3(-1,0,0);//car->GetHeadingRight();
// camera->SetDir(head,Cross(right,head));
// m_distToTar = 0.1f;//car->GetStyle()->DisWheelH*0.5f;
// camera->SetEyePos(tarPos - head*m_distToTar);
//}
//else
{
//CheckMouseRot(MOUSE_RIGHT, 10, -HALFPI * 0.2f, HALFPI * 0.2f);
CheckWheelDis(50,500);
vec3 head = role->GetHeading();
head.y = -0.5f;
head.Normalize();
vec3 up = head.Cross(vec3(0,1,0)).Cross(head);
up.Normalize();
camera->SetDir(head,up);
vec3 tarPos = role->GetPos();
SetTarPos(tarPos);
camera->SetEyePos(tarPos - camera->GetHeadDir()*m_distToTar);
}
CheckSceneCollide(G_FishGame->m_movieCollide);
//CheckSceneCollide(G_RpgMap->GetCollideMovie());
}
}
//==================^_^==================^_^==================^_^==================^_^
const char* FishCmdToString(int enumeration)
{
switch(enumeration)
{
case CMD_PlayerMove:return "CMD_PlayerMove";
case CMD_FishMove :return "CMD_FishMove ";
case CMD_EatFish :return "CMD_EatFish ";
case CMD_GameOver :return "CMD_GameOver ";
case CMD_Restart :return "CMD_Restart ";
default :return "CMD_unknow";
}
return "CMD_unknow";
}
FishScene G_FishScene;
MiniGameFish::MiniGameFish()
{
G_FishGame = this;
CmdEnumToString = FishCmdToString;
for (int i=0;i<AIFISHNUM;i++)
{
m_fishEntitys[i] = NULL;
}
}
MiniGameFish::~MiniGameFish()
{
MiniGameFish::Free();
G_FishGame = NULL;
}
bool MiniGameFish::Start()
{
m_myRolePlayer = NULL;
if(!MiniGame::Start())
return false;
if (m_movieScene == NULL)
{
LoadConfig loader(LoadConfig::GenDonotReShrinkBound,true,true);
m_movieScene = new RendSys::MovieClip;
m_movieScene->LoadFromFile("data/minigame/fisheat/scene.movie",&loader);
Frame frame;
frame.SetPos(m_startPos);
m_movieScene->SetProgramFrame(&frame);
m_movieScene->Advance();
}
if (m_movieCollide == NULL)
{
m_movieCollide = new RendSys::MovieClip;
}
Frame frame;
frame.SetPos(m_startPos);
if (0)
{
LoadConfig loader(LoadConfig::GenReShrinkBound,false,false);
m_movieCollide = new RendSys::MovieClip;
m_movieCollide->LoadFromFile("data/minigame/fisheat/scene_collide.movie",&loader);
m_movieCollide->SetProgramFrame(&frame);
m_movieCollide->Advance();
}
else
{
//随机生成
G_FishScene.GenRacingRoad2();
//rand Collide
LoadConfig loader(LoadConfig::GenDonotReShrinkBound,false,false);
m_movieCollide->LoadFromFile("data/MiniGame/Racing/collide.movie",&loader);
MovieClip* movie = m_movieCollide->GetMovieClip("scene");
if (movie)
{
Mesh* mesh = movie->GetMesh();
G_FishScene.SaveToCollide(mesh);
}
frame.SetPos(vec3(m_startPos.x,m_startPos.y - 70,m_startPos.z));
m_movieCollide->SetProgramFrame(&frame);
m_movieCollide->Advance();
}
m_deadAccumeTime = 0;
float width__ = G_Window->m_iWidth;
float height_ = G_Window->m_iHeight;
SetBoardRect(RectF((G_Window->m_iWidth-width__)/2,(G_Window->m_iHeight-height_)/2,width__,height_),
RectF(m_startPos.x-50,m_startPos.z-50,100,100),
m_startPos.y+0.1f);
FishStyle* fishStyle = G_StyleMgr->GetStyle<FishStyle>(20001);
//FISH 1~9
int level = G_MyRole->m_fishLevel;
if (level>6)
{
level = 6;
}
bool bBigFish = false;
for (int i=0;i<AIFISHNUM;i++)
{
if (m_fishEntitys[i]==NULL)
{
m_fishEntitys[i] = new FishEntity;
}
m_fishEntitys[i]->m_hideAccumeTime = RandRange(1.0f,3.0f);
m_fishEntitys[i]->m_fishSize = (FishSize)((RandRange(1,100)%3)+1);
switch(m_fishEntitys[i]->m_fishSize)
{
case FS_SMALL:
fishStyle = G_StyleMgr->GetStyle<FishStyle>(20001+level);
m_fishEntitys[i]->SetStyle(fishStyle);
m_fishEntitys[i]->GetRenderCharacter()->SetScale(vec3(fishStyle->scale,fishStyle->scale,fishStyle->scale)*0.7f);
break;
case FS_MIDDLE:
fishStyle = G_StyleMgr->GetStyle<FishStyle>(20001+level+1);
m_fishEntitys[i]->SetStyle(fishStyle);
m_fishEntitys[i]->GetRenderCharacter()->SetScale(vec3(fishStyle->scale,fishStyle->scale,fishStyle->scale)*1.2f);
break;
case FS_BIG:
fishStyle = G_StyleMgr->GetStyle<FishStyle>(20001+level+2);
m_fishEntitys[i]->SetStyle(fishStyle);
m_fishEntitys[i]->GetRenderCharacter()->SetScale(vec3(fishStyle->scale,fishStyle->scale,fishStyle->scale)*2.0f);
break;
}
}
vec3 pos;
float groundSize = BoardRect3D.width;
for (int i=0;i<AIFISHNUM;i++)
{
pos = m_startPos+vec3(RandRange(-groundSize,groundSize),5,RandRange(-groundSize,groundSize));
m_fishEntitys[i]->SetPos(pos);
m_fishEntitys[i]->m_homePos = pos;
//m_fishEntitys[i]->SetHeading(head);
}
//
for (int i = 0; i < MaxFlocks; i++)
{
m_fishFlocks[i] = new FishFlock();
m_fishFlocks[i]->Init(RandRange(8,30),10,
m_startPos+vec3(RandRange(-300,300),5,RandRange(-300,300)),
vec3(300,50,300));
}
for (int i = 0; i < MaxFlocks; i++)
{
m_fishFlocks[i]->m_enemyFlock = m_fishFlocks[(i+1)%MaxFlocks];
}
//==================^_^
for (int i=0;i<m_allPlayerNum;i++)
{
FishCharacter* thePlayer = (FishCharacter*)m_miniPlayer[i];
//SetStyle
FishStyle* style = G_StyleMgr->GetStyle<FishStyle>(20001);//90001+i);
if (style==NULL)
{
return false;
}
thePlayer->SetStyle(style);
//InitPos
FishRobot* theRobot = dynamic_cast<FishRobot*>(thePlayer);
FishRole* theRole = dynamic_cast<FishRole*>(thePlayer);
vec3 pos = m_startPos+0.5f*vec3(RandRange(-groundSize,groundSize),5,RandRange(-groundSize,groundSize));
thePlayer->SetPos(pos);
if (theRole)
{
theRole->SetWorkingWithAI(false);
theRole->m_homePos = pos;
}
else if (theRobot)
{
theRobot->SetWorkingWithAI(true);
theRobot->m_homePos = pos;
}
{
thePlayer->m_driver = new FishDriver;
Style* style = G_StyleMgr->GetStyle(thePlayer->GetPlayerInfo()->style);
thePlayer->m_driver->SetStyle(style);
thePlayer->m_driver->GetRenderCharacter()->SetScale(vec3(1.2f,1.2f,1.2f));
thePlayer->m_driver->GetRenderCharacter()->PlayAnim("drive");
}
}
//进入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();
}
//设置摄像机
CameraCtrlerFishing* ctrler = new CameraCtrlerFishing;
ctrler->SetDistToTar(300);
ctrler->SetTarPos(m_startPos);
G_Camera->PushCtrler(ctrler);
G_Camera->SetEuler(0, -30, 0);
//片头摄像机
PushIntroCamera();
G_MyRole->SetExternState(new CharacterState);
return true;
}
MiniPlayer* MiniGameFish::CreatePlayer()
{
return new FishCharacter;
}
MiniPlayer* MiniGameFish::CreateRobot()
{
return new FishRobot;
}
MiniPlayer* MiniGameFish::CreateRole()
{
m_myRolePlayer = new FishRole;
return m_myRolePlayer;
}
bool MiniGameFish::Stop()
{
G_MyRole->SetExternState(NULL);
G_MyRole->GetRenderCharacter()->SetScale(vec3(2.0f,2.0f,2.0f));
G_GuiMgr->PopGui("MiFishEat_PlayGui");
{
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);
}
MiniGame::Stop();
return true;
}
bool MiniGameFish::Render()
{
PROFILEFUN("MiniGameFish::Render();",0.0f,ALWAYSHIDE);
G_RendDriver->SetFogParms(Color(0.2f,0.9f,0.3f,1),50,500);
if (G_ShaderMgr&& G_ShaderMgr->m_curEffect)
{
G_ShaderMgr->MapChangeParm();
}
G_RendDriver->EnableRendState(RS_LIGHTING);
G_RendDriver->PushMatrix();
G_RendDriver->Translatef(m_startPos.x,m_startPos.y - 70,m_startPos.z);
G_FishScene.Render();
G_RendDriver->PopMatrix();
for (int i = 0; i < MaxFlocks; i++)
{
m_fishFlocks[i]->Render();
}
for (int i=0;i<AIFISHNUM;i++)
{
m_fishEntitys[i]->Render();
}
for (int i=0;i<m_allPlayerNum;i++)
{
FishCharacter* fish = dynamic_cast<FishCharacter*>(m_miniPlayer[i]);
fish->Render();
if(fish->m_driver)
fish->m_driver->Render();
}
if (m_movieScene)
{
m_movieScene->RendClip();
}
return true;
}
void MiniGameFish::RenderUI()
{
MiniGame::RenderUI();
/
G_RendDriver->BeginUI();
G_FontMgr->GetFontDesc().backStyle = FB_RECT;
G_FontMgr->GetFontDesc().backColor = Color(0.2f,0.3f,1.0f,0.6f);
char buf[256];
//得分:%d
sprintf(buf,TextData::GetText("T_PVB_TIP_04" ),m_myPlayer->m_score);
G_FontMgr->TextAtPos(vec2(200, 200),buf);
//剩余生命:%d
sprintf(buf,TextData::GetText("T_RACING_TIP_03" ),m_myPlayer->m_liveNum);
G_FontMgr->TextAtPos(vec2(200, 230),buf);
G_FontMgr->GetFontDesc().backStyle = FB_NULL;
}
bool MiniGameFish::Update()
{
PROFILEFUN("MiniGameFish::Update();",0.0f,ALWAYSHIDE);
MiniGame::Update();
for (int i = 0; i < MaxFlocks; i++)
{
m_fishFlocks[i]->Update();
}
for (int i=0;i<AIFISHNUM;i++)
{
m_fishEntitys[i]->Update();
}
for (int i=0;i<m_allPlayerNum;i++)
{
FishCharacter* fish = dynamic_cast<FishCharacter*>(m_miniPlayer[i]);
fish->Update();
}
return true;
}
bool MiniGameFish::Free()
{
MiniGame::Free();
for (int i = 0; i < MaxFlocks; i++)
{
delete m_fishFlocks[i];
}
for (int i=0;i<AIFISHNUM;i++)
{
SafeDelete(m_fishEntitys[i]);
}
return true;
}
bool MiniGameFish::KeepResource(bool once,int& circle,String& nextTip)
{
static bool LoadedStyles = false;
if (LoadedStyles==false)
{
/* fish20001~
*/
LoadedStyles = true;
G_StyleMgr->LoadStyles<FishStyle>("data/Logic/Style/Fish.style",Enum_Style(FishStyle));
}
//keep fish
{
PROFILEFUN("MiniGameFish::KeepResource(bool once,int& circle,String& nextTip);",0.0f,ALWAYSHIDE);
StyleGroupRef styles(Enum_Style(FishStyle));
FishStyle* it = (FishStyle*)styles.GetFirst();
while (it)
{
//Log::LogStr((*it).modelName);
G_MovieClipMgr->KeepMovie((*it).modelName);
G_RpgMap->KeepBoneStyle((*it).boneStyle);
it = (FishStyle*)styles.GetNext();
}
}
return true;
}
int MiniGameFish::ProcessPacketCmd(PacketBase* packet)
{
int cmd;
packet->ReadValue(cmd);
switch(cmd)
{
case CMD_PlayerMove:
{
int slot = 0;
vec3 pos;
vec3 speed;
packet->ReadValue(slot);
packet->ReadValue(pos);
packet->ReadValue(speed);
FishCharacter* thePlayer = (FishCharacter*)GetPlayerFromSlot(slot);
thePlayer->SetPos(pos);
thePlayer->SetSpeed(speed);
}
break;
case CMD_FishMove:
{
int slot = 0;
vec3 pos;
vec3 speed;
packet->ReadValue(slot);
packet->ReadValue(pos);
packet->ReadValue(speed);
FishCharacter* thePlayer = (FishCharacter*)GetPlayerFromSlot(slot);
thePlayer->SetPos(pos);
thePlayer->SetSpeed(speed);
}
break;
case CMD_EatFish:
{
int slot = 0;
int bEaten;
int fishID;
packet->ReadValue(slot);
packet->ReadValue(bEaten);
packet->ReadValue(fishID);
FishCharacter* thePlayer = (FishCharacter*)GetPlayerFromSlot(slot);
if (bEaten)
{
// thePlayer->SetSpeed(speed);
}
else
{
//thePlayer->SetSpeed(speed);
}
}
break;
case CMD_GameOver:
break;
case CMD_Restart:
break;
}
return 0;
}
FishScene::FishScene()
:m_marchingCubeSys(NULL)
{
}
FishScene::~FishScene()
{
Free();
}
void FishScene::Free()
{
SafeDelete(m_marchingCubeSys);
}
void FishScene::GenRacingRoad2()
{
Free();
G_TextureMgr->AddTexture(m_texture,"data/environment/terrain/w_rock0.png");
#define CubeWALL RandRange(0.6f,1.0f) //1
#define CubeEmpty RandRange(0.1f,0.4f) //0
//地形
TerrainData terrain;
terrain.New(257,257,10,10);
terrain.FillFractSurface(0,0,500,0.5f,false,0);
//生成迷宫 宽墙窄路
Maze maze;
//maze.GeneratePrimTrunkMaze(11,11);
//maze.AdjustSpace(3,3,1,1);
//maze.RandEnterExit();
//maze.OutputMaze();
maze.GeneratePrimNatureMaze(20,20);
maze.AdjustSpace(3,3,1,1);
maze.MakeBigRoad();
maze.RandEnterExit();
maze.OutputMaze();
//拓宽假路 假路可以撑开墙壁 假路上可以摆放建筑
//todo 。。。
//将地形上抬 截断顶部 靠底部挖洞 即形成倒置溶洞的室内场景
//MarchingCubeSys 地形
m_marchingCubeSys = new MarchingCubeSys;
//vec3I voxelSize(64,64,64);
vec3I voxelSize(32,32,32);
float extendScale = 10;//5; 改变extendScale的同时marchingCube整个上下范围变了, 注意 terrain的高度也要跟着调整 否则室内室外风格就变了
m_marchingCubeSys->Init(voxelSize,vec3(voxelSize.x*extendScale*2,voxelSize.y*extendScale,voxelSize.z*extendScale*2));
m_marchingCubeSys->SetGroundPos(vec3(0,m_marchingCubeSys->m_halfGroundExtend.y/3,0)); // 1/6 在地下
m_marchingCubeSys->ClearEnergys();
int maxX = m_marchingCubeSys->EnergyGridSize.x;//-1;
int maxY = m_marchingCubeSys->EnergyGridSize.y;//-1;
int maxZ = m_marchingCubeSys->EnergyGridSize.z;//-1;
//遍历
float* energy = m_marchingCubeSys->m_gridEnergys;
float* energyZ = m_marchingCubeSys->m_gridEnergys;
vec3 pos;
const float extendX = m_marchingCubeSys->VoxelGridExtend.x;
const float extendY = m_marchingCubeSys->VoxelGridExtend.y;
const float extendZ = m_marchingCubeSys->VoxelGridExtend.z;
pos.z = 0;//m_marchingCubeSys->m_groundMin.z;
const float ScaleL2T = terrain.m_iWidth/(m_marchingCubeSys->m_halfGroundExtend.x*2.0f);//marching局部坐标变为terrain坐标
for( int z = 0; z < maxZ; z++, energyZ += m_marchingCubeSys->EnergyGridSizeXY)
{
pos.z += extendZ;
pos.x = 0;//m_marchingCubeSys->m_groundMin.x;
energy = energyZ;
for(int x = 0; x < maxX; x++ )
{
pos.x += extendX;
//pos.y = 0;//m_marchingCubeSys->m_groundMin.y;
float height = terrain.GetHeightf(pos.x*ScaleL2T,pos.z*ScaleL2T);
int heightI = (height-m_marchingCubeSys->m_groundMin.y)/extendY;
energy = energyZ + x;
int y = 0;
for( ; y < heightI && y < maxY; y++)
{
//pos.y += extendY;
*energy = CubeEmpty; //地上为实 地下为空
energy += m_marchingCubeSys->EnergyGridSize.x;
}
for( ; y < maxY; y++)
{
//pos.y += extendY;
*energy = CubeWALL;
energy += m_marchingCubeSys->EnergyGridSize.x;
}
}
}
//室内场景 一般要筑一到两面墙+天花板
{
energyZ = m_marchingCubeSys->m_gridEnergys;
{
int z = 0;
//int z = m_marchingCubeSys->EnergyGridSize.z-1;
energy = energyZ +z*m_marchingCubeSys->EnergyGridSizeXY;
for(int x = 0; x < maxX; x++ )
{
energy = energyZ + x;
for( int y = 0; y < maxY; y++)
{
*energy = CubeWALL;
energy += m_marchingCubeSys->EnergyGridSize.x;
}
}
}
energyZ = m_marchingCubeSys->m_gridEnergys;
for( int z = 0; z < maxZ; z++, energyZ += m_marchingCubeSys->EnergyGridSizeXY)
{
energy = energyZ;
int x = 0;
{
energy = energyZ + x;
for( int y = 0; y < maxY; y++)
{
*energy = CubeWALL;
energy += m_marchingCubeSys->EnergyGridSize.x;
}
}
}
//筑天花板
energyZ = m_marchingCubeSys->m_gridEnergys;
for( int z = 0; z < maxZ; z++, energyZ += m_marchingCubeSys->EnergyGridSizeXY)
{
energy = energyZ;
for(int x = 0; x < maxX; x++ )
{
energy = energyZ + x;
int y = maxY-1;
{
energy += m_marchingCubeSys->EnergyGridSize.x*y;
*energy = CubeWALL;
}
}
}
}
//地道
int by = m_marchingCubeSys->EnergyGridSize.y/2;
const int Radius = Max(m_marchingCubeSys->EnergyGridSize.x/maze.m_mazeWidth,1);
const float ScaleM2M = ((float)m_marchingCubeSys->EnergyGridSize.x)/maze.m_mazeWidth;//maze坐标变为marching坐标
for (int y = 0; y < maze.m_mazeHeight; y++)
{
for (int x = 0; x < maze.m_mazeWidth; x++)
{
if (maze.mazeBlockType(x,y)==Maze::Road)
{
int bx = x*ScaleM2M;
//int by = 32; // 64/6
int bz = y*ScaleM2M;
//m_marchingCubeSys->m_gridEnergys[(bx) +(by)*(m_marchingCubeSys->EnergyGridSize.x) +(bz)*m_marchingCubeSys->EnergyGridSizeXY] = CubeWALL;
for(int i=-Radius;i<Radius;i++)
{
int cz = bz+i;
if (cz>=0 && cz<m_marchingCubeSys->EnergyGridSize.z)
{
for(int j=-Radius;j<Radius;j++)
{
int cy = by+j;
if (cy>=0 && cy<m_marchingCubeSys->EnergyGridSize.y)
{
for(int k=-Radius;k<Radius;k++)
{
int cx = bx+k;
if (cx>=0 && cx<m_marchingCubeSys->EnergyGridSize.x)
{
m_marchingCubeSys->m_gridEnergys[(cx) +(cy)*(m_marchingCubeSys->EnergyGridSize.x) +(cz)*m_marchingCubeSys->EnergyGridSizeXY] = CubeWALL;
}
}
}
}
}
}
}
}
}
m_marchingCubeSys->Update();
}
void FishScene::GenRacingRoad3()
{
Free();
G_TextureMgr->AddTexture(m_texture,"data/environment/terrain/w_rock0.png");
//地形
TerrainData terrain;
terrain.New(257,257,10,10);
terrain.FillFractSurface(0,0,500,0.5f,false,0);
//生成迷宫 宽墙窄路
Maze maze;
//maze.GeneratePrimTrunkMaze(11,11);
//maze.AdjustSpace(3,3,1,1);
//maze.RandEnterExit();
//maze.OutputMaze();
maze.GeneratePrimNatureMaze(20,20);
maze.AdjustSpace(3,3,1,1);
maze.MakeBigRoad();
maze.RandEnterExit();
maze.OutputMaze();
//拓宽假路 假路可以撑开墙壁 假路上可以摆放建筑
//todo 。。。
//将地形下移 截断底部 靠中部挖洞 即形成穿山隧道的室外场景
//MarchingCubeSys 地形
m_marchingCubeSys = new MarchingCubeSys;
//vec3I voxelSize(64,64,64);
vec3I voxelSize(32,32,32);
float extendScale = 10;//5; 改变extendScale的同时marchingCube整个上下范围变了, 注意 terrain的高度也要跟着调整 否则室内室外风格就变了
m_marchingCubeSys->Init(voxelSize,vec3(voxelSize.x*extendScale*2,voxelSize.y*extendScale,voxelSize.z*extendScale*2));
m_marchingCubeSys->SetGroundPos(vec3(0,m_marchingCubeSys->m_halfGroundExtend.y/3,0)); // 1/6 在地下
m_marchingCubeSys->ClearEnergys();
int maxX = m_marchingCubeSys->EnergyGridSize.x;//-1;
int maxY = m_marchingCubeSys->EnergyGridSize.y;//-1;
int maxZ = m_marchingCubeSys->EnergyGridSize.z;//-1;
//遍历
float* energy = m_marchingCubeSys->m_gridEnergys;
float* energyZ = m_marchingCubeSys->m_gridEnergys;
vec3 pos;
const float extendX = m_marchingCubeSys->VoxelGridExtend.x;
const float extendY = m_marchingCubeSys->VoxelGridExtend.y;
const float extendZ = m_marchingCubeSys->VoxelGridExtend.z;
pos.z = 0;//m_marchingCubeSys->m_groundMin.z;
const float ScaleL2T = terrain.m_iWidth/(m_marchingCubeSys->m_halfGroundExtend.x*2.0f);//marching局部坐标变为terrain坐标
for( int z = 0; z < maxZ; z++, energyZ += m_marchingCubeSys->EnergyGridSizeXY)
{
pos.z += extendZ;
pos.x = 0;//m_marchingCubeSys->m_groundMin.x;
energy = energyZ;
for(int x = 0; x < maxX; x++ )
{
pos.x += extendX;
//pos.y = 0;//m_marchingCubeSys->m_groundMin.y;
float height = terrain.GetHeightf(pos.x*ScaleL2T,pos.z*ScaleL2T);
height -= 200;//地形下移
int heightI = (height-m_marchingCubeSys->m_groundMin.y)/extendY;
energy = energyZ + x;
int y = 0;
for( ; y < heightI && y < maxY; y++)
{
//pos.y += extendY;
*energy = CubeWALL; //地下为实 地上为空
energy += m_marchingCubeSys->EnergyGridSize.x;
}
for( ; y < maxY; y++)
{
//pos.y += extendY;
*energy = CubeEmpty;
energy += m_marchingCubeSys->EnergyGridSize.x;
}
}
}
{
//筑天花板 山顶非空
energyZ = m_marchingCubeSys->m_gridEnergys;
for( int z = 0; z < maxZ; z++, energyZ += m_marchingCubeSys->EnergyGridSizeXY)
{
energy = energyZ;
for(int x = 0; x < maxX; x++ )
{
energy = energyZ + x;
int y = maxY-1;
{
energy += m_marchingCubeSys->EnergyGridSize.x*y;
*energy = CubeEmpty;
}
}
}
}
//挖隧道
int by = m_marchingCubeSys->EnergyGridSize.y/3;
int Radius = Max(m_marchingCubeSys->EnergyGridSize.x/maze.m_mazeWidth,1);
int RadiusY;
const float ScaleM2M = ((float)m_marchingCubeSys->EnergyGridSize.x)/maze.m_mazeWidth;//maze坐标变为marching坐标
for (int y = 0; y < maze.m_mazeHeight; y++)
{
for (int x = 0; x < maze.m_mazeWidth; x++)
{
if (maze.mazeBlockType(x,y)==Maze::Road)
{
//靠近路中间挖的高度更大
RadiusY = Radius + maze.GetSurroundingBlocks(x, y, 2,Maze::Road)*0.2f;
int bx = x*ScaleM2M;
//int by = 32; // 64/6
int bz = y*ScaleM2M;
//m_marchingCubeSys->m_gridEnergys[(bx) +(by)*(m_marchingCubeSys->EnergyGridSize.x) +(bz)*m_marchingCubeSys->EnergyGridSizeXY] = 0;
for(int i=-Radius;i<Radius;i++)
{
int cz = bz+i;
if (cz>=0 && cz<m_marchingCubeSys->EnergyGridSize.z)
{
//上半圆挖隧道
for(int j=-RadiusY;j<0;j++)
{
int cy = by+j;
if (cy>=0 && cy<m_marchingCubeSys->EnergyGridSize.y)
{
for(int k=-Radius;k<Radius;k++)
{
int cx = bx+k;
if (cx>=0 && cx<m_marchingCubeSys->EnergyGridSize.x)
{
m_marchingCubeSys->m_gridEnergys[(cx) +(cy)*(m_marchingCubeSys->EnergyGridSize.x) +(cz)*m_marchingCubeSys->EnergyGridSizeXY] = CubeWALL;
}
}
}
}
//下半圆筑路
for(int j=0;j<RadiusY;j++)
{
int cy = by+j;
if (cy>=0 && cy<m_marchingCubeSys->EnergyGridSize.y)
{
for(int k=-Radius;k<Radius;k++)
{
int cx = bx+k;
if (cx>=0 && cx<m_marchingCubeSys->EnergyGridSize.x)
{
m_marchingCubeSys->m_gridEnergys[(cx) +(cy)*(m_marchingCubeSys->EnergyGridSize.x) +(cz)*m_marchingCubeSys->EnergyGridSizeXY] = CubeEmpty;
}
}
}
}
}
}
}
}
}
m_marchingCubeSys->RemoveChip();
m_marchingCubeSys->Update();
}
void FishScene::Render()
{
if (m_marchingCubeSys)
{
m_texture->Bind();
m_marchingCubeSys->Render();
}
}
void FishScene::SaveToCollide(RendSys::Mesh* mesh)
{
if (mesh==NULL)
return;
mesh->Free();
int vVertexNum = m_marchingCubeSys->m_vertexNum;
int tVertexNum = m_marchingCubeSys->m_vertexNum;
int trigonNum = m_marchingCubeSys->m_indexNum/3;
mesh->Resize(vVertexNum, tVertexNum, trigonNum);
Mesh::Vertex* v = mesh->m_vVertexs;
Mesh::TVertex* t = mesh->m_tVertexs;
Mesh::Trigon* tri = mesh->m_trigons;
{
MarchingCubeSys::SVertex* vb = m_marchingCubeSys->m_vertexs;
for (int j=0;j<vVertexNum;++j)
{
v->x = vb->pos[0] ;
v->y = vb->pos[1] ;
v->z = vb->pos[2] ;
v->nx = vb->normal[0] ;
v->ny = vb->normal[1] ;
v->nz = vb->normal[2] ;
t->u = vb->uvw[0] ;
t->v = vb->uvw[1] ;
t->w = vb->uvw[2] ;
v++;
vb++;
t++;
}
MarchingCubeSys::IndexInt* trib = m_marchingCubeSys->m_indexs;
for (int j=0;j<trigonNum;++j)
{
tri->vIndex[0] = trib[0] ;
tri->vIndex[1] = trib[1] ;
tri->vIndex[2] = trib[2] ;
tri+=1;
trib+=3;
}
}
//mesh->CreateBuff();//test
mesh->BuildTree();
}