📄 carobject.cpp
字号:
#include "StdAfx.h"
#include "CarObject.h"
#include "../model/Model.h"
#include "../model/TriMesh.h"
#include "OGLutil.h"
#include "../res/ModelLoadManager.h"
#include "QuadTree.h"
#include "SceneManager.h"
using namespace std;
CCarObject::CCarObject()
{
m_pCarBodyModel = NULL;
m_pWheelModel = NULL;
m_fMoveSpeed = 0.0f;
m_fTurnSpeed = 0.0f;
m_fMaxMoveSpeed = 0.0f;
m_fTurnRadian = 0.0f;
m_fWheelRollRadian = 0.0f;
m_fWheelTurnRadian = 0.0f;
m_eCurState = ECarState_Begin;
}
CCarObject::~CCarObject()
{
}
void CCarObject::BuildObjectBox()
{
// 现在只计算车身。
if (m_pCarBodyModel != NULL)
{
m_boxObjectBox.Empty();
int iTriMeshCount = m_pCarBodyModel->GetPartCount();
for (int i=0; i<iTriMeshCount; ++i)
{
TriMesh* mesh = m_pCarBodyModel->GetPartMesh(i);
m_boxObjectBox.Add(mesh->GetBoundingBox());
}
}
}
void CCarObject::LoadWheelPosition(const char *filename)
{
ifstream inf(filename);
for (int i = 0; i < WHEEL_COUNT; ++i)
{
inf >> m_posWheel[i].x >> m_posWheel[i].y >> m_posWheel[i].z;
}
}
void CCarObject::LoadModels(const char *filename)
{
char szPathName[64];
char szFileName[128];
bool bHasPath = false;
char* ptr = strrchr(filename, '/');
if (ptr == NULL)
{
ptr = strrchr(filename, '\\');
}
if (ptr == NULL)
{
szPathName[0] = '\0';
}
else
{
int len = static_cast<int>(ptr - filename);
strncpy(szPathName, filename, len);
szPathName[len] = '/';
szPathName[len+1] = '\0';
}
m_pCarBodyModel = g_ModelLoadManager.LoadModel(filename);
strcpy(szFileName, szPathName);
strcat(szFileName, "Wheel.3ds");
m_pWheelModel = g_ModelLoadManager.LoadModel(szFileName);
strcpy(szFileName, szPathName);
strcat(szFileName, "car.cfg");
LoadWheelPosition(szFileName);
BuildObjectBox();
}
void CCarObject::RenderObject()
{
assert(m_pCarBodyModel != NULL && m_pWheelModel != NULL);
g_Renderer.PushModelViewMatrix();
g_Renderer.MulMatrix(m_mxTransformObjToWorld.m);
m_pCarBodyModel->Render();
CMatrix44F mat;
// 前面两个车轮还要有转弯的角度
for (int i=0; i<2; ++i)
{
g_Renderer.PushModelViewMatrix();
mat.SetupTranslation(m_posWheel[i]);
mat.Rotate(3, m_fWheelTurnRadian);
mat.Rotate(1, m_fWheelRollRadian);
g_Renderer.MulMatrix(mat.m);
m_pWheelModel->Render();
g_Renderer.PopModelViewMatrix();
}
for (int i=2; i<WHEEL_COUNT; ++i)
{
g_Renderer.PushModelViewMatrix();
mat.SetupTranslation(m_posWheel[i]);
mat.Rotate(1, m_fWheelRollRadian);
g_Renderer.MulMatrix(mat.m);
m_pWheelModel->Render();
g_Renderer.PopModelViewMatrix();
}
// 调试画出物体的局部盒子
//g_Renderer.RenderBox(m_boxObjectBox.min, m_boxObjectBox.max);
g_Renderer.PopModelViewMatrix();
// 调试画出物体的世界盒子
//g_Renderer.RenderBox(m_boxWorldBox.min, m_boxWorldBox.max);
}
void CCarObject::Update()
{
Move();
Animate();
m_fMoveSpeed -= 0.0014f;
// 如果在没有跑道的地方,阻力会更大一些
CQuadTree *pTree = m_pSceneManager->GetQuadTree();
if (pTree->FindTri(GetPosition()) == NULL)
{
m_fMoveSpeed -= (0.2f * m_fMoveSpeed + 0.0032f) ;
}
if (m_fMoveSpeed < 0.0f)
{
m_fMoveSpeed = 0.0f;
}
}
void CCarObject::Animate()
{
m_fWheelRollRadian -= m_fMoveSpeed;
}
void CCarObject::Move()
{
if (m_fWheelTurnRadian > 0.0f)
{
m_fTurnRadian = m_fTurnSpeed * 0.8f;
m_fWheelTurnRadian -= m_fTurnSpeed * 0.8f;
if (m_fWheelTurnRadian < 0.f)
{
m_fWheelTurnRadian = 0.f;
}
}
else if (m_fWheelTurnRadian < 0.0f)
{
m_fTurnRadian = -m_fTurnSpeed * 0.8f;
m_fWheelTurnRadian += m_fTurnSpeed * 0.8f;
if (m_fWheelTurnRadian > 0.f)
{
m_fWheelTurnRadian = 0.f;
}
}
m_mxTransformObjToWorld.Rotate(3, m_fTurnRadian);
m_mxTransformObjToWorld.Translate(Vector3(0.0f, m_fMoveSpeed, 0.0f));
SetTransform(m_mxTransformObjToWorld);
m_fTurnRadian = 0.0f;
}
void CCarObject::TurnLeft()
{
m_fWheelTurnRadian += m_fTurnSpeed;
//m_mxTransformObjToWorld.Rotate(3, m_fTurnSpeed);
//SetTransform(m_mxTransformObjToWorld);
}
void CCarObject::TurnRight()
{
m_fWheelTurnRadian -= m_fTurnSpeed;
//m_mxTransformObjToWorld.Rotate(3, -m_fTurnSpeed);
//SetTransform(m_mxTransformObjToWorld);
}
//-------------------------------------------------------------------------------
// 车子与车子的碰撞检测,true为发生碰撞,否则没有
//-------------------------------------------------------------------------------
bool CollisionCheck(const CCarObject &car1, const CCarObject &car2)
{
const AABB3& box1 = car1.GetWorldBox();
const AABB3& box2 = car2.GetWorldBox();
if (IntersectAABBs(box1, box2))
{
const AABB3& oBox = car2.GetObjectBox();
Vector3 vSize = (oBox.max - oBox.min) * 0.5f;
CMatrix44F mat1 = car1.GetTransformWorldToObj();
mat1 *= car2.GetTransformObjToWorld();
if (car1.GetObjectBox().IntersectOBB(vSize, mat1))
{
return true;
}
}
return false;
}
//-------------------------------------------------------------------------------
// 车子与车子的碰撞响应
//-------------------------------------------------------------------------------
bool OnCollision(CCarObject &car1, CCarObject &car2)
{
// 点乘
#define DOT_PRODUCT(ux,uy,vx,vy) ((ux)*(vx) + (uy)*(vy))
Vector3 pos1, pos2; // 车子的位置
Vector3 vel1, vel2; // Z轴即为车子面向的方向
pos1 = car1.GetPosition();
pos2 = car2.GetPosition();
car1.GetTransformObjToWorld().GetRow(1, &vel1);
car2.GetTransformObjToWorld().GetRow(1, &vel2);
vel1 *= car1.GetMoveSpeed();
vel2 *= car2.GetMoveSpeed();
// 就算a->b的法线向量
float nabx = pos2.x - pos1.x;
float naby = pos2.y - pos1.y;
float length = sqrt(nabx*nabx + naby*naby);
// 计算反应的坐标系的坐标轴,这个是法线轴
nabx /= length;
naby /= length;
// 计算垂直法线轴的切线轴,简单地逆时针旋转90度
float tabx = -naby;
float taby = nabx;
// a球在切线方向上初始速度的投影长度
float vait = DOT_PRODUCT(vel1.x, vel1.y, tabx, taby);
// a球在法线方向上初始速度的投影长度
float vain = DOT_PRODUCT(vel1.x, vel1.y, nabx, naby);
// b球在切线方向上初始速度的投影长度
float vbit = DOT_PRODUCT(vel2.x, vel2.y, tabx, taby);
// b球在法线方向上初始速度的投影长度
float vbin = DOT_PRODUCT(vel2.x, vel2.y, nabx, naby);
float ma = 1.2f;
float mb = 1.2f;
float vafn = (mb*vbin*(0.6f+1.f) + vain*(ma - 0.6f*mb)) / (ma + mb);
float vbfn = (ma*vain*(0.6f+1.f) - vbin*(ma - 0.6f*mb)) / (ma + mb);
// 幸运的,切线反向的速度和原来一样
float vaft = vait;
float vbft = vbit;
// 就这样,宝贝!
// 最终速度的向量如下:
// object a (vafn, vaft)
// object b (vbfn, vbft)
// 最后问题是我们在n-t坐标系中!我们需要转换回原来的x-y坐标系中,基本上我们
// 需要计算相对于n-t坐标轴的x分量的和,已经相对于n-t坐标轴的y分量的和,因为
// n-t轴相对于原来的x-y坐标系可能同时有x和y分量。
float xfa = vafn*nabx + vaft*tabx;
float yfa = vafn*naby + vaft*taby;
float xfb = vbfn*nabx + vbft*tabx;
float yfb = vbfn*naby + vbft*taby;
vel1.x = xfa, vel1.y = yfa;
vel2.x = xfb, vel2.y = yfb;
float speed1 = VectorMag(vel1);
float speed2 = VectorMag(vel2);
vel1.Normalize();
vel2.Normalize();
CMatrix44F mat1 = car1.GetTransformObjToWorld();
CMatrix44F mat2 = car2.GetTransformObjToWorld();
mat1.SetRow(1, vel1);
mat2.SetRow(1, vel2);
Vector3 vZ1(0.f, 0.f, 1.f);
Vector3 vZ2(0.f, 0.f, 1.f);
Vector3 vX1 = CrossProduct(vel1, vZ1);
Vector3 vX2 = CrossProduct(vel2, vZ2);
mat1.SetRow(0, vX1);
mat2.SetRow(0, vX2);
car1.SetTransform(mat1);
car2.SetTransform(mat2);
car1.SetMoveSpeed(speed1);
car2.SetMoveSpeed(speed2);
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -