Jump to content
• Advertisement

# Physic of ball for review

This topic is 2110 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

## Recommended Posts

Could You review below code from physics point of view. It serves to set speed, rotation for the ball. I implemented it according to my best knowledge from lyceum and a bit from books (however mostly from lyceum, because some parts of book was not understood by me). Maybe this code would be also useful for someone else.

Here is some explanation of function which serves to set force:

void Physic::setForce(D3DXVECTOR3* force, D3DXVECTOR3* collisionPoint) - this should be used when there is some constant force which influence all the time ball

void Physic::setV(D3DXVECTOR3* V, D3DXVECTOR3* collisionPoint) - this should be used when for example somebody kick the ball (so force is not set all the time to the ball), then You set as argument  V = mass of leg * velocity of leg / mass of the ball => this come from "momentum rule" known from school

Header

#ifndef _PHYSIC_
#define _PHYSIC_

#include "common.h"
#include "const.h"

#define RESISTANCE_X 0.1f
#define RESISTANCE_Z 0.1f
#define RESISTANCE_MAGNUM 0.1f

#define GROUND_ABSORBANCE 0.2f
#define GROUND_FRICTION 0.1f
#define WALL_ABSORBANCE 0.2f

//REST_THRESHOLD is the energy below which the ball is flagged as laying on ground.
//It is defined as Gravity * Height_above_ground + 0.5 * Velocity * Velocity
#define REST_THRESHOLD 0.005f

#define GROUND_LEVEL 0
#define MIN_BOUND_X -10.0f
#define MAX_BOUND_X 10.0f
#define MIN_BOUND_Z -10.0f
#define MAX_BOUND_Z 10.0f

class Physic
{
public:
typedef enum
{
SPHERE = 0,
CUBE = 1,
CUBOID = 2,
CYLINDER = 3,
OTHER = 4
} Type;

Physic(Type type, D3DXVECTOR3 pos, float mass, void* param);
~Physic();
void setForce(D3DXVECTOR3* force, D3DXVECTOR3* collisionPoint);
void setV(D3DXVECTOR3* V, D3DXVECTOR3* collisionPoint);
void resetForce();
void update(float deltaTime);

Type mType;
float mR; //distance from centre to point of net force (const for sphere)

D3DXVECTOR3 mPos; //Position
D3DXVECTOR3 mV; //Linear velocity
float mM; //Mass
D3DXVECTOR3 mNetF; //Sum of forces applied to object
D3DXVECTOR3 mA;

D3DXQUATERNION mQuatOrientation; //Orientation (rotation of the mesh)
D3DXMATRIX mMatOrientation; //Orientation (rotation of the mesh in matrix form)

D3DXVECTOR3 mE; //Angular acceleration

vector<D3DXVECTOR3> mForces;
vector<D3DXVECTOR3> mPointsF;

vector<D3DXVECTOR3> mVs;
vector<D3DXVECTOR3> mPointsV;

D3DXVECTOR3 mW; //Angular velocity
D3DXMATRIX mIinv; //Inverse moment of inertia tensor matrix

bool mGround; //Is ball placed on the ground

private:
void takeIntoAccountBounds();
float getDistFromOrigin();

};

#endif

.cpp file

#include "physic.h"

