Initial commit
This commit is contained in:
417
engines/hpl1/engine/physics/Body2D.cpp
Normal file
417
engines/hpl1/engine/physics/Body2D.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2010 - Frictional Games
|
||||
*
|
||||
* This file is part of HPL1 Engine.
|
||||
*/
|
||||
|
||||
#include "hpl1/engine/physics/Body2D.h"
|
||||
|
||||
#include "hpl1/engine/graphics/Mesh2d.h"
|
||||
#include "hpl1/engine/math/Math.h"
|
||||
#include "hpl1/engine/physics/CollideData2D.h"
|
||||
#include "hpl1/engine/physics/Collider2D.h"
|
||||
#include "hpl1/engine/scene/Entity2D.h"
|
||||
#include "hpl1/engine/scene/Node2D.h"
|
||||
|
||||
namespace hpl {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CONSTRUCTORS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cBody2D::cBody2D(const tString &asName, cMesh2D *apMesh, cVector2f avSize, cCollider2D *apCollider, int alID)
|
||||
: iEntity2D(asName) {
|
||||
mvSize = avSize;
|
||||
mpMesh = apMesh;
|
||||
mpCollider = apCollider;
|
||||
|
||||
mpCollMesh = mpMesh->CreateCollisonMesh(0, mvSize);
|
||||
mpBaseCollMesh = mpMesh->CreateCollisonMesh(0, mvSize);
|
||||
|
||||
/*for(int i=0;i<(int)mpCollMesh->mvPos.size();i++)
|
||||
{
|
||||
Log("Pos%d: %s\n", i,mpCollMesh->mvPos[i].ToString().c_str());
|
||||
}
|
||||
|
||||
for(int i=0;i<(int)mpCollMesh->mvNormal.size();i++)
|
||||
{
|
||||
Log("Norm%d: %s\n", i,mpCollMesh->mvNormal[i].ToString().c_str());
|
||||
}*/
|
||||
|
||||
// Log("------------\n");
|
||||
|
||||
// Set some default values to the properties
|
||||
mfMaxVel = 0;
|
||||
mfAcc = 1;
|
||||
|
||||
mfAirFriction = 0.005f;
|
||||
mfGroundFriction = 0.3f;
|
||||
mfGravity = 0.4f;
|
||||
mfMaxGravityVel = 3;
|
||||
|
||||
mbCollidable = false;
|
||||
mbCollides = true;
|
||||
mbMoved = false;
|
||||
mbOnGround = false;
|
||||
mbGroundFrictionX = false;
|
||||
mbGroundFrictionY = false;
|
||||
|
||||
mvCollideCount = 0;
|
||||
|
||||
mvMovement = 0;
|
||||
|
||||
mbAttachToGround = false;
|
||||
mbAttachBodies = true;
|
||||
|
||||
mpParentBody = NULL;
|
||||
|
||||
mpNode = NULL;
|
||||
mlID = alID;
|
||||
|
||||
mlCollideFlag = eFlagBit_0;
|
||||
mlCollideType = eFlagBit_1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cBody2D::~cBody2D() {
|
||||
hplDelete(mpCollMesh);
|
||||
hplDelete(mpBaseCollMesh);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC METHODS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::UpdateLogic(float afTimeStep) {
|
||||
cVector3f vStartPos = GetPosition();
|
||||
|
||||
if (mbAttachToGround) {
|
||||
if (mpParentBody != NULL) {
|
||||
// What can be done is to add this to the force, and then att the end redcue the same amout
|
||||
// This will allow the body to add the velocity to it's jumps for example.
|
||||
cVector3f vMovement = mpParentBody->GetMovement(); // mpParentBody->GetPosition() - mpParentBody->GetLastPosition();
|
||||
SetPosition(GetPosition() + vMovement);
|
||||
}
|
||||
}
|
||||
|
||||
cCollideData2D CollideData;
|
||||
// Update Gravity
|
||||
|
||||
mbGroundFrictionX = false;
|
||||
|
||||
if (mbCollides && mfGravity > 0) {
|
||||
cVector3f vTempPos = GetPosition();
|
||||
|
||||
float fXSize = mvSize.x;
|
||||
cRect2f Rect(vTempPos.x - fXSize / 2, vTempPos.y + mfGravity,
|
||||
fXSize, mvSize.y / 2);
|
||||
|
||||
if (mpCollider->CollideRect(Rect, GetCollideFlag(), NULL)) {
|
||||
// We are still on ground.
|
||||
mbOnGround = true;
|
||||
mbGroundFrictionX = true;
|
||||
// Log("Standing on ground\n");
|
||||
} else {
|
||||
// If the player used to be on ground, add some extra force
|
||||
if (mbOnGround) {
|
||||
mvForce.y += mfGravity * 2;
|
||||
}
|
||||
|
||||
mbOnGround = false;
|
||||
mvForce.y += mfGravity;
|
||||
if (mvForce.y > mfMaxGravityVel)
|
||||
mvForce.y = mfMaxGravityVel;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the Y Axis and check for collision
|
||||
AddPosXY(cVector2f(0, mvForce.y));
|
||||
|
||||
if (mbCollides) {
|
||||
UpdateCollisionMesh();
|
||||
UpdateBoundingBox();
|
||||
if (mpCollider->CollideBody(this, &CollideData)) {
|
||||
if (mvLastCollidePos.y == GetPosition().y)
|
||||
mvCollideCount.y++;
|
||||
|
||||
if (mvForce.y > 0) {
|
||||
if (mbAttachToGround) {
|
||||
// If collided with a body, make it the new reference frame.
|
||||
if (CollideData.mlstBodies.size() > 0) {
|
||||
tBody2DListIt it = CollideData.mlstBodies.begin();
|
||||
if (*it != mpParentBody) {
|
||||
if (mpParentBody != NULL)
|
||||
DetachBody(mpParentBody);
|
||||
|
||||
SetParentBody(*it);
|
||||
(*it)->AttachBody(this);
|
||||
// Log("Attaching!\n");
|
||||
}
|
||||
} else {
|
||||
if (mpParentBody != NULL) {
|
||||
DetachBody(mpParentBody);
|
||||
mpParentBody = NULL;
|
||||
// Log("Detaching!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mbOnGround = true;
|
||||
mvForce.y = 0;
|
||||
}
|
||||
|
||||
if (mvCollideCount.y > 0) {
|
||||
|
||||
mvForce.y = 0;
|
||||
}
|
||||
|
||||
mvLastCollidePos.y = GetPosition().y;
|
||||
mbGroundFrictionX = true;
|
||||
} else {
|
||||
mvCollideCount.y = 0;
|
||||
if (!mbOnGround)
|
||||
mvLastCollidePos.y = -10000;
|
||||
// mbGroundFrictionX = false;
|
||||
}
|
||||
|
||||
if (mbOnGround == false && mbAttachToGround) {
|
||||
if (mpParentBody != NULL) {
|
||||
DetachBody(mpParentBody);
|
||||
mpParentBody = NULL;
|
||||
// Log("Detaching!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the X Axis and check for collision
|
||||
AddPosXY(cVector2f(mvForce.x, 0));
|
||||
|
||||
if (mbCollides) {
|
||||
UpdateCollisionMesh();
|
||||
UpdateBoundingBox();
|
||||
if (mpCollider->CollideBody(this, NULL)) {
|
||||
if (mvLastCollidePos.x == GetPosition().x)
|
||||
mvCollideCount.x++;
|
||||
|
||||
if (mvCollideCount.x > 0) {
|
||||
mvForce.x = 0;
|
||||
}
|
||||
|
||||
mvLastCollidePos.x = GetPosition().x;
|
||||
} else {
|
||||
mvCollideCount.x = 0;
|
||||
mvLastCollidePos.x = -10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the force
|
||||
float fAngle = 0, fStrength = 0;
|
||||
cMath::GetAngleFromVector(mvForce, &fAngle, &fStrength);
|
||||
|
||||
fStrength -= mfAirFriction; // This is the air friction.
|
||||
// It should be combined with the friction of the collided material.
|
||||
|
||||
if (fStrength < 0)
|
||||
fStrength = 0;
|
||||
|
||||
SetForce(fAngle, fStrength);
|
||||
|
||||
// Don't do any friction if the body has moved.
|
||||
// if(!mbMoved) Or?
|
||||
{
|
||||
if (mbGroundFrictionX && mvForce.x != 0) {
|
||||
// Log("GroundFriction!\n");
|
||||
// Log("Force: %s\n",mvForce.ToString().c_str());
|
||||
if (mvForce.x > 0) {
|
||||
mvForce.x -= mfGroundFriction;
|
||||
if (mvForce.x < 0)
|
||||
mvForce.x = 0;
|
||||
} else {
|
||||
mvForce.x += mfGroundFriction;
|
||||
if (mvForce.x > 0)
|
||||
mvForce.x = 0;
|
||||
}
|
||||
// Log("Force: %s\n",mvForce.ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
mvMovement = GetPosition() - vStartPos;
|
||||
|
||||
/*tBody2DListIt BodyIt = mlstAttachedBodies.begin();
|
||||
for(;BodyIt != mlstAttachedBodies.end();BodyIt++)
|
||||
{
|
||||
cBody2D* pBody = *BodyIt;
|
||||
|
||||
pBody->SetPosition(pBody->GetPosition() + vMovement);
|
||||
}*/
|
||||
|
||||
if (mpNode) {
|
||||
mpNode->SetPosition(GetWorldPosition());
|
||||
}
|
||||
|
||||
mbMoved = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::Move(float afValue) {
|
||||
float fAngle = 0, fStrength = 0;
|
||||
|
||||
cVector2f vForwardVec = cMath::GetVectorFromAngle2D(mvRotation.z, 1);
|
||||
cVector2f vMovement = cMath::ProjectVector2D(mvForce, vForwardVec);
|
||||
cMath::GetAngleFromVector(vMovement, &fAngle, &fStrength);
|
||||
|
||||
if (fStrength < mfMaxVel) {
|
||||
float fTempAcc = mfAcc;
|
||||
|
||||
if (fStrength + fTempAcc > mfMaxVel) {
|
||||
fTempAcc -= (fStrength + fTempAcc) - mfMaxVel;
|
||||
}
|
||||
|
||||
mvForce += vForwardVec * fTempAcc;
|
||||
|
||||
mbMoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::AddForce(float afAngle, float afStrength) {
|
||||
cVector2f vForce = cMath::GetVectorFromAngle2D(afAngle, afStrength);
|
||||
|
||||
AddForce(vForce);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::AddForce(const cVector2f &avForce) {
|
||||
mvForce += avForce;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::SetForce(float afAngle, float afStrength) {
|
||||
cVector2f vForce = cMath::GetVectorFromAngle2D(afAngle, afStrength);
|
||||
SetForce(vForce);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::SetForce(const cVector2f &avForce) {
|
||||
mvForce = avForce;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
const cRect2f &cBody2D::GetBoundingBox() {
|
||||
return mBoundingBox;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
bool cBody2D::UpdateBoundingBox() {
|
||||
cVector2f vSize;
|
||||
|
||||
/*if(mvRotation.z != 0)
|
||||
{
|
||||
//Only Temp...
|
||||
float fMaxSize = sqrt(mvSize.x*mvSize.x + mvSize.y*mvSize.y);
|
||||
|
||||
vSize.x = fMaxSize;
|
||||
vSize.y = fMaxSize;
|
||||
}
|
||||
else*/
|
||||
{
|
||||
vSize = mvSize;
|
||||
}
|
||||
|
||||
mBoundingBox = cRect2f(cVector2f(GetWorldPosition().x - vSize.x / 2,
|
||||
GetWorldPosition().y - vSize.y / 2),
|
||||
vSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::UpdateCollisionMesh() {
|
||||
cVector2f vPos(GetPosition().x, GetPosition().y);
|
||||
for (int i = 0; i < (int)mpCollMesh->mvPos.size(); i++) {
|
||||
mpCollMesh->mvPos[i] = vPos + mpBaseCollMesh->mvPos[i];
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
cCollisionMesh2D *cBody2D::GetCollisionMesh() {
|
||||
return mpCollMesh;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::AttachBody(cBody2D *apBody) {
|
||||
mlstAttachedBodies.push_back(apBody);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::DetachBody(cBody2D *apBody) {
|
||||
tBody2DListIt it = mlstAttachedBodies.begin();
|
||||
for (; it != mlstAttachedBodies.end(); it++) {
|
||||
if (*it == apBody) {
|
||||
mlstAttachedBodies.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::SetParentBody(cBody2D *apBody) {
|
||||
mpParentBody = apBody;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE METHODS
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void cBody2D::AddPosXY(cVector2f avPosAdd) {
|
||||
cVector3f vPos = GetPosition();
|
||||
vPos += avPosAdd;
|
||||
SetPosition(vPos);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
} // namespace hpl
|
||||
Reference in New Issue
Block a user