/*************************************************************************** movingobject.cpp - Moving object class ------------------- begin : Wed Dec 4 2002 copyright : (C) 2002 by CJP email : cornware-cjp@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "movingobject.h" #include "movobjinput.h" #include "physics.h" CMovingObject::CMovingObject(CDataManager *manager) : CDataObject(manager, CDataObject::eMovingObject) { //default mass: m_InvMass = 1.0; m_InputData = new CMovObjInput; m_LastNetworkUpdateTime = -1000.0; //first update will always come through this m_Ground.nor = CVector(0,0,0); } CMovingObject::~CMovingObject() { unload(); delete m_InputData; //I guess this will happen for all CMovingObject-derived classes } bool CMovingObject::load(const CString &filename, const CParamList &list) { CDataObject::load(filename, list); m_MovObjID = list.getValue("ID", "0").toInt(); m_InputData->m_MovObjID = m_MovObjID; return true; } void CMovingObject::unload() { //for(unsigned int i=0; i < m_Bodies.size(); i++) // m_Bodies[i].destroyODE(); m_Bodies.clear(); m_Sounds.clear(); m_Textures.clear(); CDataObject::unload(); } void CMovingObject::addForce(CVector F) { m_Ftot += F; } void CMovingObject::addTorque(CVector M) { m_Mtot += M; } void CMovingObject::addForceAt(CVector F, CVector pos) { m_Ftot += F; m_Mtot += F.crossProduct(pos); /* CVector Madd = F.crossProduct(pos); printf(" F = %s\n", CString(F).c_str()); printf(" p = %s\n", CString(pos).c_str()); printf(" M = %s\n", CString(Madd).c_str()); */ } void CMovingObject::update(CPhysics *simulator, float dt) { //Integration step of the simulation: //printf("Ftot = (%s) kN\n", CString(m_Ftot/1000.0).c_str()); //linear things: CVector accel = m_Ftot * m_InvMass; m_Position += (m_Velocity + 0.5*dt*accel)*dt; m_Velocity += dt*accel; //angular things: //inverse inertia tensor, corrected for body orientation CMatrix invInertia = m_OrientationMatrix.transpose() * m_InvInertia * m_OrientationMatrix; CVector angaccel = invInertia * m_Mtot; CMatrix dM; dM.setRotation((m_AngularVelocity + 0.5*dt*angaccel)*dt); m_OrientationMatrix *= dM; m_AngularVelocity += dt*angaccel; //Place the bodies: placeBodies(); //Reset the forces: m_Ftot = CVector (0,0,0); m_Mtot = CVector (0,0,0); } void CMovingObject::determineGroundPlane(CPhysics *simulator) { //TODO: some good default for non-car moving objects } void CMovingObject::correctCollisions() { for(unsigned int c=0; c < m_SimCollisions.size(); c++) { CCollisionData col = m_SimCollisions[c]; //printf("depth = %.3f\n", col.depth); CVector dr = col.nor * col.depth; //correct the position m_Position += dr; //set the collision velocity to zero m_Velocity -= col.vmean; float radcomp = m_Velocity.dotProduct(col.nor); if(radcomp < 0.0) m_Velocity -= radcomp * col.nor; m_Velocity += col.vmean; } } CBinBuffer &CMovingObject::getData(CBinBuffer &b) const { b += (Uint8)m_MovObjID; b.addFloat32(m_LastUpdateTime, 0.005); //more accurate than 1/100 sec CVector p = m_Position, o = m_OrientationMatrix.getRotation(), v = m_Velocity, w = m_AngularVelocity; b.addVector32(p, 0.001); b.addVector16(o, 0.0002); b.addVector16(v, 0.01); b.addVector16(w, 0.001); return b; } bool CMovingObject::setData(const CBinBuffer &b, unsigned int &pos) { Uint8 ID = b.getUint8(pos); if(ID != m_MovObjID) return false; //wrong delivery, in some way float time = b.getFloat32(pos, 0.005); //printf("Received package: sendTime = %.2f\n", time); if(time < m_LastNetworkUpdateTime) { printf("Old package: time %.2f < %.2f\n", time, m_LastNetworkUpdateTime); return false; //it was an old package } if(time > theWorld->m_LastTime + 3.0) { printf("Too late package: time %.2f > %.2f + 3.0\n", time, theWorld->m_LastTime); return false; //probably a package from a previous game session } m_LastNetworkUpdateTime = time; m_LastUpdateTime = theWorld->m_LastTime; //TODO: correct game time for average lag time CVector p = b.getVector32(pos, 0.001), o = b.getVector16(pos, 0.0002), v = b.getVector16(pos, 0.01), w = b.getVector16(pos, 0.001); /* A little hack: We do not REALLY set the position to the position in the message. Instead, we mix it with the current position. This damps out "synchronisation errors" */ //no damping at low speeds float dampFactor = v.abs2() / (10.0 + v.abs2()); //lower damping at higher differences in speed (e.g. collisions) float vdif2 = (v - m_Velocity).abs2(); dampFactor *= 10.0 / (10.0 + vdif2); if(dampFactor > 0.95) dampFactor = 0.95; //not too much damping if(!(dampFactor >= 0.0 && dampFactor <= 1.0)) dampFactor = 0.0; //you never know //printf("dampFactor = %s\n", CString(dampFactor).c_str()); //some damping to correct for "synchronisation noise" //We only do damping in the direction of v CVector vdir = v.normal(); CVector p_vdir = p.component(vdir); CVector p_ortho = p - p_vdir; m_Position = p_ortho + (1.0 - dampFactor) * p_vdir + dampFactor * m_Position.component(vdir); m_OrientationMatrix.setRotation(o); m_Velocity = v; m_AngularVelocity = w; return true; }