今天暂时不用挨饿,继续吃昨天剩下的水饺。吃哕了,写点东西缓一缓。
这是一个3D版赛车小游戏,使用的还是crapell引擎,游戏支持多人联机和自动挂机。可以单独玩,也可以嵌入RPG游戏作为一个小任务,RPG的玩家或npc来充当驾驶员角色。
游戏的赛道场景使用了随机生成方法,先配合TSP算法生成直角拐弯的迷宫,然后根据迷宫来拼接道路,关于迷宫生成算法在另一篇文章中有介绍。其实还有更好的场景生成算法,将在其它的小游戏中介绍,比如marching cube和波函数坍缩算法。
游戏的物理部分做了两种方案,第一种不用物理引擎,直接通过四个轮子的状态来解算,第二种是使用bullet引擎。没有使用自己开发的物理引擎,因为在另一个小游戏中已经模拟过,高速运动时不是太稳定。
自己做了几个赛车的模型
"合金战车", 某游戏中截取的模型,主要测试金属材质
"蜘蛛车", 八条腿的生化蜘蛛参与赛跑,腿部动画是自己随便K的帧
"汽艇车", 喷水效果,陆地上的汽艇
"坦克车", 看似多个轮子,实际还是四个轮子模型
车辙印暂时是假的,仅仅是一道刀光,车上加了布料旗子,排气管烟雾,喷水效果,氮气粒子效果都是直接从3dsmax导出即可,几乎不需要额外的配置。
有一些想法没做,比如奖励、道具。地形机关。
暂时写了一个简单的自动驾驶开车算法,以便于npc也能加入游戏,没有用到人工智能。
赛道场景随机拼接,包括两种路面,几种带过渡的墙壁,两种隧道,两种栅栏,树,草地,房子,拐弯和分岔口等模型。
截图是debug版的不要看fps。电脑坏了,这是用的十几年前的笔记本,兼容有问题,运行游戏超过半分钟就会过热关机。随便截了几张。
赛车玩家类:
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/RacingCar.h
// @Brief: RacingCar
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#ifndef __RacingCar__H__
#define __RacingCar__H__
#include "AI/Entity/LogicCharacter.h"
#include "Rpg/MiniGame.h"
//[0] = Front_L
//[1] = Front_R
//[2] = Rear_L
//[3] = Rear_R
class btVehicleTuning;
struct btVehicleRaycaster;
class btCollisionShape;
class btCompoundShape;
class btRigidBody;
class btDefaultCollisionConfiguration;
class btBroadphaseInterface;
class btCollisionDispatcher;
class btConstraintSolver;
class btDynamicsWorld;
class btTriangleIndexVertexArray;
class GL_ShapeDrawer;
class BulletAppDemo;
#include "BulletDynamics/Vehicle/btRaycastVehicle.h"
#define FitScale_ 0.1f
//赛车型号
struct CarStyle:public CharacterStyle
{
public:
DeclareStyleEnum(CarStyle ,209);
virtual bool Load(File& file);
virtual bool Save(File& file);
float Mass; //质量1
float MaxEngineForce; //后轮推力
float MaxBrakingForce; //刹车力
float TurnForce; //前轮转动力度
float MaxWheelAng; //前轮最大转角
float MoveBrakingRate; //速度正比摩擦系数
float TurnBrakingRate; //前轮转向恢系数
float BodyL,BodyW,BodyH;//长宽高
float WheelRadius[4]; //四轮半径
float DisWheelH; //前后轮距
float Bottom; //底盘高度 以车底地面为原点
vec3 WheelPos[4]; //四轮位置
vec3 driverOffset;
int WheelRotable; //动画上轮子是否转向,履带可能不转向
};
//不用了
class RoleState_Drive
{
public:
virtual void Render();
virtual void Update();
virtual void OnAnimCallBack(const char* frameName);
};
//rpg玩家做司机
class CarDriver: public LogicCharacter
{
public:
virtual void Update();
};
//赛车状态
enum RacingCarState
{
RS_None, //
RS_Forward, //闪进突破、闪避 闪进中不会和其它车碰撞
RS_BeBeaten, //被击打
RS_SuperSkill, //必杀技:todo特效绑定
RS_BeSuperSkill, //被必杀
RS_Racing, //
Rs_Reseting, //重置中 耗时 老鹰提起
RS_Show, //秀
RS_DeadRoll, //死亡翻滚
RS_Victory, //
RS_Lose, //
RS_MaxNum,
};
const char* RacingCarStateToString(int enumeration);
#define RegisterAllStateFun(ObjClass) \
RegisterStateFun(ObjClass,RS_Racing );\
RegisterStateFun(ObjClass,RS_DeadRoll );\
//todo 软性旗杆 爬坡速度
//todo 蒙皮式龙车 参考 physicdragon
class CarCharacterDragon
{
public:
};
//todo 多节列车
class CarCharacterTrain
{
public:
};
class SimRigidBody;
//两个父类中都有virtual Update,自己也必须实现
class CarCharacter: public BaseEntity, public MiniPlayer, public StateObj
{
public:
CarCharacter();
virtual ~CarCharacter();
virtual bool Start();
virtual void Free();
virtual void Update();
virtual void Render();
virtual bool SetStyle(Style* style);
virtual CarStyle* GetStyle();
virtual void OnAnimCallBack(const char* frameName);
//virtual RoleBanner* GetBanner( BannerSlot slot );
virtual void UpdateMovement();
//!着陆
virtual bool GetHeightAt (vec3& pos,float top=500,float bot=500) const;
virtual void ResetCar();
//计算路程
void CalRoadLength();
//计算路点
void CalWayPoint();
//向后开车
bool IsWrongDir();
<<状态
//DeclareStateFun(GS_None );
DeclareStateFun(RS_Racing );
DeclareStateFun(RS_DeadRoll );
//typedef StateClass<CarCharacter,RS_MaxNum> ThisStateClass;
typedef bool (CarCharacter::*StateFun)();
static StateFun m_stateFun[RS_MaxNum][StateFun_Num];
virtual bool RouteCallStateFun(int state,StateFunType fun);
virtual bool TryChangeState(RacingCarState state);
bool m_stateSwitch[RS_MaxNum];
>>
void SendCmdMove();
void SendCmdCarDeadRoll();
void SetPosHeading(const vec3& pos,const vec3& heading);
void SetPosEuler (const vec3& pos,const vec3& rot);
void SetTransform (const vec3& pos,const mat3& rot);
void SetSpeed( const vec3& lineVelocity ,const vec3& angVelocity);
vec3& GetSpeed();
//!方向
vec3 GetHeading() const;
void Jump();
//车体
RenderCharacter* m_renderCharacter;
//车轮 车轮用骨骼动画暂时无法改变半径 需要重定向 使用关键帧动画则攻击死亡动作无法统一
//或者两种车模型动画美术都做一遍
RendSys::MovieClip* m_movieWheels[4];
//车轮印
RendSys::MovieClip* m_movieSteps[2];
//氮气
RendSys::MovieClip* m_movieLight;
//驾驶员
LogicCharacter* m_driver;
float m_accumTime;
bool m_bJumpping;
vec3 m_massCenter;
vec3 m_massCenterGround;
vec3 m_lineVelocity;
vec3 m_angVelocity;
//!动画朝向
vec3 m_heading;
mat3 m_rot;
vec3 m_wheelPos[4];
vec3 m_wheelGroundPos[4];
vec3 m_wheelSpeed[4];
float m_engineForce; //牵引力
float m_breakingForce; //刹车力
float m_wheelAng; //转角
//#define MethodFourWheel
#define MethodPhyBullet
#define PHYSCALE 1
//方案一 四点法
#ifdef MethodFourWheel
#endif
//方案二
#ifdef MethodPhyBullet
///notice that for higher-quality slow-moving vehicles, another approach might be better
///implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
void EditRender(int debugMode);
btRigidBody* m_carBody;
btRaycastVehicle* m_vehicle;
btRaycastVehicle::btVehicleTuning m_tuning;
btVehicleRaycaster* m_vehicleRayCaster;
btDynamicsWorld* m_dynamicsWorld;
GL_ShapeDrawer* m_shapeDrawer;
btCompoundShape* m_compoundShape;
btCollisionShape* m_chassisShape;
btCollisionShape* m_wheelShape;
btVector3* m_vertices;
btTriangleIndexVertexArray* m_indexVertexArrays;
#endif
//整数部分是已经完成的圈数 完成一圈时roadlength为1
float m_roadLength;
int m_nextWayPoint;
int m_lastWayPoint;
vec3 m_nextWayPointPos;
vec3 m_lastWayPointPos;
float m_wrongWayTime;
float m_energy;
mat4 m_deadRotMat;
vec3 m_deadRotRad;
Regulator* m_regulator;
SoundChannel3D* m_sound;
//重量转换Weight Transfer 向路面低的一方产生向心力 下坡时速度加快 漂移时重心升高减速
//四个轮胎处的地面高度 传递力 或直接计算旋转矩阵
};
#endif
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/RacingCar.cpp
// @Brief: RacingCar
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#include "General/Pch.h"
#include "General/File.h"
#include "General/General.h"
#include "General/Regulator.h"
#include "General/Timer.h"
#include "Math/MathLibAdvance.h"
#include "AI/Navigation/SteeringSystem.h"
#include "CarRacing/MiniGameRacing.h"
#include "CarRacing/CarCharacter.h"
#include "CarRacing/CarRole.h"
#include "CarRacing/CarRobot.h"
#include "Input/InputMgr.h"
#include "Render/Camera.h"
#include "Render/Curve.h"
#include "Render/MC_Misc.h"
#include "Render/SceneMgr.h"
#include "Render/RendDriver.h"
#include "Rpg/RpgGame.h"
#include "Rpg/SyncGameInfo.h"
#include "Sound/ChannelSound.h"
#include "Sound/SoundListener.h"
#include "Sound/SoundManager.h"
#include "Packet/PacketMiniGame.h"
#ifdef MethodPhyBullet
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "Physic/GL_ShapeDrawer.h"
#endif
//#include "General/Pce.h"
#define InWaterDis 1
CheckStyleEnum(CarStyle);
bool CarStyle::Load( File& file )
{
name = file.ReadString();
ID = file.ReadInt();
file.ReadString(modelName,128);
file.ReadString(boneStyle,128);
UnifyPath(modelName);
Mass = 1;
BodyL = 20*1.7;
BodyW = 10*1.7;
BodyH = 5*1.7;
MoveBrakingRate = 0.8f;
TurnBrakingRate = 0.8f;
MaxEngineForce = 1000;
MaxBrakingForce= 100;
TurnForce = 1;
MaxWheelAng = 0.3f;
vec3 WheelPos_[4] =
{
//vec3(-3.5f,0.0f,5.0f),vec3(3.5f,0.0f,5.0f),
//vec3(-3.5f,0.0f,-5.0f),vec3(3.5f,0.0f,-5.0f),
vec3(3.5f,0.0f,5.0f) ,//fl
vec3(-3.5f,0.0f,5.0f),//fr
vec3(3.5f,0.0f,-5.0f),//bl
vec3(-3.5f,0.0f,-5.0f),//br
};
for (int i=0;i<4;i++)
{
WheelPos[i] = WheelPos_[i];
}
for (int i=0;i<4;i++)
{
file >> WheelRadius[i];
//WheelRadius[i] = 2.5*1.7f;
}
DisWheelH = 10.0f;
Bottom = BodyH*0.5f;//底盘高度
file >> WheelRotable;
file >> radius >> scale;
file >> maxSpeed >> maxTurnSpeed >> alarmDistance;
driverOffset = vec3(0,Bottom + WheelRadius[0]*1.0f,0);
return true;
}
bool CarStyle::Save( File& file )
{
//String head = file.ReadString();
//int num = file.ReadInt();
//name = file.ReadString();
//ID = file.ReadInt();
//file.ReadString(modelName,128);
//file.ReadString(boneStyle,128);
//UnifyPath(modelName);
//file >> radius >> scale;
//file >> maxSpeed >> maxTurnSpeed >> alarmDistance;
return true;
}
CarCharacter::StateFun CarCharacter::m_stateFun[RS_MaxNum][StateFun_Num]={};
void CarDriver::Update()
{
m_renderCharacter->Update();
}
CarCharacter::CarCharacter()
:m_driver(NULL)
{
m_renderCharacter = new RenderCharacter;
RegisterAllStateFun(CarCharacter);
m_regulator = new Regulator(15,0);
m_curState = RS_Racing;
m_sound = new SoundChannel3D;
#ifdef MethodPhyBullet
m_compoundShape = NULL;
m_chassisShape = NULL;
m_wheelShape = NULL;
m_vehicleRayCaster = NULL;
m_vehicle = NULL;
#endif
}
CarCharacter::~CarCharacter()
{
SafeDelete(m_regulator);
SafeDelete(m_renderCharacter);
SafeDelete(m_sound);
SafeDelete(m_driver);
}
void CarCharacter::Free()
{
m_renderCharacter->Free();
//m_sound->Release();
SafeDelete(m_driver);
#ifdef MethodPhyBullet
SafeDelete(m_chassisShape);
SafeDelete(m_chassisShape);
SafeDelete(m_wheelShape);
SafeDelete(m_vehicleRayCaster);
SafeDelete(m_vehicle);
#endif
}
bool CarCharacter::SetStyle( Style* style )
{
if(m_entityStyle == style)
return true;
BaseEntity::SetStyle(style);
CarStyle* style_ = GetStyle();
if(style_==NULL)
return false;
RendSys::MovieClip*movieClip = G_MovieClipMgr->KeepMovie(style_->modelName);
if (movieClip == NULL)
{
//assert(0&&"LogicCharacter::SetStyle(movieClip == NULL)");
//return false;
movieClip = new RendSys::MC_Frame;
if (!movieClip->LoadFromFile(style_->modelName))
{
delete movieClip;
return false;
}
}
else
{
movieClip = movieClip->Clone();
}
m_renderCharacter->SetBoneStyle(style_->boneStyle);
m_renderCharacter->SetMovie(movieClip);
m_renderCharacter->SetScale(vec3(style_->scale,style_->scale,style_->scale)*FitScale_);
m_renderCharacter->PlayAnim("stand");
//绑定的武器不会添加触发onFrameTag
//使用共用骨架做帧事件的回调
m_renderCharacter->GetMixSkeleton()->SetCallBack(this,&CarCharacter::OnAnimCallBack);
//movieClip = m_renderCharacter->GetMovie();
m_movieWheels[0] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("WheelFront_L_clone"));
m_movieWheels[1] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("WheelFront_R_clone"));
m_movieWheels[2] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("WheelRear_L_clone"));
m_movieWheels[3] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("WheelRear_R_clone"));
m_movieSteps[0] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("leftStep_clone"));
m_movieSteps[1] = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("rightStep_clone"));
if(m_movieSteps[0])
m_movieSteps[0]->SetInheritParentFrame(false);
if(m_movieSteps[1])
m_movieSteps[1]->SetInheritParentFrame(false);
m_movieLight = dynamic_cast<MC_Frame*>(movieClip->GetMovieClip("zlight_clone"));
m_engineForce = 0.f;
m_breakingForce = 0.f;
m_wheelAng = 0.f;
#ifdef MethodPhyBullet
float HalfLong = style_->BodyL*0.5f*FitScale_;
float HalfWidth = style_->BodyW*0.5f*FitScale_;
float HalfHigh = style_->BodyH*0.5f*FitScale_;
float Bottom = style_->Bottom*FitScale_;//底盘高度
m_chassisShape = new btBoxShape(btVector3(HalfWidth,HalfHigh,HalfLong)); //半长boxHalfExtents
m_compoundShape = new btCompoundShape;
btTransform localTrans;
localTrans.setIdentity();
localTrans.setOrigin(btVector3(0,HalfHigh+Bottom,0));
m_compoundShape->addChildShape(localTrans,m_chassisShape);
btTransform tr;
tr.setIdentity();
tr.setOrigin(btVector3(0,40.f,0));
m_carBody = G_RacingGame->localCreateRigidBody(800,tr,m_compoundShape);
//m_carBody->setDamping(0.2,0.2);
m_carBody->setActivationState(DISABLE_DEACTIVATION);
float wheelRadius = style_->WheelRadius[0]*FitScale_;
float wheelWidth = style_->WheelRadius[0]*FitScale_*0.2f;
m_wheelShape = new btCylinderShapeX(btVector3(wheelWidth,style_->WheelRadius[0]*FitScale_,style_->WheelRadius[0]*FitScale_));
m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_dynamicsWorld);
m_vehicle = new btRaycastVehicle(m_tuning,m_carBody,m_vehicleRayCaster);
float suspensionRestLength = wheelRadius*1.2f;//2.0f;//1.2f; //悬架静止长度? 太小会抖动
float wheelFriction = 1000;//BT_LARGE_FLOAT;
float suspensionStiffness = 20; //10.f;//20.f;
float suspensionDamping = 2.3f;
float suspensionCompression = 4.4f;//2.2f;//4.4f;
float rollInfluence = 0.1f;//0.05f;//0.1f;//1.0f;
float connectionHeight = wheelRadius*2*1.2f;//?
//btVector3 connectionPointCS0(1-(0.3*wheelWidth),1.2,1.5);
btVector3 connectionPoint[4] =
{
btVector3( HalfWidth-(0.3*wheelWidth) ,connectionHeight,HalfLong-wheelRadius),
btVector3(-HalfWidth+(0.3*wheelWidth) ,connectionHeight,HalfLong-wheelRadius),
btVector3(-HalfWidth+(0.3*wheelWidth) ,connectionHeight,-HalfLong+wheelRadius),
btVector3( HalfWidth-(0.3*wheelWidth) ,connectionHeight,-HalfLong+wheelRadius),
};
bool isFrontWheel[4] = {true,true,false,false};
for (int i=0;i<4;i++)
{
btVector3 wheelDirectionCS0(0,-1,0);
btVector3 wheelAxleCS(-1,0,0);
m_vehicle->addWheel(connectionPoint[i],wheelDirectionCS0,wheelAxleCS,suspensionRestLength,style_->WheelRadius[i]*FitScale_,m_tuning,isFrontWheel[i]);
//有可能失效
//btWheelInfo& wheel = m_vehicle->getWheelInfo(i);
}
for (int i=0;i<4;i++)
{
btWheelInfo& wheel = m_vehicle->getWheelInfo(i);
wheel.m_suspensionStiffness = suspensionStiffness;
wheel.m_wheelsDampingRelaxation = suspensionDamping;
wheel.m_wheelsDampingCompression = suspensionCompression;
wheel.m_frictionSlip = wheelFriction;
wheel.m_rollInfluence = rollInfluence;
}
m_vehicle->setCoordinateSystem(0,1,2);//面向z的坐标系
m_dynamicsWorld->addVehicle(m_vehicle);
#endif
return true;
}
CarStyle* CarCharacter::GetStyle()
{
return dynamic_cast<CarStyle*>(m_entityStyle);
}
//RoleBanner* CarCharacter::GetBanner( BannerSlot slot )
//{
//
//}
bool CarCharacter::Start()
{
MiniPlayer::Start();
m_roadLength = 0;
m_nextWayPoint = 1;
m_lastWayPoint = 0;
m_liveNum = 4;
m_energy = 0;
m_nextWayPointPos = G_RacingGame->m_roadPath->GetPoint(m_nextWayPoint)->pos;
m_lastWayPointPos = G_RacingGame->m_roadPath->GetPoint(m_lastWayPoint)->pos;
m_wheelAng = 0;
m_accumTime = 0;
m_sound->PlaySound__("data/sound/car/car_run.wav",true);
return true;
}
void CarCharacter::Update()
{
MiniPlayer::Update();
CarStyle* style = GetStyle();
float FrameTime = G_Timer->GetStepTimeLimited();
m_energy += FrameTime;
m_engineForce = 0;
if(RS_None<m_curState&&m_curState<RS_MaxNum)
{
RouteCallStateFun(m_curState,StateFun_Update);
m_stateAccumTime += G_Timer->GetStepTime();
}
//deadroll 时要下落 但是不要四轮定位?
UpdateMovement();
//vec3 offset(0,GetStyle()->DisWheelH*0.6f,0);
//offset = offset - m_rot*offset;
vec3 offset = m_rot*vec3(0,(style->Bottom+style->BodyH*0.5f)*FitScale_,0);
m_pos = m_massCenter;// - offset;
m_renderCharacter->SetPos(m_pos);
m_renderCharacter->SetRot(m_rot);
m_renderCharacter->Update();
if (m_movieLight)
{
m_movieLight->SetVisible(m_bJumpping);
}
//设置司机位置
if (m_driver)
{
vec3 pos = m_pos + m_rot*GetStyle()->driverOffset*FitScale_;
m_driver->GetRenderCharacter()->SetPos(pos);
m_driver->GetRenderCharacter()->SetRot(m_rot);
m_driver->Update();
}
m_sound->SetSoundPos(m_pos);
m_sound->SetSoundVel(m_lineVelocity);
//m_sound->SetPlayRate(22050+10000*(1+m_lineVelocity.Length()/FitScale_/100.0f));
}
bool CarCharacter::GetHeightAt(vec3& pos,float top/*=500*/,float bot/*=500*/) const
{
return G_RacingGame->GetHeightAt(pos,top,bot);
}
#ifdef MethodFourWheel
void CarCharacter::UpdateMovement()
{
CarStyle* style = GetStyle();
vec3 destPos;
//震荡:SimStepTime 0.002f GetStepTimeLimited=0.003, m_accumTime=0.003,0.004,0.003,0.004,
//不考虑零头,模拟步数为 1, 2, 1, 2产生震荡 50%
//如果 SimStepTime 0.0002f GetStepTimeLimited=0.0031, m_accumTime=0.0031,0.0032,0.0031,0.0032,
//不考虑零头,模拟步数为 15, 16, 15, 16产生震荡 1/16
//如果考虑零头,可以适当降低模拟步数 要注意复利引起的帧相关性变化
#define SimStepTime 0.0005f //0.03f/0.0005f=60
float FrameTime = G_Timer->GetStepTimeLimited();
//float FrameTime = 0.002f;//测试 不再震荡
m_accumTime += FrameTime;
//OutputDebugText(StrFormat("m_accumTime=%f\n",m_accumTime));
//帧速变快,系数变小,类似计算复利,仍然有误差 极限误差倍数为自然常数e
//复利误差随期数迅速递减
float SimTime = 0;
while(m_accumTime > 0)
{
SimTime = min(m_accumTime,SimStepTime);
SimTime = min(SimTime,FrameTime);
m_accumTime -= SimTime;
vec3 oldSpeed = m_lineVelocity;
m_lineVelocity += m_heading*m_engineForce*SimTime/style->Mass;
//??? 上坡还是太快??
m_lineVelocity.y = 0;
float vel = m_lineVelocity.Length();
if (vel<0.001f)
{
m_lineVelocity = vec3(0,0,0);
}
else
{
//m_heading = m_speed;
//m_heading.Normalize();
if (m_lineVelocity.Dot(m_heading)>0)
{
m_lineVelocity = m_heading* (vel*(1-style->MoveBrakingRate*SimTime));
}
else
{
m_lineVelocity = -m_heading* (vel*(1-style->MoveBrakingRate*SimTime));
}
//todo 漂移
}
m_massCenterGround += (m_lineVelocity+oldSpeed)*(0.5f*SimTime);
//处理和其它车的碰撞 todo??
//todo 车体转角于 前轮转角 速度 time 直接的关系
//todo 确保 车轮切于路径弧 无漂移 抓地强
float bodyTurn = m_wheelAng * min(1,(0.003f*m_lineVelocity.Length()));
if (bodyTurn>0.001f||bodyTurn<-0.001f)
{
mat4 turnMat;
turnMat.FromRotateY(-bodyTurn*SimTime);
m_heading = turnMat*m_heading;
//m_speed = mat*m_speed;
}
//??
m_heading.y = 0;
m_heading.Normalize();
}
G_RacingGame->GetHeightAt(m_massCenterGround,30,3000);
//==================^_^==================^_^==================^_^==================^_^
mat4 mat = mat4(m_rot);
mat.SetTranslate(m_massCenterGround);
//根据四个轮子处地形高度旋转车体
for (int i=0;i<4;i++)
{
m_wheelGroundPos[i] = mat*style->WheelPos[i];//仅使用计算xz
G_RacingGame->GetHeightAt(m_wheelGroundPos[i],30,3000);
vec3& wheelGround = m_wheelGroundPos[i];
vec3& wheelPos = m_wheelPos[i];
vec3& wheelSpeed = m_wheelSpeed[i];
wheelPos.x = wheelGround.x;
wheelPos.z = wheelGround.z;
//轮子受到重力
wheelSpeed.y -= 100*FrameTime;
wheelPos += wheelSpeed*FrameTime;
if (wheelPos.y > wheelGround.y+25)
{
m_bJumpping = true;
}
if (wheelPos.y < wheelGround.y+_EPSILON)
{
wheelPos = wheelGround;
wheelSpeed = vec3(0,0,0);//vec3(0,(wheelGround.y-wheelPos.y)*0.03f,0);
//反弹系数?
m_bJumpping = false;
}
}
vec3 up = (m_wheelPos[2]-m_wheelPos[0]).Cross(m_wheelPos[1]-m_wheelPos[0]);
up.Normalize();
if (up.Length()<0.1f)
{
up = vec3(0,1,0); //m_rot全0会导致
}
vec3 right = m_heading.Cross(up);
right.Normalize();
if (right.Length()<0.1f)
{
right = vec3(0,0,1);// up head重合导致
}
vec3 front = up.Cross(right);
//front.Normalize();
m_rot.InverseLookAt(-right,up,front);
m_massCenter = (m_wheelPos[0]+m_wheelPos[1]+m_wheelPos[2]+m_wheelPos[3])*0.25f;
//TestNotValidNum(m_pos);
}
#endif
#ifdef MethodPhyBullet
void CarCharacter::EditRender(int debugMode)
{
btVector3 worldBoundsMin,worldBoundsMax;
m_dynamicsWorld->getBroadphase()->getBroadphaseAabb(worldBoundsMin,worldBoundsMax);
btVector3 wheelColor(1,0,0);
btScalar m[16];
for (int i=0;i<m_vehicle->getNumWheels();i++)
{
//draw wheels (cylinders)
m_vehicle->getWheelInfo(i).m_worldTransform.getOpenGLMatrix(m);
m_shapeDrawer->drawOpenGL(m,m_wheelShape,wheelColor,debugMode,worldBoundsMin,worldBoundsMax);
}
}
void CarCharacter::UpdateMovement()
{
CarStyle* style = GetStyle();
vec3 destPos;
for (int i=0;i<m_vehicle->getNumWheels();i++)
{
m_vehicle->updateWheelTransform(i,true);
}
btScalar m[16];
for (int i=0;i<m_vehicle->getNumWheels();i++)
{
btWheelInfo& wheelInfo = m_vehicle->getWheelInfo(i);
//if (wheelInfo.m_raycastInfo.m_isInContact)
//{
// m_bJumpping = false;
//}
wheelInfo.m_worldTransform.getOpenGLMatrix(m);
Frame frame;
frame.m_matrix = m;
//m_rendMovie->SetProgramFrame(&frame);
//m_rendMovie->Advance();
}
btTransform tran = m_carBody->getCenterOfMassTransform();
m_massCenter = btvec3(tran.getOrigin());
m_massCenterGround = m_massCenter;
G_RacingGame->GetHeightAt(m_massCenterGround,30*FitScale_,3000);
m_lineVelocity = btvec3(m_carBody->getLinearVelocity());
const btMatrix3x3& mat = tran.getBasis();
m_rot.mat[0] = mat[0][0]; m_rot.mat[3] = mat[0][1]; m_rot.mat[6] = mat[0][2];
m_rot.mat[1] = mat[1][0]; m_rot.mat[4] = mat[1][1]; m_rot.mat[7] = mat[1][2];
m_rot.mat[2] = mat[2][0]; m_rot.mat[5] = mat[2][1]; m_rot.mat[8] = mat[2][2];
m_heading = m_rot*vec3(0,0,1);
if (m_massCenter.y > m_massCenterGround.y + style->BodyH*FitScale_*3)
{
m_bJumpping = true;
}
if (m_bJumpping)
{
if (m_massCenter.y < m_massCenterGround.y + style->BodyH*FitScale_*0.1f
&&m_lineVelocity.y < 5.0f*FitScale_)
{
m_bJumpping = false;
}
}
for (int i=0;i<m_vehicle->getNumWheels();i++)
{
btWheelInfo& wheelInfo = m_vehicle->getWheelInfo(i);
//m_carBody->getWorldTransform().getOpenGLMatrix(m);
m_wheelPos[i] = btvec3(wheelInfo.m_worldTransform.getOrigin()) + m_rot*vec3(0,-style->WheelRadius[i]*FitScale_,0);
m_wheelGroundPos[i] = m_wheelPos[i];
G_RacingGame->GetHeightAt(m_wheelGroundPos[i],30*FitScale_,3000);
}
//m_wheelSpeed[4];
//TestNotValidNum(m_pos);
}
#endif
void CarCharacter::Render()
{
m_renderCharacter->Render();
if (m_driver)
{
m_driver->Render();
}
#ifdef _DEBUG
G_RendDriver->SetRenderStateEnable(RS_LIGHTING, false);
G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D, false);
G_RendDriver->DisableRendState(RS_DEPTH_TEST);
G_RendDriver->SetLineWidth(1.0f);
G_RendDriver->Color3f(0.0f, 0.0f, 1.0f);
G_RendDriver->RendBegin(RS_LINES);
G_RendDriver->Vertex3fv(&m_nextWayPointPos.x);
G_RendDriver->Vertex3fv(&m_massCenterGround.x);
G_RendDriver->RendEnd();
#endif
}
bool CarCharacter::RouteCallStateFun(int state,StateFunType fun)
{
//stateFun 不能为virtual 否则调用的是派生方法
if(m_stateFun[state][fun])
{
return (this->*m_stateFun[state][fun])();
}
else
{
if (fun==StateFun_Check)
{
return true;
}
}
return false;
}
bool CarCharacter::TryChangeState(RacingCarState state)
{
if (m_curState==state)
{
return false;
}
if(RS_None>=state||state>=RS_MaxNum)
{
return false;
}
//开关
if(m_stateSwitch[state] == false)
{
return false;
}
//条件
if(RouteCallStateFun(state,StateFun_Check)==false)
{
return false;
}
//
m_lastState = m_curState;
m_lastStateType = m_curStateType;
RouteCallStateFun(m_curState,StateFun_Exit);
m_stateAccumTime = 0;
m_curState = state;
//力度清零
m_engineForce = 0;
RouteCallStateFun(m_curState,StateFun_Enter);
return true;
}
//==================^_^==================^_^==================^_^==================^_^
bool CarCharacter::RS_RacingStateCheck()
{
return true;
}
bool CarCharacter::RS_RacingStateEnter()
{
//ClearMoveForce();
m_sound->PlaySound__("data/sound/car/car_run.wav",true);
return true;
}
bool CarCharacter::RS_RacingStateExit()
{
return true;
}
bool CarCharacter::RS_RacingStateUpdate()
{
if (G_RacingGame->GetGameState() != MS_Gamming)
{
return false;
}
CarStyle* style = GetStyle();
const char* anim = "run";
if (G_RacingGame->GetGameState() != MS_IntroCamera)
{
m_renderCharacter->PlayAnim(anim);
}
mat4 matA,matB,mat;
matA.FromRotateY(m_wheelAng*1);
matB.FromRotateY(m_wheelAng*-0.2f);
Frame frame;
float dis = m_lineVelocity.Length();//time=1
for (int i=0;i<4;i++)
{
{
//动画100帧转一圈
float rat = dis/FitScale_/(style->WheelRadius[i]*TWOPI)*100.0f;
rat = min(rat,200);
MC_Skeleton* skeletonMovie = dynamic_cast<MC_Skeleton*>(m_movieWheels[i]);
MC_Frame* frameMovie = dynamic_cast<MC_Frame*>(m_movieWheels[i]);
四轮转速
需要运动模糊处理
if (skeletonMovie)
{
// skeletonMovie->GetMixSkeleton()->SetSpeed(rat);
}
else if (frameMovie)
{
frameMovie->GetPlayHead()->SetSpeed(rat);
}
m_renderCharacter->GetMixSkeleton()->SetSpeed(rat);
}
//四轮转角
if(style->WheelRotable && m_movieWheels[i])
{
if (i<2)
{
mat = matA;
mat.SetTranslate((style->WheelPos[i] - mat*style->WheelPos[i])*FitScale_);
frame.m_matrix = mat;
m_movieWheels[i]->SetProgramFrame(&frame);
}
else
{
mat = matB;
mat.SetTranslate((style->WheelPos[i] - mat*style->WheelPos[i])*FitScale_);
frame.m_matrix = mat;
m_movieWheels[i]->SetProgramFrame(&frame);
}
}
}
#ifdef MethodPhyBullet
mat4 mat2;
mat3 scale;
scale.FromScale(FitScale_*2,FitScale_*2,FitScale_*2);
for (int i=2;i<m_vehicle->getNumWheels();i++)
{
if ((m_wheelPos[i] -m_wheelGroundPos[i]).Length()<style->WheelRadius[i]*FitScale_*0.3f)
{
int step = -1;
if (i==2)
step = 0;
if (i==3)
step = 1;
if (step!=-1)
{
frame.m_matrix = m_rot*scale;
//frame.m_matrix.Identity();
//frame.m_matrix.SetTranslate(m_wheelGroundPos[i]);
frame.m_matrix.SetTranslate(m_massCenter);
if(m_movieSteps[step])
m_movieSteps[step]->SetProgramFrame(&frame);
}
}
}
#endif
//if (m_bJumpping==false)
//{
// //frame.m_pos = m_wheelGroundPos[2];
// frame.m_matrix = m_rot;
// //frame.m_matrix.Identity();
// frame.m_matrix.SetTranslate(m_wheelGroundPos[2]);
// if(m_movieSteps[0])
// m_movieSteps[0]->SetProgramFrame(&frame);
// frame.m_matrix = m_rot;
// frame.m_matrix.SetTranslate(m_wheelGroundPos[3]);
// if(m_movieSteps[1])
// m_movieSteps[1]->SetProgramFrame(&frame);
//}
//
m_score = (int)(m_roadLength*1000);
if(m_playerInfo)
m_playerInfo->score = (int)(m_roadLength*1000);
m_sound->SetPlayRate(22050+10000*(1+m_lineVelocity.Length()/FitScale_/100.0f));
return true;
}
//==================^_^==================^_^==================^_^==================^_^
bool CarCharacter::RS_DeadRollStateCheck()
{
return true;
}
bool CarCharacter::RS_DeadRollStateEnter()
{
m_sound->PlaySound__("data/sound/car/car_exploid.wav",true);
m_sound->SetPlayRate(22050);
m_deadRotMat.FromAxisAngle(vec3(RandRange(-2.0f,2.0f),RandRange(-2.0f,2.0f),RandRange(-2.0f,2.0f)),RandRange(-20.0f,20.0f)*DEG2RAD);
//绕多个轴有错误?
int axix = Rand()%3;
m_deadRotRad = vec3(RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f));
m_deadRotRad[axix] *= 20;
return true;
}
bool CarCharacter::RS_DeadRollStateExit()
{
//清除翻滚
Frame* frame = m_renderCharacter->GetMovie()->GetProgramFrame();
frame->m_matrix.Identity();
m_renderCharacter->GetMovie()->SetProgramFrame(frame);
return true;
}
bool CarCharacter::RS_DeadRollStateUpdate()
{
//掉下路面
vec3 pos = GetPos();
RayMovieCollideRes res(vec3(pos.x,pos.y+50,pos.z),vec3(pos.x,pos.y-500,pos.z));
res.parallelY = true;
bool hit = (NULL!=G_RacingGame->m_movieCollide->IntersectTray(res));
if (hit==true)
{
//掉回路上 ? 可以走捷径?
TryChangeState(RS_Racing);
}
m_wrongWayTime += G_Timer->GetStepTime();
Frame* frame = m_renderCharacter->GetMovie()->GetProgramFrame();
vec3 landPos;
GetHeightAt(landPos,60,3000);
//已经落地,开启新的地面碰撞弹开模拟?
if (pos.y < landPos.y + CHARACTER_HEIGHT/2)
{
frame->m_rot+=m_deadRotRad*-0.1f;
}
else if (pos.y <= G_SceneMgr->m_waterLevel - InWaterDis)
{
//已经落水,模拟浮力
pos.y = G_SceneMgr->m_waterLevel - InWaterDis;
frame->m_rot+=m_deadRotRad*-0.1f;
}
else
{
frame->m_rot+=m_deadRotRad;
}
frame->m_matrix = m_deadRotMat*frame->m_matrix;
m_renderCharacter->GetMovie()->SetProgramFrame(frame);
return true;
}
//==================^_^==================^_^==================^_^==================^_^
void CarCharacter::OnAnimCallBack(const char* frameName)
{
//LogicCharacter::OnAnimCallBack(frameName);
if (strcmp(frameName,"end") == 0)
{
bool inWater = false;//m_pos.y <= G_SceneMgr->m_waterLevel - InWaterDis;
if (inWater)
{
m_renderCharacter->PlayAnim("swim");
if(m_driver)
m_driver->GetRenderCharacter()->PlayAnim("swim");
}
else
{
if (m_lineVelocity.IsZero())
{
m_renderCharacter->PlayAnim("stand");
if(m_driver)
m_driver->GetRenderCharacter()->PlayAnim("stand");
}
else
{
//m_sound->PlaySound__("data/sound/event_run.wav",true);
m_renderCharacter->PlayAnim("run");
if(m_driver)
m_driver->GetRenderCharacter()->PlayAnim("drive");
}
}
}
}
void CarCharacter::SendCmdMove()
{
C2SPacketMiniGameCmd packet;
packet.WriteHeader();
packet.WriteValue(CMD_CarMove);
packet.WriteValue(m_roomSlot);
packet.WriteValue(m_massCenter.x);
packet.WriteValue(m_massCenter.y);
packet.WriteValue(m_massCenter.z);
vec3 rot = m_rot.GetEulerAngRadXZY();
packet.WriteValue(rot.x);
packet.WriteValue(rot.y);
packet.WriteValue(rot.z);
packet.WriteValue(m_lineVelocity.x);
packet.WriteValue(m_lineVelocity.y);
packet.WriteValue(m_lineVelocity.z);
packet.WriteValue(m_angVelocity.x);
packet.WriteValue(m_angVelocity.y);
packet.WriteValue(m_angVelocity.z);
packet.WriteValue(m_roadLength);
G_MiniGame->SendPacketToOther(&packet);
}
void CarCharacter::SendCmdCarDeadRoll()
{
C2SPacketMiniGameCmd packet;
packet.WriteHeader();
packet.WriteValue(CMD_CarDeadRoll);
packet.WriteValue(m_roomSlot);
packet.WriteValue(m_massCenter.x);
packet.WriteValue(m_massCenter.y);
packet.WriteValue(m_massCenter.z);
vec3 rot = m_rot.GetEulerAngRadXZY();
packet.WriteValue(rot.x);
packet.WriteValue(rot.y);
packet.WriteValue(rot.z);
packet.WriteValue(m_lineVelocity.x);
packet.WriteValue(m_lineVelocity.y);
packet.WriteValue(m_lineVelocity.z);
packet.WriteValue(m_angVelocity.x);
packet.WriteValue(m_angVelocity.y);
packet.WriteValue(m_angVelocity.z);
//packet.WriteArray(m_deadRotMat.mat,sizeof(float)*16);
packet.WriteArray(&m_deadRotRad.x,sizeof(float)*3);
G_MiniGame->SendPacketToOther(&packet);
}
void CarCharacter::CalRoadLength()
{
//整数部分是已经完成的圈数 完成一圈roadlength为1 向后退时不计算的太精确
int roadLength = m_roadLength;
m_roadLength = roadLength + m_lastWayPoint/(float)G_RacingGame->m_roadPath->GetPointNum();
float toNext = (m_massCenterGround - m_nextWayPointPos).Length();
float toLast = (m_massCenterGround - m_lastWayPointPos).Length();
m_roadLength += toLast/(toNext+toLast)/(float)G_RacingGame->m_roadPath->GetPointNum();
}
bool CarCharacter::IsWrongDir()
{
bool wrongDir = false;
vec3 dif = m_nextWayPointPos - m_massCenterGround;
dif.Normalize();
//if (m_heading.Dot(dif) < 0) //大于90度拐弯时会误判
if (m_heading.Dot(dif) < -0.707f)
{
wrongDir = true;
}
return wrongDir;
}
void CarCharacter::CalWayPoint()
{
//避免锐角路径
vec3 nextPathDir = G_RacingGame->m_roadPath->GetDirToNextPoint(m_nextWayPoint);
vec3 lastPathDir = G_RacingGame->m_roadPath->GetDirToNextPoint(m_lastWayPoint);
//if (toNext < 10) //速度太快 冲过去了?
//到达下一个路点
//if ((m_massCenterGround-m_nextWayPointPos).Dot(nextPathDir)>0) //可能有大于90度的拐角
//点距
vec3 next2WayPointPos = G_RacingGame->m_roadPath->GetPoint(m_nextWayPoint+1)->pos;
float dis = DistPointSegment(m_pos, m_lastWayPointPos, m_nextWayPointPos);
float disNext = DistPointSegment(m_pos, m_nextWayPointPos, next2WayPointPos);
if(disNext<dis*0.9f) //如果m_nextWayPointPos==next2WayPointPos 会有问题 无法转到下一段0长度的路径
{
m_lastWayPoint = m_nextWayPoint;
m_nextWayPoint++;
if (m_nextWayPoint >= G_RacingGame->m_roadPath->GetPointNum())
{
//回到起点
m_nextWayPoint = 0;
m_roadLength += 1;
}
m_nextWayPointPos = G_RacingGame->m_roadPath->GetPoint(m_nextWayPoint)->pos;
m_lastWayPointPos = G_RacingGame->m_roadPath->GetPoint(m_lastWayPoint)->pos;
}
//后退到达上一路点 ?
if ((m_massCenterGround-m_lastWayPointPos).Dot(lastPathDir)<0)
{
}
}
void CarCharacter::ResetCar()
{
m_liveNum--;
m_wrongWayTime = 0;
//m_massCenter = m_lastWayPointPos; //如果路点相隔太远会退回很远
m_massCenter = G_RacingGame->GetRoadPathPos(m_roadLength);
m_massCenterGround = m_massCenter;
G_RacingGame->GetHeightAt(m_massCenterGround,30*FitScale_,3000);
if (m_massCenter.y < m_massCenterGround.y)
{
//路点相聚很远 中间地形上拱
m_massCenter.y = m_massCenterGround.y;
}
m_lineVelocity = vec3();
m_heading = m_nextWayPointPos - m_massCenterGround;
m_heading.Normalize();
vec3 up = vec3(0,1,0);//(m_wheelPos[0]-m_wheelPos[1]).Cross(m_wheelPos[2]-m_wheelPos[0]);
up.Normalize();
if (up.Length()<0.1f)
{
up = vec3(0,1,0); //m_rot全0会导致
}
vec3 right = m_heading.Cross(up);
right.Normalize();
if (right.Length()<0.1f)
{
right = vec3(0,0,1);// up head重合导致
}
vec3 front = up.Cross(right);
//front.Normalize();
m_rot.InverseLookAt(-right,up,front);
#ifdef MethodPhyBullet
btTransform tran;
tran.setOrigin(btvec3(m_massCenter));
quat rotQ;
rotQ.FromMatrix(m_rot);
btQuaternion q(rotQ.x,rotQ.y,rotQ.z,rotQ.w);
//q.setEuler()
tran.setRotation(q);
//m_carBody->setWorldTransform(tran);
m_carBody->setCenterOfMassTransform(tran);
//SetPos(m_massCenter);
m_wheelAng = 0.f;
m_carBody->setLinearVelocity(btVector3(0,0,0));
m_carBody->setAngularVelocity(btVector3(0,0,0));
//for (int i=0;i<m_vehicle->getNumWheels();i++)
//{
// m_vehicle->updateWheelTransform(i,true);
//}
#endif
TryChangeState(RS_Racing);
}
void CarCharacter::SetPosHeading(const vec3& pos,const vec3& heading)
{
m_rot.FromToDir(vec3(0,0,1),vec3(0,1,0),heading,vec3(0,1,0));
SetTransform(pos,m_rot);
}
void CarCharacter::SetPosEuler(const vec3& pos,const vec3& rot)
{
m_rot.FromEulerAngRadXZY(rot);
SetTransform(pos,m_rot);
}
void CarCharacter::SetTransform(const vec3& pos,const mat3& rot)
{
m_massCenter = m_massCenterGround = pos;
G_RacingGame->GetHeightAt(m_massCenterGround,30*FitScale_,3000);
CarStyle* style = GetStyle();
vec3 offset = m_rot*vec3(0,(style->Bottom+style->BodyH*0.5f)*FitScale_,0);
m_pos = m_massCenter;// - offset;
m_rot = rot;
m_heading = m_rot*vec3(0,0,1);
#ifdef MethodPhyBullet
btTransform tran;
tran.setOrigin(btvec3(m_massCenter));
quat rotQ;
rotQ.FromMatrix(m_rot);
btQuaternion q(rotQ.x,rotQ.y,rotQ.z,rotQ.w);
tran.setRotation(q);
m_carBody->setCenterOfMassTransform(tran);
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_carBody->getBroadphaseHandle(),m_dynamicsWorld->getDispatcher());
if (m_vehicle)
{
m_vehicle->resetSuspension();
for (int i=0;i<m_vehicle->getNumWheels();i++)
{
m_vehicle->updateWheelTransform(i,true);
}
}
#endif
}
void CarCharacter::SetSpeed( const vec3& lineVelocity ,const vec3& angVelocity)
{
m_lineVelocity = lineVelocity;
m_angVelocity = angVelocity;
#ifdef MethodPhyBullet
m_carBody->setLinearVelocity(btvec3(m_lineVelocity));
m_carBody->setAngularVelocity(btvec3(m_angVelocity));
#endif
}
vec3& CarCharacter::GetSpeed()
{
return m_lineVelocity;
}
vec3 CarCharacter::GetHeading() const
{
return m_heading;
}
void CarCharacter::Jump()
{
if(m_bJumpping == true)
return;
m_bJumpping = true;
#ifdef MethodFourWheel
for (int i=0;i<4;i++)
{
vec3& wheelSpeed = m_wheelSpeed[i];
wheelSpeed.y = 60;
}
#endif
#ifdef MethodPhyBullet
//btVector3 impulse(0,0.003f/m_carBody->getInvMass(),0);
m_carBody->applyImpulse(impulse,m_carBody->getCenterOfMassPosition());
//for (int i=0;i<m_vehicle->getNumWheels();i++)
//{
// btWheelInfo& wheelInfo = m_vehicle->getWheelInfo(i);
// m_carBody->applyImpulse(impulse/m_vehicle->getNumWheels(),wheelInfo.m_worldTransform.getOrigin());
//}
m_carBody->setLinearVelocity(m_carBody->getLinearVelocity()+btVector3(0,30*FitScale_,0));
m_lineVelocity = btvec3(m_carBody->getLinearVelocity());
#endif
if (m_driver)
{
m_driver->GetRenderCharacter()->PlayAnim("jump");
}
}
简单的自动驾驶算法:
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/RacingCar.h
// @Brief: RacingCar
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#ifndef __CarRobot__H__
#define __CarRobot__H__
#include "CarRacing/CarCharacter.h"
class CarRobot: public CarCharacter
{
public:
CarRobot();
~CarRobot();
virtual void Free();
virtual void Render();
virtual void Update();
virtual bool SetStyle(Style* style);
virtual void OnAnimCallBack(const char* frameName);
virtual void UpdateMovement();
virtual void ResetCar();
void AiInput();
<<状态
//DeclareStateFun(GS_None );
DeclareStateFun(RS_Racing );
DeclareStateFun(RS_DeadRoll );
//typedef StateClass<CarRobot,RS_MaxNum> ThisStateClass;
typedef bool (CarRobot::*StateFun)();
static StateFun m_stateFun[RS_MaxNum][StateFun_Num];
virtual bool RouteCallStateFun(int state,StateFunType fun);
virtual bool TryChangeState(RacingCarState state);
>>
void SetWorkingWithAI(bool working);
//完成一圈的时间
float m_circleTime;
//AI挂机
bool m_workingWithAI;
//陷入死角的时间
double m_blockTime;
vec3 m_blockPos;
bool m_bBacking;
};
#endif
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/RacingCar.cpp
// @Brief: RacingCar
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#include "General/Pch.h"
#include "AI/Navigation/SteeringSystem.h"
#include "CarRacing/MiniGameRacing.h"
#include "CarRacing/CarRobot.h"
#include "CarRacing/CarRole.h"
#include "General/General.h"
#include "General/Regulator.h"
#include "General/Timer.h"
#include "Input/InputMgr.h"
#include "Render/Camera.h"
#include "Render/Curve.h"
#include "Render/MC_Misc.h"
#include "Render/SceneMgr.h"
#include "Rpg/RpgGame.h"
#include "Sound/SoundListener.h"
#include "Sound/SoundManager.h"
#include "Packet/PacketMiniGame.h"
#include "General/Pce.h"
#include "Math/MathLibAdvance.h"
#define InWaterDis 1
CarRobot::StateFun CarRobot::m_stateFun[RS_MaxNum][StateFun_Num]={};
CarRobot::CarRobot()
:m_workingWithAI(true)
,m_blockTime(0)
{
RegisterAllStateFun(CarRobot);
}
CarRobot::~CarRobot()
{
CarRobot::Free();
}
void CarRobot::Free()
{
CarCharacter::Free();
}
void CarRobot::Render()
{
CarCharacter::Render();
}
void CarRobot::UpdateMovement()
{
CarCharacter::UpdateMovement();
// UpdateHeadBySpeed();
}
void CarRobot::SetWorkingWithAI(bool working)
{
m_workingWithAI = working;
m_bBacking = false;
m_blockTime = 0;
//if (m_workingWithAI==false)
//{
// ClearMoveForce();
// m_speed = vec3(0,0,0);
// TryChangeState(GS_Stand);
// m_steering->SteeringOff(SteeringSystem::arrive);
// m_steering->SteeringOff(SteeringSystem::Wander);
// m_steering->SteeringOff(SteeringSystem::OffsetPursuit);
//}
}
void CarRobot::Update()
{
CarCharacter::Update();
//重置汽车
if (m_wrongWayTime > 4.0f)
{
ResetCar();
}
}
void CarRobot::ResetCar()
{
CarCharacter::ResetCar();
if (dynamic_cast<CarRobot*>(this) || dynamic_cast<CarRole*>(this))
{
C2SPacketMiniGameCmd packet;
packet.WriteHeader();
packet.WriteValue(CMD_CarReset);
packet.WriteValue(m_roomSlot);
packet.WriteValue(m_massCenter.x);
packet.WriteValue(m_massCenter.y);
packet.WriteValue(m_massCenter.z);
vec3 rot = m_rot.GetEulerAngRadXZY();
packet.WriteValue(rot.x);
packet.WriteValue(rot.y);
packet.WriteValue(rot.z);
G_MiniGame->SendPacketToOther(&packet);
}
m_blockTime = 0;
}
bool CarRobot::RouteCallStateFun(int state,StateFunType fun)
{
//stateFun 不能为virtual 否则调用的是派生方法
if(m_stateFun[state][fun])
{
return (this->*m_stateFun[state][fun])();
}
else
{
if (fun==StateFun_Check)
{
return true;
}
}
return false;
}
bool CarRobot::TryChangeState(RacingCarState state)
{
if (m_curState==state)
{
return false;
}
if(RS_None>=state||state>=RS_MaxNum)
{
return false;
}
//开关
if(m_stateSwitch[state] == false)
{
return false;
}
//条件
if(RouteCallStateFun(state,StateFun_Check)==false)
{
return false;
}
//
m_lastState = m_curState;
m_lastStateType = m_curStateType;
RouteCallStateFun(m_curState,StateFun_Exit);
m_stateAccumTime = 0;
m_curState = state;
//力度清零
m_engineForce = 0;
RouteCallStateFun(m_curState,StateFun_Enter);
return true;
}
//==================^_^==================^_^==================^_^==================^_^
bool CarRobot::RS_RacingStateCheck()
{
return true;
}
bool CarRobot::RS_RacingStateEnter()
{
//ClearMoveForce();
return true;
}
bool CarRobot::RS_RacingStateExit()
{
return true;
}
//bool CarRobot::RS_RacingStateUpdate()
//{
// if (G_RacingGame->GetGameState() != MS_Gamming)
// {
// return false;
// }
//
// //return true;
//
// CarCharacter::RS_RacingStateUpdate();
//
// vec3 nextDir = G_RacingGame->m_roadPath->GetDirToNextPoint(m_nextWayPoint);
// vec3 lastDir = G_RacingGame->m_roadPath->GetDirToNextPoint(m_lastWayPoint);
//
// //
// CalWayPoint();
//
// //不准确,可能导致ai车不动
// //CalRoadLength();
//
// 向后开车
// //if (IsWrongDir())
// //{
// // m_wrongWayTime += G_Timer->GetStepTime();
// //}
// //else
// //{
// // m_wrongWayTime = 0;
// //}
//
// //掉下路面
// vec3 pos = GetPos();
// RayMovieCollideRes res(vec3(pos.x,pos.y+50,pos.z),vec3(pos.x,pos.y-500,pos.z));
// res.parallelY = true;
// bool hit = (NULL!=G_RacingGame->m_movieCollide->IntersectTray(res));
// if (!hit)
// {
// //翻滚
// TryChangeState(RS_DeadRoll);
// }
//
// float roadLength = G_Timer->GetStepTime()/m_circleTime;
// float dif = m_roadLength - G_RacingGame->m_myRolePlayer->m_roadLength;
// if (dif > 0.2)
// {
// roadLength *= 0.25;
// }
// else if (dif < -0.2)
// {
// roadLength *= 4;
// }
// else if (dif > 0.05)
// {
// roadLength *= 0.5;
// }
// else if (dif < -0.05)
// {
// roadLength *= 2;
// }
// m_roadLength += roadLength;
//
// vec3 oldPos = m_massCenter;
// m_massCenter = G_RacingGame->GetRoadPathPos(m_roadLength);
// G_RacingGame->GetHeightAt(m_massCenter,30*FitScale_,3000);
// m_massCenterGround = m_massCenter;
//
// m_heading = m_nextWayPointPos - m_massCenterGround;
// m_heading.Normalize();
//
// SetPosHeading(m_massCenter,m_heading);
// m_lineVelocity = m_heading*(m_massCenter-oldPos).Length()/G_Timer->GetStepTime();
//
// SendCmdMove();
// return true;
//}
void CarRobot::AiInput()
{
CarStyle* style = GetStyle();
if(0)
{
this->Jump();
}
if(0)
{
ResetCar();
}
//
float time = G_Timer->GetStepTimeLimited();
//ai模拟按键
bool pressed_UP = false;
bool pressed_DOWN = false;
bool pressed_LEFT = false;
bool pressed_RIGHT = false;
#ifdef MethodFourWheel
float speed = m_lineVelocity.Length();
#endif
#ifdef MethodPhyBullet
float speed = m_carBody->getLinearVelocity().length();
#endif
if (m_bBacking || speed<1.1f*FitScale_)
{
m_blockTime += G_Timer->GetStepTimeLimited();
}
else
{
m_blockTime = 0;
}
if (m_blockTime>0.5f)
{
m_blockPos = m_massCenterGround;
m_bBacking = true;
}
if (m_bBacking)
{
if ((m_blockPos - m_massCenterGround).Length()> 40*FitScale_//有可能堵在死角
|| m_blockTime >2.0f
)
{
m_blockTime = 0;
m_bBacking = false;
}
}
//模拟拐弯输入
{
vec3 headingTar = m_nextWayPointPos;
vec3 dif = headingTar - m_massCenterGround;
float len = dif.Length();
if ( (speed > 90*FitScale_ && len<120*1.0f*FitScale_) //todo 连续变化; 和坡度(地形法线z值)相关; 和到路边距离相关;
|| (speed > 60*FitScale_ && len<120*0.6f*FitScale_
|| len<120*0.4f*FitScale_ )
)
{
//拐弯处
//转向下下个点
headingTar = G_RacingGame->m_roadPath->GetPoint(m_nextWayPoint+1)->pos;
dif = headingTar - m_massCenterGround;
}
float dis = DistPointSegment(m_massCenterGround, m_lastWayPointPos, m_nextWayPointPos);
if (dis>120*0.5f*FitScale_)//由于后退 m_nextWayPointPos不后退 导致
{
//转向上下个点
//headingTar = G_RacingGame->m_roadPath->GetPoint(m_nextWayPoint-1)->pos;
float t;
ClosestPointSegment(m_massCenterGround, m_lastWayPointPos, m_nextWayPointPos, t,headingTar);
//
G_RacingGame->GetHeightAt(headingTar,30*FitScale_,3000);
dif = headingTar - m_massCenterGround;
}
dif.y = 0;
dif.Normalize();
float difAng = SafeAcos(m_heading.Dot(dif));
if (m_heading.Cross(dif).y>0)
{
if (m_wheelAng<difAng)
{
if (m_bBacking)
pressed_RIGHT = true;
else
pressed_LEFT = true;
}
}
else
{
if (m_wheelAng>-difAng)
{
if (m_bBacking)
pressed_LEFT = true;
else
pressed_RIGHT = true;
}
}
}
//模拟油门刹车输入
{
if (m_bBacking)
{
pressed_DOWN = true;
}
else
{
float wayAng = 90;
vec3 dif = m_nextWayPointPos - m_massCenterGround;
float len = dif.Length();
if (len<120*0.5f*FitScale_ && wayAng>45)
{
//拐弯处
if(speed > 40*FitScale_)
{
pressed_DOWN = true;
}
else if(speed < 30*FitScale_)
{
pressed_UP = true;
}
}
else if (len<120*0.9f*FitScale_ && wayAng>45)
{
//拐弯处
if(speed > 60*FitScale_)
{
pressed_DOWN = true;
}
else if(speed < 40*FitScale_)
{
pressed_UP = true;
}
}
else if (len<120*1.9f*FitScale_ && wayAng>45)
{
//拐弯处
if(speed > 80*FitScale_)
{
pressed_DOWN = true;
}
else if(speed < 50*FitScale_)
{
pressed_UP = true;
}
}
else
{
pressed_UP = true;
}
}
}
//处理输入
if (pressed_UP)
{
m_engineForce = style->MaxEngineForce;
m_breakingForce = 0.f;
//if (m_driver)
//{
// m_driver->GetRenderCharacter()->PlayAnim("drive");
//}
}
else if (pressed_DOWN)
{
//m_breakingForce = maxBreakingForce;
//m_engineForce = 0.f;
m_engineForce = -style->MaxEngineForce;
m_breakingForce = 0.f;
}
else
{
m_engineForce = 0;
m_breakingForce = 0.f;
}
if (pressed_LEFT)
{
m_wheelAng += style->TurnForce*time;
Clamp(m_wheelAng,-style->MaxWheelAng,style->MaxWheelAng);
//if (m_driver)
//{
// m_driver->GetRenderCharacter()->PlayAnim("drive_left");
//}
}
else if (pressed_RIGHT)
{
m_wheelAng -= style->TurnForce*time;
Clamp(m_wheelAng,-style->MaxWheelAng,style->MaxWheelAng);
//if (m_driver)
//{
// m_driver->GetRenderCharacter()->PlayAnim("drive_right");
//}
}
else
{
//m_wheelAng = 0;
//前轮转角
if (m_wheelAng>0.001f||m_wheelAng<-0.001f)
{
m_wheelAng *= (1-style->TurnBrakingRate*time);
}
else
{
m_wheelAng = 0;
}
}
#ifdef MethodPhyBullet
//后轮
m_vehicle->applyEngineForce(m_engineForce,2);
m_vehicle->setBrake(m_breakingForce,2);
m_vehicle->applyEngineForce(m_engineForce,3);
m_vehicle->setBrake(m_breakingForce,3);
//前轮
m_vehicle->setSteeringValue(m_wheelAng,0);
m_vehicle->setSteeringValue(m_wheelAng,1);
#endif
//char buf[256];
//sprintf(buf,"%.1f,%.1f,%.1f\n",m_engineForce,m_breakingForce,m_wheelAng);
//OutputDebugText(buf);
}
bool CarRobot::RS_RacingStateUpdate()
{
if (G_RacingGame->GetGameState() != MS_Gamming)
{
return false;
}
AiInput();
CarCharacter::RS_RacingStateUpdate();
//
CalWayPoint();
//
CalRoadLength();
//if (m_bRoaming==false)//非漫游测试状态
{
//向后开车
vec3 up(0,1,0);
if (IsWrongDir()
||(m_rot*up).Dot(up)<0
||G_RacingGame->IsOnRoad(m_pos)==false
)
{
m_wrongWayTime += G_Timer->GetStepTime();
}
else
{
m_wrongWayTime = 0;
}
//掉下路面
vec3 pos = GetPos();
RayMovieCollideRes res(vec3(pos.x,pos.y+50,pos.z),vec3(pos.x,pos.y-500,pos.z));
res.parallelY = true;
bool hit = (NULL!=G_RacingGame->m_movieCollide->IntersectTray(res));
if (!hit)
{
//翻滚
TryChangeState(RS_DeadRoll);
}
}
SendCmdMove();
return true;
}
//==================^_^==================^_^==================^_^==================^_^
bool CarRobot::RS_DeadRollStateCheck()
{
return true;
}
bool CarRobot::RS_DeadRollStateEnter()
{
CarCharacter::RS_DeadRollStateEnter();
SendCmdCarDeadRoll();
return true;
}
bool CarRobot::RS_DeadRollStateExit()
{
//清除翻滚
CarCharacter::RS_DeadRollStateExit();
return true;
}
bool CarRobot::RS_DeadRollStateUpdate()
{
//掉下路面
CarCharacter::RS_DeadRollStateUpdate();
return true;
}
bool CarRobot::SetStyle( Style* style )
{
CarCharacter::SetStyle(style);
m_circleTime = 30* RandRange(1.0f,4.0f);
return true;
}
void CarRobot::OnAnimCallBack( const char* frameName )
{
CarCharacter::OnAnimCallBack(frameName);
}
游戏类及场景生成算法:
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/MiniGameRacing.h
// @Brief: MiniGameRacing
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#ifndef __MiniGameRacing__H__
#define __MiniGameRacing__H__
#include "Render/Texture.h"
#include "Rpg/MiniGame.h"
#include "Render/City.h"
#include "CarRacing/CarCharacter.h"
#include <vector>
class Curve;
class CarRole;
class CarRobot;
class btVehicleTuning;
struct btVehicleRaycaster;
class btCollisionShape;
class btCompoundShape;
class btRigidBody;
class btDefaultCollisionConfiguration;
class btBroadphaseInterface;
class btCollisionDispatcher;
class btConstraintSolver;
class btDynamicsWorld;
class btTriangleIndexVertexArray;
class GL_ShapeDrawer;
class BulletAppDemo;
enum RacingState
{
RS_Prepare = MiniGameState_Max+1,
};
enum MiniRacingCmd
{
CMD_CarMove , //赛车移动
CMD_CarDeadRoll, //死亡翻滚
CMD_CarReset , //重置
CMD_BugDead , //
CMD_Anim , //播放动画
};
const char* RacingCmdToString(int enumeration);
namespace RendSys
{
class Mesh;
};
//随机生成地图
class RacingRoad
{
public:
struct BatchMovie
{
char name[32];
RendSys::MovieClip* movie;
vec3 pos;
int rot;
};
RacingRoad();
~RacingRoad();
void Free();
void GenRacingRoad(int seed);
void Render();
void SaveToCollide(RendSys::Mesh* mesh);
void AddMovie(const char* name_,const char* type_,const vec3& pos,int rot);
//
TexturePtr m_texture[8];
//批次
Batch* m_batchs;
int m_batchNum;
std::vector<vec3> m_path;
#define MaxBatchMovie 2048
BatchMovie m_batchMovies[MaxBatchMovie];
int m_batchMovieNum;
RendSys::MovieClip* m_movieLib;
};
//氮气 N 后视镜 motionblur tail water layer 指示牌
//max 挖陷阱, 蘑菇时间奖励, 苍蝇拍 弹球 口香糖 奶油 地刺,云梯,小怪物,金币,电锯,跑酷木门
class MiniGameRacing:public MiniGame
{
public:
MiniGameRacing();
virtual~MiniGameRacing();
virtual bool Start();
virtual bool Stop();
virtual bool Render();
virtual void RenderUI();
virtual bool Update();
virtual bool Free();
virtual void OnSize();
virtual bool KeepResource(bool once,int& circle,String& nextTip);
virtual void OnStartCameraEnd();
//三种类型结构
virtual MiniPlayer* CreatePlayer();
virtual MiniPlayer* CreateRobot ();
virtual MiniPlayer* CreateRole ();
void ToggleViewEye(int eyeMode);
void ToggleObserver();
//处理游戏网络命令包
virtual int ProcessPacketCmd(PacketBase* packet);
//virtual const char* CmdToString(const char* stream,int len);
//获得路径上的位置,整数部分为整圈数
vec3 GetRoadPathPos(float roadLength);
bool IsOnRoad(vec3& pos);
void EditRender();
CarRole* m_myRolePlayer;
int m_sceneID;
MovieClip* m_road;
Curve* m_roadPath;
TexturePtr m_texNeedle;
TexturePtr m_texSpeedo;
float m_countDownTime;
TexturePtr m_texCountdown[4];
//方案二 bullet
#ifdef MethodPhyBullet
void Reset();
btRigidBody* localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape);
btDefaultCollisionConfiguration* m_collisionConfiguration;
btBroadphaseInterface* m_overlappingPairCache;
btCollisionDispatcher* m_dispatcher;
btConstraintSolver* m_constraintSolver;
btDynamicsWorld* m_dynamicsWorld;
GL_ShapeDrawer* m_shapeDrawer;
btCollisionShape* m_shapeGround;
btVector3* m_vertices;
btTriangleIndexVertexArray* m_indexVertexArrays;
btScalar m_defaultContactProcessingThreshold;
#endif
};
extern MiniGameRacing* G_RacingGame;
btVector3 btvec3(const vec3& v);
vec3 btvec3(const btVector3& v);
#endif
//========================================================
// @Date: 2016.05
// @File: SourceDemoClient/CarRacing/MiniGameRacing.cpp
// @Brief: MiniGameRacing
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#include "General/Pch.h"
#include "AI/Navigation/SteeringSystem.h"
#include "General/General.h"
#include "General/StringUtil.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "General/Option.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Render/Camera.h"
#include "Render/Curve.h"
#include "Render/Font.h"
#include "Render/RendDriver.h"
#include "Render/SceneMgr.h"
#include "Rpg/RpgGame.h"
#include "Rpg/SyncGameInfo.h"
#include "CarRacing/MiniGameRacing.h"
#include "CarRacing/CarRole.h"
#include "CarRacing/CarRobot.h"
#include "CarRacing/CarOther.h"
#include "CarRacing/MiRacing_PlayGui.h"
#include "Net/PacketList.h"
#include "Render/Maze.h"
#include "Render/MC_Misc.h"
#include "Render/Terrain.h"
#include <vector>
#ifdef MethodPhyBullet
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "Physic/GL_ShapeDrawer.h"
#ifdef _DEBUG
#pragma message(__FILE__": linking with LinearMath_debug.lib")
#pragma comment(lib,"LinearMath_debug.lib" )
#pragma message(__FILE__": linking with BulletDynamics_debug.lib")
#pragma comment(lib,"BulletDynamics_debug.lib" )
#pragma message(__FILE__": linking with BulletCollision_debug.lib")
#pragma comment(lib,"BulletCollision_debug.lib" )
#else
#pragma message(__FILE__": linking with LinearMath.lib")
#pragma comment(lib,"LinearMath.lib" )
#pragma message(__FILE__": linking with BulletDynamics.lib")
#pragma comment(lib,"BulletDynamics.lib" )
#pragma message(__FILE__": linking with BulletCollision.lib")
#pragma comment(lib,"BulletCollision.lib" )
#endif
#endif
//#include "General/Pce.h"
#define InWaterDis 1
MiniGameRacing* G_RacingGame;
class RoleRacingState:public CharacterState
{
public:
virtual void Enter();
virtual StateReturn Update();
virtual StateReturn Render();
virtual StateReturn OnAnimCallBack(const char* frameName);
virtual void Exit();
};
void RoleRacingState::Enter()
{
}
StateReturn RoleRacingState::Update()
{
Role* role = dynamic_cast<Role*>(m_owner);
if (G_RacingGame->GetGameState() != MS_IntroCamera)
{
// role->SetPos(G_RacingGame->m_myRolePlayer->GetPos());
// role->SetHeading(G_RacingGame->m_myRolePlayer->GetHeading());
}
//role->LogicCharacter::Update();
role->GetRenderCharacter()->Update();
return BreakVisiual;
}
StateReturn RoleRacingState::Render()
{
return ContinueVisiual;
}
StateReturn RoleRacingState::OnAnimCallBack( const char* frameName )
{
//LogicCharacter::OnAnimCallBack(frameName);
Role* role = dynamic_cast<Role*>(m_owner);
if (role == NULL)
{
return ContinueVisiual;
}
if (strcmp(frameName,"end") == 0)
{
bool inWater = role->GetPos().y <= G_SceneMgr->m_waterLevel - InWaterDis;
if (inWater)
{
role->m_renderCharacter->PlayAnim("swim");
}
else
{
//if (role->GetSpeed().Length()<0.1f)
if (G_RacingGame->m_myRolePlayer->GetSpeed().Length()<0.1f)
{
role->m_renderCharacter->PlayAnim("stand");
}
else
{
//m_sound->PlaySound__("data/sound/event_run.wav",true);
role->m_renderCharacter->PlayAnim("drive");
}
}
}
return BreakVisiual;
}
void RoleRacingState::Exit()
{
}
//关于镜头://摄像机tarpos 1驾驶员
class CameraCtrlerRacing: public CameraCtrlerTarget
{
public:
CameraCtrlerRacing();
virtual void Update();
Mode m_eyeView;
CarCharacter* target;
};
CameraCtrlerRacing::CameraCtrlerRacing()
:m_eyeView(ThirdPerson)
,target(NULL)
{
m_distToTar = 40*FitScale_;
}
void CameraCtrlerRacing::Update()
{
if(G_Keyboard->IsKeyPressed(DIK_LCONTROL))
{
if(G_Keyboard->IsKeyUping(DIK_V))
{
m_eyeView = (m_eyeView==FirstPerson)?ThirdPerson:FirstPerson;
}
}
if (G_RacingGame==NULL)
{
m_toBeRemove = true;
return;
}
CarCharacter* car = target? target:G_RacingGame->m_myRolePlayer;
CarStyle* style = car->GetStyle();
if (car)
{
Camera* camera = G_Camera;
if (m_eyeView==FirstPerson)
{
vec3 eyePos = car->GetPos() + (style->driverOffset + vec3(0,style->BodyH,0) ) *FitScale_;
vec3 head = car->m_rot*vec3(0,0,1);
SetTarPos(eyePos+head);
vec3 right = car->m_rot*vec3(-1,0,0);
camera->SetDir(head,Cross(right,head));
m_distToTar = 0.1f;
camera->SetEyePos(eyePos);
}
else
{
//第三人称 tar限制在car的地面投影点 增加车辆腾空感
//或者 tar限制在car周围的盒子内
//或者使用橡皮筋缓动
vec3 tarPos = car->m_massCenterGround;//GetPos();
if (tarPos.y < car->GetPos().y-20)
{
tarPos.y = car->GetPos().y-20;
}
SetTarPos(tarPos);
vec3 head = car->GetHeading();
head.y = 0;
head.Normalize();
head.y = -0.6f;
head.Normalize();
camera->SetDir(head,vec3(0,1,0));
//CheckMouseRot(MOUSE_RIGHT, 10, -HALFPI * 0.2f, HALFPI * 0.2f);
CheckWheelDis(30*FitScale_,500*FitScale_);
camera->SetEyePos(tarPos - head*m_distToTar);
}
CheckSceneCollide(G_RacingGame->m_movieCollide);
//CheckSceneCollide(G_RpgMap->GetCollideMovie());
}
}
//==================^_^==================^_^==================^_^==================^_^
const char* RacingCmdToString(int enumeration)
{
switch(enumeration)
{
case CMD_CarMove :return "CMD_CarMove ";
case CMD_CarDeadRoll:return "CMD_CarDeadRoll";
case CMD_CarReset :return "CMD_CarReset ";
case CMD_BugDead :return "CMD_BugDead ";
case CMD_Anim :return "CMD_Anim ";
default :return "CMD_unknow";
}
return "CMD_unknow";
}
RacingRoad G_RacingRoad;
MiniGameRacing::MiniGameRacing()
:m_roadPath(NULL)
,m_myRolePlayer(NULL)
,m_road(NULL)
{
CmdEnumToString = RacingCmdToString;
G_RacingGame = this;
#ifdef MethodPhyBullet
m_shapeGround = NULL;
m_indexVertexArrays = NULL;
m_vertices = NULL;
m_dynamicsWorld = NULL;
m_constraintSolver = NULL;
//broadphase
m_overlappingPairCache = NULL;
m_dispatcher = NULL;
m_collisionConfiguration = NULL;
#endif
}
MiniGameRacing::~MiniGameRacing()
{
MiniGameRacing::Free();
G_RacingGame = NULL;
}
bool MiniGameRacing::Start()
{
m_myRolePlayer = NULL;
if(!MiniGame::Start())
return false;
m_sceneID = 1;
Frame frame;
frame.SetPos(m_startPos);
if( m_sceneID == 0)
{
if (m_movieScene == NULL)
{
m_gameState = MS_End;
return false;
}
//模型中加载
m_movieScene->SetProgramFrame(&frame);
m_movieScene->Advance();
m_movieCollide->SetProgramFrame(&frame);
m_movieCollide->Advance();
//
if (m_roadPath == NULL)
{
m_roadPath = new Curve;//BSpline;
}
//File file;
//vec3 pos;
//char buf[64];
//sprintf_s(buf,"data/Logic/Map/racingPath%d.path",G_RpgMap->GetCurMapStyle()->ID);
//if (file.Fopen(buf,"rt"))
//{
// m_roadPath = new CCurve;//BSpline;
// file.ReadString();
// int cnt = file.ReadInt();
// for (int i=0;i<cnt;i++)
// {
// pos.x = file.ReadFloat();
// pos.y = file.ReadFloat()+1-295;
// pos.z = file.ReadFloat();
// //m_roadPath->AddKnot(pos);
// m_roadPath->AddPnt(pos);
// }
//}
//else
//{
// m_isEnd = true;
// return false;
//}
vec3 pos;
RendSys::MovieClip wayPoint;
wayPoint.LoadFromFile("data/MiniGame/Racing/RacingRoad_waypoint.movie");
wayPoint.Advance();
int cnt = 46;
char buf[64];
for (int i=0;i<cnt;i++)
{
sprintf_s(buf,"waypoint%02d",i+1);
pos = m_startPos + wayPoint.GetMovieClip(buf)->GetCollideSys().m_max;
pos.y-= 15;
m_roadPath->AddPoint(pos);
}
}
else
{
//随机生成
G_RacingRoad.GenRacingRoad(m_startSeed);
//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_RacingRoad.SaveToCollide(mesh);
}
m_movieCollide->SetProgramFrame(&frame);
m_movieCollide->Advance();
if (m_roadPath == NULL)
{
m_roadPath = new Curve;//BSpline;
}
//
#ifdef _DEBUG
for (int i=1;i<G_RacingRoad.m_path.size();i++)
{
for (int j=0;j<i;j++)
{
if (G_RacingRoad.m_path[i]==G_RacingRoad.m_path[j])
{
Assert(0,"G_RacingRoad.m_path[i]==G_RacingRoad.m_path[j]");
}
}
}
#endif
//vec3 pos;// 路点需要稠密?reset car
for (int i=0;i<G_RacingRoad.m_path.size();i++)
{
//m_roadPath->AddPoint(m_startPos + G_RacingRoad.m_path[i] + vec3(0,-15,0));
m_roadPath->AddPoint(m_startPos + G_RacingRoad.m_path[i] + vec3(0,0,0));
}
}
#ifdef MethodPhyBullet
m_defaultContactProcessingThreshold = BT_LARGE_FLOAT;
m_shapeDrawer = new GL_ShapeDrawer;
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_overlappingPairCache = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000));
m_constraintSolver = new btSequentialImpulseConstraintSolver();
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
//m_dynamicsWorld->setDebugDrawer(&gDebugDrawer);
m_dynamicsWorld->setGravity(btVector3(0,-9.8f*PHYSCALE,0));
MovieClip* movie = m_movieCollide->GetMovieClip("scene");
if (movie)
{
Mesh* mesh = movie->GetMesh();
const int totalVerts = mesh->m_vVertexNum;
const int totalTriangles = mesh->m_trigonNum;
//copy if double
m_vertices = new btVector3[totalVerts];
int* gIndices = new int[totalTriangles*3];
Mesh::Vertex* v = mesh->m_vVertexs;
for (int i=0;i<totalVerts;++i,++v)
{
m_vertices[i].setValue(v->x,v->y,v->z);
}
Mesh::Trigon* tri = mesh->m_trigons;
int index = 0;
for (int i=0;i<totalTriangles;++i,++tri)
{
gIndices[index++] = tri->vIndex[0];
gIndices[index++] = tri->vIndex[1];
gIndices[index++] = tri->vIndex[2];
}
int vertStride = sizeof(btVector3);
int indexStride = sizeof(int)*3;
m_indexVertexArrays = new btTriangleIndexVertexArray(totalTriangles,gIndices,indexStride,
totalVerts,(btScalar*) &m_vertices[0].x(),vertStride);
m_shapeGround = new btBvhTriangleMeshShape(m_indexVertexArrays,true);
btTransform startTran;
startTran.setIdentity();
startTran.setOrigin(btvec3(m_startPos));
localCreateRigidBody(0,startTran,m_shapeGround);
}
Reset();
#endif
//m_road = m_movieCollide->getroad
//
int index = 0;
vec3 raceStartPos = m_roadPath->GetPos(index);
vec3 nextPos = m_roadPath->GetPos((int)index + 1);
vec3 startHeading = nextPos - raceStartPos;
startHeading.Normalize();
//
for (int i=0;i<m_allPlayerNum;i++)
{
CarCharacter* thePlayer = (CarCharacter*)m_miniPlayer[i];
//CarStyle* carStyle = G_StyleMgr->GetStyle<CarStyle>(10006);
CarStyle* carStyle = G_StyleMgr->GetStyle<CarStyle>(10000+(m_miniPlayer[i]->GetPlayerInfo()->roomSlot%7));
//起始位置
vec3 carStartPos;
if(m_allPlayerNum<=1)
{
carStartPos = raceStartPos;
}
else
{
vec3 right = startHeading.Cross(vec3(0,1,0));
carStartPos = raceStartPos+ right*(40/(m_allPlayerNum-1)*(i) - 20)*FitScale_;
}
#ifdef MethodPhyBullet
//
thePlayer->m_dynamicsWorld = m_dynamicsWorld;
thePlayer->m_shapeDrawer = m_shapeDrawer;
#endif
thePlayer->Start();
thePlayer->SetStyle(carStyle);
thePlayer->SetPosHeading(carStartPos,startHeading);
//设置driver
//方案一:driver=new CarDriver; 不需要外挂externState,暂停role的更新,CarDriver处理更新,不需role在视野内,效率稍低但逻辑更独立
// otherRole不禁止绘制,留个静止的分身也没关系,otherplayer更新已在别的客户端停止
//if (IsUnitTesting())
{
thePlayer->m_driver = new CarDriver;
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)*FitScale_);
thePlayer->m_driver->GetRenderCharacter()->PlayAnim("drive");
}
//方案二:driver=role; 需要外挂externState处理role的更新,role进入房间时同时进入视野,且在房间内时禁止退出视野
//if (m_miniPlayer[i]==m_myRolePlayer)
//{
// LogicCharacter* driver = G_MyRole;
// if (driver)
// {
// thePlayer->m_driver = driver;
// driver->SetPos(carStartPos+carStyle->driverOffset*FitScale_);
// driver->SetHeading(startHeading);
// driver->GetRenderCharacter()->PlayAnim("drive");
// driver->SetExternState(new RoleRacingState);
// }
//}
}
G_MyRole->SetExternState(new CharacterState); //otherRole不禁止绘制,留个静止的分身也没关系,otherplayer更新已在别的客户端停止
//设置摄像机
G_Camera->PopCtrler();
G_Camera->PushCtrler(new CameraCtrlerRacing);
//片头摄像机
PushIntroCamera();
//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。
if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);
return true;
}
MiniPlayer* MiniGameRacing::CreatePlayer()
{
return new CarOther;
}
MiniPlayer* MiniGameRacing::CreateRobot()
{
return new CarRobot;
}
MiniPlayer* MiniGameRacing::CreateRole()
{
m_myRolePlayer = new CarRole;
return m_myRolePlayer;
}
bool MiniGameRacing::Stop()
{
G_Camera->PopCtrler();
CameraCtrlerTarget* ctrlerTarget = G_Camera->IsCurCtrler<CameraCtrlerTarget>();
if(ctrlerTarget)
ctrlerTarget->SetTarEntity(G_MyRole);
G_MyRole->SetExternState(NULL);
G_MyRole->GetRenderCharacter()->SetScale(vec3(2.0f,2.0f,2.0f));
//跳出车门
G_MyRole->Jump();
G_GuiMgr->PopGui("MiRacing_PlayGui");
{
if (m_myRolePlayer && m_myRolePlayer->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();
G_Option->m_cfgMotionBlur2 = false;
#ifdef MethodPhyBullet
for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject( obj );
delete obj;
}
SafeDelete(m_shapeGround);
SafeDelete(m_indexVertexArrays);
SafeDelete(m_vertices);
SafeDelete(m_dynamicsWorld);
SafeDelete(m_constraintSolver);
//SafeDelete(broadphase
SafeDelete(m_overlappingPairCache);
SafeDelete(m_dispatcher);
SafeDelete(m_collisionConfiguration);
SafeDelete(m_shapeDrawer);
#endif
return true;
}
bool MiniGameRacing::Free()
{
MiniGame::Free();
SafeDelete(m_roadPath);
return true;
}
bool MiniGameRacing::Update()
{
MiniGame::Update();
if(m_gameState == MS_End)
{
return false;
}
if (m_movieScene)
{
m_movieScene->Advance();
}
if (m_movieCollide)
{
m_movieCollide->Advance();
}
for (int i=0;i<m_allPlayerNum;i++)
{
m_miniPlayer[i]->Update();
}
#ifdef MethodPhyBullet
if (m_dynamicsWorld)
{
float dt = G_Timer->GetStepTimeLimited();
int maxSimSubSteps = 5;//m_idle ? 1 : 2;
float fixedTimeStep = dt*0.25f;// 1/60 fixedTimeStep如果大于dt/3 可能产生震荡?
//fixedTimeStep==0.02 dt==0.09
int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps,fixedTimeStep);
//char buf[256];
//sprintf(buf,"%.3f,%d\n",dt,numSimSteps);
//OutputDebugText(buf);
}
#endif
if(m_myRolePlayer==NULL)
{
return false;
}
switch(m_gameState)
{
case RS_Prepare:
{
m_countDownTime-=G_Timer->GetStepTimeLimited()*3;
if (m_countDownTime<0)
{
m_gameState = MS_Gamming;
}
}
break;
case MS_Gamming:
//计算排行
{
for (int i=0;i<m_allPlayerNum;i++)
{
CarCharacter* carI = dynamic_cast<CarCharacter*>(m_miniPlayer[i]);
int rank = 1;
for (int j=0;j<m_allPlayerNum;j++)
{
CarCharacter* carJ = dynamic_cast<CarCharacter*>(m_miniPlayer[j]);
if (i!=j && carJ->m_roadLength > carI->m_roadLength)
{
rank++;
}
}
carI->m_rank = rank;
}
}
break;
}
G_Option->m_cfgMotionBlur2 = true;
return true;
}
bool MiniGameRacing::Render()
{
if (m_gameState == MS_End)
{
return false;
}
if(m_movieScene)
{
//m_movieScene->RendClip();
}
if(m_movieCollide)
{
//m_movieCollide->RendClip();
}
G_RendDriver->EnableRendState(RS_LIGHTING);
G_RendDriver->PushMatrix();
G_RendDriver->Translatef(m_startPos.x,m_startPos.y,m_startPos.z);
G_RacingRoad.Render();
G_RendDriver->PopMatrix();
for (int i=0;i<m_allPlayerNum;i++)
{
CarCharacter* car = dynamic_cast<CarCharacter*>(m_miniPlayer[i]);
car->Render();
}
#ifdef _DEBUG
G_RendDriver->DisableRendState(RS_LIGHTING);
G_RendDriver->DisableRendState(RS_DEPTH_TEST);
m_roadPath->Render();
#endif
EditRender();
//shader 还没退出
//此处绘制ui会被场景中的水遮罩,比如象棋
return true;
}
void MiniGameRacing::RenderUI()
{
MiniGame::RenderUI();
if (m_gameState == MS_End)
{
return;
}
// G_MyRole->RenderBanner();
//m_myCar->RenderBanner();
if(m_myRolePlayer==NULL)
{
return;
}
///
G_RendDriver->BeginUI();
float left = 150;
char buf[256];
G_FontMgr->GetFontDesc().backStyle = FB_RECT;
G_FontMgr->GetFontDesc().backColor = Color(0.2f,0.3f,1.0f,0.6f);
//目前排名:第 %d 名
sprintf(buf,TextData::GetText("T_RACING_TIP_02" ),m_myRolePlayer->m_rank);
G_FontMgr->TextAtPos(vec2(left, 230),buf);
路程 : %d,%d,%d,%d,%d
//sprintf_s(buf,TextData::GetText("T_RACING_TIP_05" ),int(m_myCar->m_roadLength*100),
// int(dynamic_cast<CarCharacter*>(m_miniPlayer[0])->m_roadLength*100),
// int(dynamic_cast<CarCharacter*>(m_miniPlayer[1])->m_roadLength*100),
// int(dynamic_cast<CarCharacter*>(m_miniPlayer[2])->m_roadLength*100),
// int(dynamic_cast<CarCharacter*>(m_miniPlayer[3])->m_roadLength*100));
//G_FontMgr->TextAtPos(vec2(left, 260),buf);
//剩余生命:%d
sprintf(buf,TextData::GetText("T_RACING_TIP_03" ),m_myRolePlayer->m_liveNum);
G_FontMgr->TextAtPos(vec2(left, 290),buf);
if (m_myRolePlayer->m_wrongWayTime > 0)
{
//方向错误! %d
sprintf(buf,TextData::GetText("T_RACING_TIP_04" ),(int)(m_myRolePlayer->m_wrongWayTime*10));
G_FontMgr->TextAtPos(vec2(left, 320),buf);
}
G_FontMgr->GetFontDesc().backStyle = FB_NULL;
G_RendDriver->Color4f(1,1,1,1);
//速度计 真实的速度计 比例尺1:5
m_texSpeedo->Bind();
G_RendDriver->DrawTextureRect(RectF(100,400,200,200));
//指针
m_texNeedle->Bind();
float rad = -m_myRolePlayer->GetSpeed().Length()/FitScale_/5/130*(1.5f*_PI);
rad += _PI*0.41f;
RectF src(0,1,1,-1);
G_RendDriver->DrawTextureRect(RectF(100,400,200,200),src,vec2(100,100),rad,ET_SCALE);
//倒计时
switch(m_gameState)
{
case RS_Prepare:
{
int index = m_countDownTime;
if (index>3)
{
index = 3;
}
else if (index<0)
{
index = 0;
}
Texture* texture = m_texCountdown[index];
texture->Bind();
G_RendDriver->DrawTextureRect(vec2(G_Window->m_iWidth/2-texture->GetWidth()/2,G_Window->m_iHeight/2-texture->GetHeight()/2));
}
break;
}
}
#ifdef MethodFourWheel
void MiniGameRacing::EditRender()
{
}
#endif
#ifdef MethodPhyBullet
void MiniGameRacing::EditRender()
{
int debugMode = -1;
if(m_debugSwitch[0]==true)
debugMode = btIDebugDraw::DBG_DrawWireframe;
if(m_debugSwitch[1]==true)
debugMode = 0;
if (debugMode==-1)
{
return;
}
G_RendDriver->DisableRendState(RS_LIGHTING);
G_RendDriver->EnableRendState(RS_DEPTH_TEST);
G_RendDriver->DepthMask(true);
for (int i=0;i<m_allPlayerNum;i++)
{
CarCharacter* car = dynamic_cast<CarCharacter*>(m_miniPlayer[i]);
car->EditRender(debugMode);
}
//return;
btScalar m[16];
btVector3 worldBoundsMin,worldBoundsMax;
m_dynamicsWorld->getBroadphase()->getBroadphaseAabb(worldBoundsMin,worldBoundsMax);
btMatrix3x3 rot;
rot.setIdentity();
const int numObjects = m_dynamicsWorld->getNumCollisionObjects();
for(int i=0;i<numObjects;i++)
{
btCollisionObject* colObj=m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body=btRigidBody::upcast(colObj);
if(body&&body->getMotionState())
{
btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState();
myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(m);
rot=myMotionState->m_graphicsWorldTrans.getBasis();
}
else
{
colObj->getWorldTransform().getOpenGLMatrix(m);
rot=colObj->getWorldTransform().getBasis();
}
btVector3 wireColor(1.f,1.0f,0.5f); //wantsdeactivation
if(i&1)
wireColor=btVector3(0.f,0.0f,1.f);
if (colObj->getActivationState() == 1) //active
{
if (i & 1)
wireColor += btVector3 (1.f,0.f,0.f);
else
wireColor += btVector3 (.5f,0.f,0.f);
}
if(colObj->getActivationState()==2) //ISLAND_SLEEPING
{
if(i&1)
wireColor += btVector3 (0.f,1.f, 0.f);
else
wireColor += btVector3 (0.f,0.5f,0.f);
}
btVector3 aabbMin,aabbMax;
m_dynamicsWorld->getBroadphase()->getBroadphaseAabb(aabbMin,aabbMax);
aabbMin-=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT);
aabbMax+=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT);
m_dynamicsWorld->getDebugDrawer()->drawAabb(aabbMin,aabbMax,btVector3(1,1,1));
//m_shapeDrawer->drawOpenGL(m,colObj->getCollisionShape(),wireColor,0,aabbMin,aabbMax);
m_shapeDrawer->drawOpenGL(m,colObj->getCollisionShape(),wireColor,debugMode,aabbMin,aabbMax);
}
//if (m_dynamicsWorld)
// m_dynamicsWorld->debugDrawWorld();
}
void MiniGameRacing::Reset()
{
//gVehicleSteering = 0.f;
//m_carChassis->setCenterOfMassTransform(btTransform::getIdentity());
//m_carChassis->setLinearVelocity(btVector3(0,0,0));
//m_carChassis->setAngularVelocity(btVector3(0,0,0));
//m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_carChassis->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
//if (m_vehicle)
//{
// m_vehicle->resetSuspension();
// for (int i=0;i<m_vehicle->getNumWheels();i++)
// {
// //synchronize the wheels with the (interpolated) chassis worldtransform
// m_vehicle->updateWheelTransform(i,true);
// }
//}
}
btRigidBody* MiniGameRacing::localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape)
{
btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
bool isDynamic = (mass != 0.f);
btVector3 localInertia(0,0,0);
if (isDynamic)
shape->calculateLocalInertia(mass,localInertia);
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
#define USE_MOTIONSTATE 1
#ifdef USE_MOTIONSTATE
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,shape,localInertia);
btRigidBody* body = new btRigidBody(cInfo);
body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);
#else
btRigidBody* body = new btRigidBody(mass,0,shape,localInertia);
body->setWorldTransform(startTransform);
#endif//
m_dynamicsWorld->addRigidBody(body);
return body;
}
#endif
void MiniGameRacing::OnSize()
{
}
void MiniGameRacing::OnStartCameraEnd()
{
m_gameState = RS_Prepare;
m_countDownTime = 4;
PlaySound__("data/sound/car/countdown.wav");
}
bool MiniGameRacing::KeepResource(bool once,int& circle,String& nextTip)
{
if(!G_TextureMgr->AddTexture(m_texNeedle,"data/gui/minigame/racing/needle.png"))
return false;
if(!G_TextureMgr->AddTexture(m_texSpeedo,"data/gui/minigame/racing/speedo.png"))
return false;
if(!G_TextureMgr->AddTexture(m_texCountdown[0],"data/gui/minigame/racing/countdown0.png"))
return false;
if(!G_TextureMgr->AddTexture(m_texCountdown[1],"data/gui/minigame/racing/countdown1.png"))
return false;
if(!G_TextureMgr->AddTexture(m_texCountdown[2],"data/gui/minigame/racing/countdown2.png"))
return false;
if(!G_TextureMgr->AddTexture(m_texCountdown[3],"data/gui/minigame/racing/countdown3.png"))
return false;
static bool LoadedStyles = false;
if (LoadedStyles==false)
{
/* car10000~11000
*/
LoadedStyles = true;
G_StyleMgr->LoadStyles<CarStyle>("data/Logic/Style/Car.style",Enum_Style(CarStyle));
}
//keep car
{
PROFILEFUN("MiniGameRacing::KeepResource(bool once,int& circle,String& nextTip);",0.0f,ALWAYSHIDE);
StyleGroupRef styles(Enum_Style(CarStyle));
CarStyle* it = (CarStyle*)styles.GetFirst();
while (it)
{
if(!G_MovieClipMgr->KeepMovie((*it).modelName))
return false;
if(!G_RpgMap->KeepBoneStyle((*it).boneStyle))
{
//return false;
}
it = (CarStyle*)styles.GetNext();
}
}
//keep road
if( m_sceneID == 0)
{
//模型中加载
if (m_movieScene == NULL)
{
m_movieScene = new RendSys::MovieClip;
}
{
LoadConfig loader(LoadConfig::GenDonotReShrinkBound,true,true);
m_movieScene->LoadFromFile("data/MiniGame/Racing/RacingRoad.movie",&loader);
if (m_movieScene->IsLoadComplete() == false)
{
m_movieScene->FreeMovie();
SafeDelete(m_movieScene);
return false;
}
m_movieScene->Advance();
}
if (m_movieCollide == NULL)
{
m_movieCollide = new RendSys::MovieClip;
}
{
LoadConfig loader(LoadConfig::GenDonotReShrinkBound,false,false);
m_movieCollide->LoadFromFile("data/MiniGame/Racing/RacingRoad.movie",&loader);
if (m_movieCollide->IsLoadComplete() == false)
{
m_movieCollide->FreeMovie();
SafeDelete(m_movieCollide);
return false;
}
m_movieCollide->Advance();
}
}
else
{
//随机生成
if (m_movieCollide == NULL)
{
m_movieCollide = new RendSys::MovieClip;
}
LoadConfig loader(LoadConfig::GenDonotReShrinkBound,false,false);
m_movieCollide->LoadFromFile("data/MiniGame/Racing/collide.movie",&loader);
}
// sprintf_s(buf,"%sdrive.bone",boneStyle);
// m_keepAnim.push_back(SkeletonPtr());G_SkeletonMgr->AddSkeleton(m_keepAnim.back(),buf);
return true;
}
int MiniGameRacing::ProcessPacketCmd(PacketBase* packet)
{
int cmd;
packet->ReadValue(cmd);
switch(cmd)
{
case CMD_CarMove:
{
int roomSlot;
vec3 pos;
vec3 rot;
vec3 lineVelocity;
vec3 angVelocity;
float roadLength;
packet->ReadValue(roomSlot);
packet->ReadValue(pos.x);
packet->ReadValue(pos.y);
packet->ReadValue(pos.z);
packet->ReadValue(rot.x);
packet->ReadValue(rot.y);
packet->ReadValue(rot.z);
packet->ReadValue(lineVelocity.x);
packet->ReadValue(lineVelocity.y);
packet->ReadValue(lineVelocity.z);
packet->ReadValue(angVelocity.x);
packet->ReadValue(angVelocity.y);
packet->ReadValue(angVelocity.z);
packet->ReadValue(roadLength);
//
CarCharacter* car = dynamic_cast<CarCharacter*>(GetPlayerFromSlot(roomSlot));
if (car)
{
car->SetPosEuler(pos,rot);
car->SetSpeed(lineVelocity,angVelocity);
car->m_roadLength = roadLength;
}
}
break;
case CMD_CarDeadRoll:
{
int roomSlot;
vec3 pos;
vec3 rot;
vec3 lineVelocity;
vec3 angVelocity;
vec3 deadRotRad;
packet->ReadValue(roomSlot);
packet->ReadValue(pos.x);
packet->ReadValue(pos.y);
packet->ReadValue(pos.z);
packet->ReadValue(rot.x);
packet->ReadValue(rot.y);
packet->ReadValue(rot.z);
packet->ReadValue(lineVelocity.x);
packet->ReadValue(lineVelocity.y);
packet->ReadValue(lineVelocity.z);
packet->ReadValue(angVelocity.x);
packet->ReadValue(angVelocity.y);
packet->ReadValue(angVelocity.z);
//packet->ReadArray(m_deadRotMat.mat,sizeof(float)*16);
packet->ReadArray(&deadRotRad.x,sizeof(float)*3);
//
CarCharacter* car = dynamic_cast<CarCharacter*>(GetPlayerFromSlot(roomSlot));
if (car)
{
car->SetPosEuler(pos,rot);
car->SetSpeed(lineVelocity,angVelocity);
car->TryChangeState(RS_DeadRoll);
car->m_deadRotRad = deadRotRad;
}
}
break;
case CMD_CarReset:
{
int roomSlot;
vec3 pos;
vec3 rot;
packet->ReadValue(roomSlot);
packet->ReadValue(pos.x);
packet->ReadValue(pos.y);
packet->ReadValue(pos.z);
packet->ReadValue(rot.x);
packet->ReadValue(rot.y);
packet->ReadValue(rot.z);
//
CarCharacter* car = dynamic_cast<CarCharacter*>(GetPlayerFromSlot(roomSlot));
if (car)
{
car->SetPosEuler(pos,rot);
car->SetSpeed(vec3(),vec3());
car->TryChangeState(RS_Racing);
}
}
break;
}
//for (int i=0;i<m_aiPlayerNum;i++)
//{
// m_miniPlayer[i].ProcessPacketCmd(packet);
//}
return 0;
}
vec3 MiniGameRacing::GetRoadPathPos(float roadLength)
{
//整数部分为整圈数
int size = G_RacingGame->m_roadPath->GetPointNum();
int circleNum = roadLength;
float index = size*(roadLength-circleNum);
return G_RacingGame->m_roadPath->GetPosf(index);
}
bool MiniGameRacing::IsOnRoad(vec3& pos)
{
//no FitScale_
//if (m_road
// &&
// )
//{
//}
//||NULL!=m_road->IntersectTray(res));
//if (GetHeightOnMovie(m_road,pos,20,3000))
//{
// return;
//}
//if (GetHeightOnMovie(m_road,pos,-20,-3000))
//{
// return;
//}
return true;
}
void MiniGameRacing::ToggleViewEye(int eyeMode)
{
CameraCtrlerRacing* ctrler = dynamic_cast<CameraCtrlerRacing*>(G_Camera->GetCurCtrler());
if (ctrler)
{
ctrler->m_eyeView = (CameraCtrlerRacing::Mode)eyeMode;
}
}
void MiniGameRacing::ToggleObserver()
{
static int index = 0;
index++;
index %= m_allPlayerNum;
CameraCtrlerRacing* ctrler = dynamic_cast<CameraCtrlerRacing*>(G_Camera->GetCurCtrler());
if (ctrler)
{
ctrler->target = (CarCharacter*)GetPlayerFromIndex(index);
}
}
//==================^_^==================^_^==================^_^==================^_^
struct WayPoint
{
int x,y;
char roadType[2]; //A B C... AB BA AC CA...
int roadLen; //当前类型路的累积长度
char barrierType[2];
int barrierLen;
char wallType[2];
int wallLen;
int parentDir;
};
#define MaxBatchVertex 30000
RacingRoad::RacingRoad()
:m_batchs(NULL)
,m_batchNum(0)
,m_batchMovieNum(0)
,m_movieLib(NULL)
{
}
RacingRoad::~RacingRoad()
{
Free();
}
void RacingRoad::Free()
{
SafeDeleteArray(m_batchs);
m_batchNum = 0;
m_batchMovieNum = 0;
SafeDelete(m_movieLib);
}
void RacingRoad::AddMovie(const char* name_,const char* type_,const vec3& pos,int rot)
{
if(m_batchMovieNum<MaxBatchMovie)
{
BatchMovie& batchMovie = m_batchMovies[m_batchMovieNum];
sprintf(batchMovie.name,"%s%s",name_,type_);
batchMovie.movie = m_movieLib->GetMovieClip(batchMovie.name);
batchMovie.pos = pos;
batchMovie.rot = rot;
m_batchMovieNum++;
if (batchMovie.movie==NULL)
{
int a = 0;
}
}
else
{
OutputDebugText("over max batch movie");
}
}
//void AddMovie(const char* name,int rot_)
//{
// sprintf(buf,"%s%s",name,type_);
// batchMovie.movie = (RendSys::MC_Frame*)movieLib->GetMovieClip(buf);
// batchMovie.pos = pos_;
// batchMovie.rot = rot_;
// batchMovieNum++;
//}
void RacingRoad::GenRacingRoad(int seed)
{
Free();
G_TextureMgr->AddTexture(m_texture[0],"data/minigame/racing/cart/route.png");
G_TextureMgr->AddTexture(m_texture[1],"data/minigame/racing/cart/temple.png");
G_TextureMgr->AddTexture(m_texture[2],"data/minigame/racing/cart/temple2.png");
G_TextureMgr->AddTexture(m_texture[3],"data/minigame/racing/cart/temple3.png");
G_TextureMgr->AddTexture(m_texture[4],"data/minigame/racing/cart/route2.png");
m_movieLib = new RendSys::MovieClip;
m_movieLib->LoadFromFile("data/minigame/racing/cart/scene2.movie");
//方案一 使用放样拼接 分叉放样
//todo 。。。
Srand(seed);
//方案二 使用迷宫拼接
//地形
TerrainData terrain;
terrain.New(65,65,120,120);
//terrain.FillFractSurface(0,0,300,0.5f,false,0);
terrain.FillFractSurface(0,0,500,0.2f,false,0);
生成迷宫
//Maze maze;
maze.AllocMaze(50,50,Maze::Unused);
//maze.GeneratePrimTrunkMaze(11,11);
maze.GeneratePrimTrunkMaze(7,7);
//maze.AdjustSpace(3,3,1,1);
//maze.RandEnterExit();
//maze.OutputMaze();
//生成迷宫
Maze maze;
//maze.GenerateTspSquareMaze(40,40,&m_path);
maze.GenerateTspSquareMaze(20,20,&m_path);
maze.RandEnterExit();
maze.OutputMaze();
//导航路径
float offsetX = maze.m_mazeWidth*120/2;
float offsetZ = maze.m_mazeHeight*120/2;
for (int i=0;i<m_path.size();i++)
{
m_path[i].x = m_path[i].x*120 - offsetX;
m_path[i].z = m_path[i].y*120 - offsetZ;
//叠加地形高度
m_path[i].y = terrain.GetHeightf((m_path[i].x+offsetX)*(1/120.0f)+0.5f,(m_path[i].z+offsetZ)*(1/120.0f)+0.5f);
m_path[i] *= FitScale_;
}
//拓宽假路 假路可以撑开墙壁 假路上可以摆放建筑
//todo 。。。
char roadSeeds [128][128][2];
char barrierSeeds[128][128][2];
char wallSeeds [128][128][2];
memset(roadSeeds ,0,sizeof(roadSeeds ));
memset(barrierSeeds,0,sizeof(barrierSeeds));
memset(wallSeeds ,0,sizeof(wallSeeds ));
char accessFlags[128][128];
memset(accessFlags,0,sizeof(accessFlags));
int roadFlags[128][128];
//遍历 设置路的类型
{
for (int y = 0; y < maze.m_mazeHeight; y++)
{
for (int x = 0; x < maze.m_mazeWidth; x++)
{
int roadFlag = 0;
if (y>0 && maze.mazeBlockType(x,y-1)==Maze::Road)
{
roadFlag|=1;
}
if (y<maze.m_mazeHeight-1 && maze.mazeBlockType(x,y+1)==Maze::Road)
{
roadFlag|=2;
}
if (x>0 && maze.mazeBlockType(x-1,y)==Maze::Road)
{
roadFlag|=4;
}
if (x<maze.m_mazeWidth-1 && maze.mazeBlockType(x+1,y)==Maze::Road)
{
roadFlag|=8;
}
if (x>0 && y>0 && maze.mazeBlockType(x-1,y-1) == Maze::Road)
{
roadFlag |= 16;
}
if (x<maze.m_mazeWidth-1 && y>0 && maze.mazeBlockType(x+1,y-1) == Maze::Road)
{
roadFlag |= 32;
}
if (x>0 && y<maze.m_mazeHeight-1 && maze.mazeBlockType(x-1,y+1) == Maze::Road)
{
roadFlag |= 64;
}
if (x<maze.m_mazeWidth-1 && y<maze.m_mazeHeight-1 && maze.mazeBlockType(x+1,y+1) == Maze::Road)
{
roadFlag |= 128;
}
roadFlags[y][x] = roadFlag;
}
}
std::list<WayPoint> path;
//添加第一个点
path.push_back(WayPoint());
int x = maze.m_enter.x;
int y = maze.m_enter.y;
accessFlags[x][y] = true;
WayPoint& newWayPoint = path.back();
newWayPoint.x = x;
newWayPoint.y = y;
newWayPoint.parentDir = -1;
newWayPoint.roadType[0] = 'A';
newWayPoint.roadType[1] = 0;
newWayPoint.roadLen = 0;
newWayPoint.barrierType[0] = 'A';
newWayPoint.barrierType[1] = 0;
newWayPoint.barrierLen = 0;
newWayPoint.wallType[0] = 'A';
newWayPoint.wallType[1] = 0;
newWayPoint.wallLen = 0;
roadSeeds [y][x][0] = 'A';
roadSeeds [y][x][1] = 0;
barrierSeeds [y][x][0] = 'A';
barrierSeeds [y][x][1] = 0;
wallSeeds [y][x][0] = 'A';
wallSeeds [y][x][1] = 0;
while(path.size()>0)
{
WayPoint& curWayPoint = path.back();
x = curWayPoint.x;
y = curWayPoint.y;
int wallFlag = roadFlags[y][x]; //8邻居
int roadFlag = wallFlag&(1|2|4|8);//4邻居
int nextWay[4];
int nextWayNum = 0;
if (roadFlag&1)
{
if (accessFlags[x][y-1]==false)
nextWay[nextWayNum++] = 1;
}
if (roadFlag&2)
{
if (accessFlags[x][y+1]==false)
nextWay[nextWayNum++] = 2;
}
if (roadFlag&4)
{
if (accessFlags[x-1][y]==false)
nextWay[nextWayNum++] = 3;
}
if (roadFlag&8)
{
if (accessFlags[x+1][y]==false)
nextWay[nextWayNum++] = 4;
}
//
if (nextWayNum>0)
{
int newDir = nextWay[rand()%nextWayNum];
bool bStraight = (roadFlag==3 || roadFlag==12);
bool bStraight2 = (wallFlag==3 || wallFlag==12);
//改变路的类型
if (curWayPoint.roadLen>4
&& bStraight == true //无分叉拐弯的直路才允许改变
&& rand()%4==0
)
{
int curType = curWayPoint.roadType[0];
int newType = curType+1;
if (newType>'B')//循环
newType = 'A';
curWayPoint.roadType[0] = newType;
curWayPoint.roadType[1] = 0;
curWayPoint.roadLen = 0;
if (newType!=curType)
{
switch(newDir)
{
case 1: case 3:
roadSeeds[curWayPoint.y][curWayPoint.x][0] = curType;
roadSeeds[curWayPoint.y][curWayPoint.x][1] = newType; //AB A=>B 过渡类型
break;
case 2: case 4:
roadSeeds[curWayPoint.y][curWayPoint.x][0] = newType;
roadSeeds[curWayPoint.y][curWayPoint.x][1] = curType; //BA B=>A
break;
}
}
}
//改栅栏的类型
if (curWayPoint.barrierLen>4
&& bStraight == true //无分叉拐弯的直路才允许改变
&& rand()%4==0
)
{
int curType = curWayPoint.barrierType[0];
int newType = curType+1;
if (newType>'B')//循环
newType = 'A';
curWayPoint.barrierType[0] = newType;
curWayPoint.barrierType[1] = 0;
curWayPoint.barrierLen = 0;
if (newType!=curType)
{
switch(newDir)
{
case 1: case 3:
barrierSeeds[curWayPoint.y][curWayPoint.x][0] = curType;
barrierSeeds[curWayPoint.y][curWayPoint.x][1] = newType; //AB A=>B 过渡类型
break;
case 2: case 4:
barrierSeeds[curWayPoint.y][curWayPoint.x][0] = newType;
barrierSeeds[curWayPoint.y][curWayPoint.x][1] = curType; //BA B=>A
break;
}
}
}
//改变外墙的类型
if (curWayPoint.wallLen>4
&& bStraight2 == true //无分叉拐弯的直路才允许改变 //前一个 后一个也不能有分叉和拐弯
&& rand()%3==0
)
{
int curType = curWayPoint.wallType[0];
int newType = curType+1;
//if (newType>'F')//循环
// newType = 'A';
newType = RandRange(int('A'),int('F'));
curWayPoint.wallType[0] = newType;
curWayPoint.wallType[1] = 0;
curWayPoint.wallLen = 0;
if (newType!=curType)
{
switch(newDir)
{
case 1: case 3:
wallSeeds[curWayPoint.y][curWayPoint.x][0] = curType;
wallSeeds[curWayPoint.y][curWayPoint.x][1] = newType; //AB A=>B 过渡类型
break;
case 2: case 4:
wallSeeds[curWayPoint.y][curWayPoint.x][0] = newType;
wallSeeds[curWayPoint.y][curWayPoint.x][1] = curType; //BA B=>A
break;
}
}
}
//
path.push_back(WayPoint());
WayPoint& newWayPoint = path.back();
switch(newDir)
{
case 1:x=curWayPoint.x;y=curWayPoint.y-1;break;
case 2:x=curWayPoint.x;y=curWayPoint.y+1;break;
case 3:x=curWayPoint.x-1;y=curWayPoint.y;break;
case 4:x=curWayPoint.x+1;y=curWayPoint.y;break;
}
accessFlags[x][y] = true;
newWayPoint.x = x;
newWayPoint.y = y;
newWayPoint.parentDir = newDir;
newWayPoint.roadType[0] = curWayPoint.roadType[0];
newWayPoint.roadType[1] = 0;
newWayPoint.roadLen = curWayPoint.roadLen+1;
roadSeeds [y][x][0] = newWayPoint.roadType[0];
roadSeeds [y][x][1] = 0;
newWayPoint.barrierType[0] = curWayPoint.barrierType[0];
newWayPoint.barrierType[1] = 0;
newWayPoint.barrierLen = curWayPoint.barrierLen+1;
barrierSeeds[y][x][0] = newWayPoint.barrierType[0];
barrierSeeds[y][x][1] = 0;
newWayPoint.wallType[0] = curWayPoint.wallType[0];
newWayPoint.wallType[1] = 0;
newWayPoint.wallLen = curWayPoint.wallLen+1;
wallSeeds [y][x][0] = newWayPoint.wallType[0];
wallSeeds [y][x][1] = 0;
}
else
{
path.pop_back();
}
}
}
{
char buf[2048];
char* pBuf = buf;
//for (int y = maze.m_mazeHeight-1; y>=0; y--)
for (int y = 0; y < maze.m_mazeHeight; y++)
{
pBuf = buf;
for (int x = 0; x < maze.m_mazeWidth; x++)
{
pBuf[0] = wallSeeds[y][x][0];
pBuf[1] = wallSeeds[y][x][1];
if (pBuf[0]==0)
pBuf[0] = ' ';
if (pBuf[1]==0)
pBuf[1] = ' ';
pBuf[2] = '|';
pBuf+=3;
}
*pBuf = '\0';
OutputDebugText(buf);
OutputDebugText("\n");
}
}
//
m_batchNum = 5;
m_batchs = new Batch[m_batchNum];
for (int i=0;i<m_batchNum;i++)
{
m_batchs[i].ID = i;
m_batchs[i].m_texture = m_texture[i];
m_batchs[i].Allocate(MaxBatchVertex);
}
//
vec3 pos_;
int roadFlag;
int wallFlag;
for (int y = 0; y < maze.m_mazeHeight; y++)
{
for (int x = 0; x < maze.m_mazeWidth; x++)
{
if (m_batchMovieNum>MaxBatchMovie)
{
break;
}
pos_.x = x*120 - offsetX;
pos_.z = y*120 - offsetZ;
Maze::Block& block = maze.mazeBlock(x,y);
wallFlag = roadFlags[y][x]; //8邻居
roadFlag = wallFlag&(1|2|4|8);//4邻居
char roadTypeBuf[32];
char barrierTypeBuf[32];
char wallTypeBuf[32];
if(block.type == Maze::Road)
{
char* roadSeed = roadSeeds[y][x];
roadTypeBuf[0] = roadSeed[0]; //strcpy
roadTypeBuf[1] = roadSeed[1];
roadTypeBuf[2] = 0;
char* barrierSeed = barrierSeeds[y][x];
barrierTypeBuf[0] = barrierSeed[0]; //strcpy
barrierTypeBuf[1] = barrierSeed[1];
barrierTypeBuf[2] = 0;
char* wallSeed = wallSeeds[y][x];
int vari = 0;
road_straightA0~3, 0的几率较大
//{
// vari = rand()%6;
// if(vari>3)vari = 0;
//}
//road
switch(roadFlag)
{
//island
case 0:
AddMovie("road_straight",roadTypeBuf, pos_, 0); //?
break;
//straight
case 3:
if(roadSeed[1]==0)//A0~3 直墙 非过渡
{
roadTypeBuf[1] = '0' + vari;
roadTypeBuf[2] = 0;
}
AddMovie("road_straight",roadTypeBuf, pos_, 0);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_straight","D0", pos_, 0);
AddMovie("barrier",barrierTypeBuf, pos_, 0);
AddMovie("barrier",barrierTypeBuf, pos_, 180);
break;
case 12:
if(roadSeed[1]==0)//A0~3 直墙 非过渡
{
roadTypeBuf[1] = '0' + vari;
roadTypeBuf[2] = 0;
}
AddMovie("road_straight",roadTypeBuf, pos_, 90);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_straight","D0", pos_, 90);
AddMovie("barrier",barrierTypeBuf, pos_, 90);
AddMovie("barrier",barrierTypeBuf, pos_, 270);
break;
//end
case 1:
AddMovie("road_end",roadTypeBuf, pos_, 0);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_end","D", pos_, 0);
break;
case 2:
AddMovie("road_end",roadTypeBuf, pos_, 180);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_end","D", pos_, 180);
break;
case 4:
AddMovie("road_end",roadTypeBuf, pos_, 90);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_end","D", pos_, 90);
break;
case 8:
AddMovie("road_end",roadTypeBuf, pos_, 270);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_end","D", pos_, 270);
break;
//corner
case 5:
AddMovie("road_corner",roadTypeBuf, pos_, 90);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_corner","D", pos_, 90);
AddMovie("barrier",barrierTypeBuf, pos_, 270);
AddMovie("barrier",barrierTypeBuf, pos_, 0);
break;
case 9:
AddMovie("road_corner",roadTypeBuf, pos_, 0);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_corner","D", pos_, 0);
AddMovie("barrier",barrierTypeBuf, pos_, 180);
AddMovie("barrier",barrierTypeBuf, pos_, 270);
break;
case 6:
AddMovie("road_corner",roadTypeBuf, pos_, 180);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_corner","D", pos_, 180);
AddMovie("barrier",barrierTypeBuf, pos_, 0);
AddMovie("barrier",barrierTypeBuf, pos_, 90);
break;
case 10:
AddMovie("road_corner",roadTypeBuf, pos_, 270);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_corner","D", pos_, 270);
AddMovie("barrier",barrierTypeBuf, pos_, 90);
AddMovie("barrier",barrierTypeBuf, pos_, 180);
break;
//fork
case 7:
AddMovie("road_fork",roadTypeBuf, pos_, 90);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_fork","D", pos_, 90);
AddMovie("barrier",barrierTypeBuf, pos_, 0);
break;
case 14:
AddMovie("road_fork",roadTypeBuf, pos_, 180);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_fork","D", pos_, 180);
AddMovie("barrier",barrierTypeBuf, pos_, 90);
break;
case 11:
AddMovie("road_fork",roadTypeBuf, pos_, 270);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_fork","D", pos_, 270);
AddMovie("barrier",barrierTypeBuf, pos_, 180);
break;
case 13:
AddMovie("road_fork",roadTypeBuf, pos_, 0);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_fork","D", pos_, 0);
AddMovie("barrier",barrierTypeBuf, pos_, 270);
break;
//cross
case 15:
AddMovie("road_cross",roadTypeBuf, pos_, 0);
if(wallSeed[0]=='D'&&wallSeed[1]==0)AddMovie("road_cross","D", pos_, 0);
break;
}
}
else
{
//wall
if (wallFlag==0)
{
continue; //不是路边
}
char* wallSeed = NULL;
if (wallFlag&1)
wallSeed = wallSeeds[y-1][x];
else if (wallFlag&2)
wallSeed = wallSeeds[y+1][x];
else if (wallFlag&4)
wallSeed = wallSeeds[y][x-1];
else if (wallFlag&8)
wallSeed = wallSeeds[y][x+1];
else if (wallFlag&16)
wallSeed = wallSeeds[y-1][x-1];
else if (wallFlag&32)
wallSeed = wallSeeds[y-1][x+1];
else if (wallFlag&64)
wallSeed = wallSeeds[y+1][x-1];
else if (wallFlag&128)
wallSeed = wallSeeds[y+1][x+1];
if (wallSeed==NULL
||(wallSeed[0]=='D'&&wallSeed[1]==0)//细隧道拼接方法比较特殊 同路
)
{
wallTypeBuf[0] = 0; //空模型
}
else
{
wallTypeBuf[0] = wallSeed[0]; //strcpy
wallTypeBuf[1] = wallSeed[1];
wallTypeBuf[2] = 0;
}
int vari = 0;
//wall_straightA0~3, 0的几率较大
if (wallSeed[0]=='C')//tree
{
vari = rand()%8;
if(vari>5)vari = 0;
}
else
{
vari = rand()%6;
if(vari>3)vari = 0;
}
switch(wallFlag)
{
case 1:
case 1+16:
case 1+32:
case 1+16+32:
if(wallSeed[1]==0)//A0~3 直墙 非过渡
{
wallTypeBuf[1] = '0' + vari;
wallTypeBuf[2] = 0;
}
AddMovie("wall_straight",wallTypeBuf, pos_, 90);
break;
case 2:
case 2+64:
case 2+128:
case 2+64+128:
if(wallSeed[1]==0)//A0~3 直墙 非过渡
{
wallTypeBuf[1] = '0' + vari;
wallTypeBuf[2] = 0;
}
AddMovie("wall_straight",wallTypeBuf, pos_, 271);
break;
case 4:
case 4+16:
case 4+64:
case 4+16+64:
if(wallSeed[1]==0)//A0~3 直墙 非过渡
{
wallTypeBuf[1] = '0' + vari;
wallTypeBuf[2] = 0;
}
AddMovie("wall_straight",wallTypeBuf, pos_, 181);
break;
case 8:
case 8+32:
case 8+128:
case 8+32+128:
if(wallSeed[1]==0)//A0~3 直墙 非过渡
{
wallTypeBuf[1] = '0' + vari;
wallTypeBuf[2] = 0;
}
AddMovie("wall_straight",wallTypeBuf, pos_, 0);
break;
//corner
case 16:
AddMovie("wall_cornerF",wallTypeBuf, pos_, 90);
break;
case 32:
AddMovie("wall_cornerF",wallTypeBuf, pos_, 0);
break;
case 64:
AddMovie("wall_cornerF",wallTypeBuf, pos_, 180);
break;
case 128:
AddMovie("wall_cornerF",wallTypeBuf, pos_, 270);
break;
//corner2
case 32+1+16+4+64:
AddMovie("wall_cornerM",wallTypeBuf, pos_, 180);
break;
case 16+4+64+2+128:
AddMovie("wall_cornerM",wallTypeBuf, pos_, 270);
break;
case 64+2+128+8+32:
AddMovie("wall_cornerM",wallTypeBuf, pos_, 0);
break;
case 128+8+32+1+16:
AddMovie("wall_cornerM",wallTypeBuf, pos_, 90);
break;
}
}
}
}
vec3 pos;
vec3 normal;
mat3* mat;
mat3 mat90,mat180,mat270,mat180M,mat270M;
mat90.FromRotateY(_PI/2);
mat180.FromRotateY(_PI);
mat270.FromRotateY(-_PI/2);
mat3 mirror;
mirror.FromMirrorZ();
mat180M = mat180*mirror;
mat270M = mat270*mirror;
Batch* batch;
RendSys::Mesh* mesh;
BatchMovie* blockMovie;
for (int i=0;i<m_batchMovieNum;i++)
{
blockMovie = &m_batchMovies[i];
if (blockMovie->movie==NULL)
continue;
if(strstr(blockMovie->movie->GetTextureName(),"route."))
batch = &m_batchs[0];
else if(strstr(blockMovie->movie->GetTextureName(),"temple."))
batch = &m_batchs[1];
else if(strstr(blockMovie->movie->GetTextureName(),"temple2."))
batch = &m_batchs[2];
else if(strstr(blockMovie->movie->GetTextureName(),"temple3."))
batch = &m_batchs[3];
else
batch = &m_batchs[4];
mesh = blockMovie->movie->GetMesh();
//
if(batch->m_indexNum+mesh->m_trigonNum*3 > MaxBatchVertex)
continue;
if(batch->m_vVertexNum+mesh->m_vVertexNum > MaxBatchVertex)
continue;
switch(blockMovie->rot)
{
case 0 : mat = NULL; break;
case 90 : mat = &mat90; break;
case 180: mat = &mat180;break;
case 270: mat = &mat270;break;
case 181: mat = &mat180M;break;
case 271: mat = &mat270M;break;
}
int startVertex = batch->m_vVertexNum;
//赋值索引
RendSys::Mesh::Trigon* srcTrigon = mesh->m_trigons;
IndexInt* startIndex = &batch->m_indexs[batch->m_indexNum];
for (int j = 0; j < mesh->m_trigonNum; j++,srcTrigon++,startIndex+=3)
{
startIndex[0] = startVertex + srcTrigon->vIndex[0];
startIndex[1] = startVertex + srcTrigon->vIndex[1];
startIndex[2] = startVertex + srcTrigon->vIndex[2];
}
//赋值点
RendSys::Mesh::Vertex* srcVertex = mesh->m_vVertexs;
Batch::Vertex* dstVertex = &batch->m_vVertexs[startVertex];
for (int j = 0; j < mesh->m_vVertexNum; j++,srcVertex++,dstVertex++)
{
pos.x = srcVertex->x;
pos.y = srcVertex->y;
pos.z = srcVertex->z;
if(mat)
{
pos = (*mat) * pos;
}
pos += blockMovie->pos;
//todo 水平噪声偏置
dstVertex->x = pos.x;
dstVertex->z = pos.z;
//叠加地形高度 产生裂缝问题? 相邻的模型在相交边上顶点布局不同叠加的地形高度不同导致裂缝? 使模型在边上具有相同的点分布不方便
//边界上的点的高度使用直线插值计算
//或者模型所有的点都使用四个角点插值 只需要地形顶点正好和四个角点重合即可
dstVertex->y = pos.y + terrain.GetHeightf((dstVertex->x+offsetX)*(1/120.0f)+0.5f,(dstVertex->z+offsetZ)*(1/120.0f)+0.5f);
normal.x = srcVertex->nx;
normal.y = srcVertex->ny;
normal.z = srcVertex->nz;
if(mat)
{
normal = (*mat) * normal;
}
dstVertex->nx = normal.x;
dstVertex->ny = normal.y;
dstVertex->nz = normal.z;
dstVertex->u = mesh->m_tVertexs[j].u;
dstVertex->v = mesh->m_tVertexs[j].v;
dstVertex->w = mesh->m_tVertexs[j].w;
dstVertex->x *= FitScale_;
dstVertex->y *= FitScale_;
dstVertex->z *= FitScale_;
}
batch->m_indexNum += mesh->m_trigonNum*3;
batch->m_vVertexNum += mesh->m_vVertexNum;
}
for (int i=0;i<m_batchNum;i++)
{
m_batchs[i].CreateBuffer();
m_batchs[i].MapBuffer();
}
SafeDelete(m_movieLib);
}
void RacingRoad::Render()
{
for (int i=0;i<m_batchNum;i++)
{
m_batchs[i].Render();
}
}
void RacingRoad::SaveToCollide(RendSys::Mesh* mesh)
{
if (mesh==NULL)
return;
mesh->Free();
int vVertexNum = 0;
int tVertexNum = 0;
int trigonNum = 0;
for (int i=0;i<m_batchNum;i++)
{
vVertexNum += m_batchs[i].m_vVertexNum;
tVertexNum += m_batchs[i].m_vVertexNum;
trigonNum += m_batchs[i].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;
int indexOffset = 0;
for (int i=0;i<m_batchNum;i++)
{
vVertexNum = m_batchs[i].m_vVertexNum;
Batch::Vertex* vb = m_batchs[i].m_vVertexs;
for (int j=0;j<vVertexNum;++j)
{
v->x = vb->x ;
v->y = vb->y ;
v->z = vb->z ;
v->nx = vb->nx;
v->ny = vb->ny;
v->nz = vb->nz;
t->u = vb->u;
t->v = vb->v;
t->w = vb->w;
v++;
vb++;
t++;
}
trigonNum = m_batchs[i].m_indexNum/3;
IndexInt* trib = m_batchs[i].m_indexs;
for (int j=0;j<trigonNum;++j)
{
tri->vIndex[0] = trib[0] +indexOffset;
tri->vIndex[1] = trib[1] +indexOffset;
tri->vIndex[2] = trib[2] +indexOffset;
tri+=1;
trib+=3;
}
indexOffset += vVertexNum;
}
//mesh->CreateBuff();//test
mesh->BuildTree();
}
wan