实现RPG中嵌入赛车游戏任务源代码

今天暂时不用挨饿,继续吃昨天剩下的水饺。吃哕了,写点东西缓一缓。

这是一个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
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值