Physic::Physic(Physic::Type type, D3DXVECTOR3 pos, float mass, void* param):mM(mass),mType(type),mGround(false)
{
//init variables
mA = D3DXVECTOR3(0,0,0);
mV = D3DXVECTOR3(0,0,0);
mR = 0;
mNetF = D3DXVECTOR3(0,0,0);
mE = D3DXVECTOR3(0,0,0);
mW = D3DXVECTOR3(0,0,0);

//Set inertia tensor
D3DXMatrixIdentity(&mIinv);
if(mType == Physic::SPHERE)
{
mR = *(static_cast<float *>(param));
mIinv._11 = 1.00f / (mM * 0.40f * pow(mR, 2));
mIinv._22 = mIinv._11;
mIinv._33 = mIinv._11;
}

//Set mPos, orientation
mPos = pos;
d3d::setQuaternion(&mQuatOrientation, d3d::vecUP, 0); //second parameter in fact might be anything, angle = 0
D3DXMatrixRotationQuaternion(&mMatOrientation, &mQuatOrientation);
D3DXMatrixTranspose(&mMatOrientation, &mMatOrientation); //convert matrix to left-hand coordinate system
mMatOrientation._41 += mPos.x;
mMatOrientation._42 += mPos.y;
mMatOrientation._43 += mPos.z;
}
Physic::~Physic(){}
void Physic::setForce(D3DXVECTOR3* force, D3DXVECTOR3* collisionPoint)
{
mNetF += *force;
if(mType == SPHERE)
{
mForces.push_back(*force);
mPointsF.push_back(*collisionPoint);
}
}
void Physic::setV(D3DXVECTOR3* V, D3DXVECTOR3* collisionPoint)
{
mV += *V;
if(mType == SPHERE)
{
mVs.push_back(*V);
mPointsV.push_back(*collisionPoint);
}
}
void Physic::update(float t)
{
//calculate rotational motion
if(mType == SPHERE)
{
//for each collision point calculate Wo
if(!mVs.empty())
{
D3DXVECTOR3 L = D3DXVECTOR3(0,0,0);
u32 size = static_cast<u32>(mVs.size());
for(u32 i=0; i<size; ++i)
L += calc::CrossProduct(&(mPointsV.at(i) - mPos), &mVs.at(i)) * mM;
mVs.clear();
mPointsV.clear();

D3DXVECTOR3 Wo;
D3DXVec3TransformCoord(&Wo, &L, &mIinv);  //angular momentum
mW += Wo;
}

//for each collision point calculate torque
if(!mForces.empty())
{
D3DXVECTOR3 torque = D3DXVECTOR3(0,0,0);
u32 size = static_cast<u32>(mForces.size());
for(u32 i=0; i<size; ++i)
torque += calc::CrossProduct(&(mPointsF.at(i) - mPos), &mForces.at(i));
mForces.clear();
mPointsF.clear();

D3DXVec3TransformCoord(&mE, &torque, &mIinv);
}

mW += mE * t;  // E = M/I = W - Wo = M/I * t

//Update velocity about resitance
mW -= mW * RESISTANCE_MAGNUM * t;

D3DXVECTOR3 fi = mW * t;

// Apply angle to orientation
mQuatOrientation.w -= 0.5f * (mQuatOrientation.x * fi.x + mQuatOrientation.y * fi.y + mQuatOrientation.z * fi.z);
mQuatOrientation.x += 0.5f * (mQuatOrientation.w * fi.x - mQuatOrientation.z * fi.y + mQuatOrientation.y * fi.z);
mQuatOrientation.y += 0.5f * (mQuatOrientation.z * fi.x + mQuatOrientation.w * fi.y - mQuatOrientation.x * fi.z);
mQuatOrientation.z += 0.5f * (mQuatOrientation.x * fi.y - mQuatOrientation.y * fi.x + mQuatOrientation.w * fi.z);
D3DXQuaternionNormalize(&mQuatOrientation, &mQuatOrientation); //normalize the quaternion (creates a unit quaternion)
D3DXMatrixRotationQuaternion(&mMatOrientation, &mQuatOrientation);
D3DXMatrixTranspose(&mMatOrientation, &mMatOrientation); //convert matrix to left-hand coordinate system
}

//calculate progressive motion
mA += mNetF / mM;
mNetF = D3DXVECTOR3(0,0,0); //clear force

D3DXVECTOR3 Vo = mV;
mV += mA * t;

//Update velocity about resitance
mV.x -= mV.x * RESISTANCE_X * t;
mV.z -= mV.z * RESISTANCE_Z * t;
if(!mGround) //Apply gravity if the ball is not resting on the ground
mV.y += ph::g.y*t;

takeIntoAccountBounds();

mPos += ((Vo + mV) / 2.00f) * t;

//update mat orientation
mMatOrientation._41 = mPos.x;
mMatOrientation._42 = mPos.y;
mMatOrientation._43 = mPos.z;
}
void Physic::takeIntoAccountBounds()
{
if(mType != SPHERE)
mR = getDistFromOrigin();

//Check bounce on ground
if(!mGround)
{
if(mPos.y < GROUND_LEVEL + mR)
{
//Align the ball with the ground.
mPos.y = GROUND_LEVEL + mR;

//TO DO: Play sound

//Invert the Y velocity
mV.y = -mV.y * (1 - GROUND_ABSORBANCE);

//X and Z velocity are reduced because of friction (tarcie)
mV.x *= (1 - GROUND_FRICTION);
mV.z *= (1 - GROUND_FRICTION);
}
}
else //Ball is resting or rolling on ground
{
// X and Z velocity are reduced because of friction
mV.x *= (1 - GROUND_FRICTION);
mV.z *= (1 - GROUND_FRICTION);
}

//If the Y direction motion is below a certain threshold, flag the instance as laying on the ground
if(ph::g.y * (mPos.y + GROUND_LEVEL - mR) + 0.5f * mV.y * mV.y < REST_THRESHOLD)
{
//Align the ball with the ground
mPos.y = GROUND_LEVEL + mR;
mV.y = 0;
mGround = true;
}

// Check bounce on walls
if(mPos.z - mR < d3d::MIN_BOUND_Z)
{
//Align the ball with the wall
mPos.z = d3d::MIN_BOUND_Z + mR;

//Play sound

//Invert the Z velocity
mV.z = -mV.z * (1 - WALL_ABSORBANCE);
}
if(mPos.z + mR > d3d::MAX_BOUND_Z)
{
//Align the ball with the wall
mPos.z = d3d::MAX_BOUND_Z - mR;

//Play sound

//Invert the Z velocity
mV.z = -mV.z * (1 - WALL_ABSORBANCE);
}
if(mPos.x - mR < d3d::MIN_BOUND_X)
{
//Align the ball with the wall
mPos.x = d3d::MIN_BOUND_X + mR;

//Play sound

//Invert the Z velocity
mV.x = -mV.x * (1 - WALL_ABSORBANCE);
}
if(mPos.x + mR < d3d::MAX_BOUND_X)
{
//Align the ball with the wall
mPos.x = d3d::MAX_BOUND_X - mR;

//Play sound

//Invert the Z velocity
mV.x = -mV.x * (1 - WALL_ABSORBANCE);
}
}
float Physic::getDistFromOrigin()
{
switch(mType)
{
case SPHERE: return mR;
case CUBOID: return mR;
case CYLINDER: return mR;
}
return 0;
}
void Physic::resetForce()
{
mE = D3DXVECTOR3(0,0,0);
mA = D3DXVECTOR3(0,0,0);
}

Edited by anders211

#### Share this post

##### Share on other sites
Advertisement

First of all your code is not cache friendly at all. You branch your code to much, for example why check if the force vector is empty?
Another thing, you have not made a common solution for physic update. The same update function should work for all types of shapes not only spheres.

The update function should only be a physic integration. As you may recall: a = F / m, v += a * t, s += v * t + 0.5 * a * t * t for linear physic, and angularAcc = torq * I-1, rotation += angularAcc * t, orientation += rotation * t for angular physic.

I see you are doing this, however you should separate your integration code from the contact resolving, so that you can have common solution for all bodies. So what you need to do is to clean up your code, and separate it, and have in mind that your solution should not be specific for each shape, but common.

Also to paste code from visual studio, turn on "space for tabs" in the editor settings, and then convert your code file before you copy it.

#### Share this post

##### Share on other sites

• Advertisement
• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• Advertisement

• ### Popular Now

• 16
• 11
• 23
• 42
• 75
• Advertisement
×

## Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!