virtual void RequestPositionUpdate( IGameObject* pGameObject, const AUVec3f& desiredPosition, float frameDelta ) { AUVec3f pos = desiredPosition; ApplyGameAreaRepulsionField( pGameObject, pos, frameDelta ); ApplyTeamRepulsionFields( pGameObject, pos, frameDelta ); CheckForCollisions( pGameObject, pos, frameDelta ); pGameObject->GetEntity()->SetPosition(pos); }
bool CustomPhysicsEngine::Update() { for (unsigned int actorIndex = 0; actorIndex < actors.size(); ++actorIndex) { actors[actorIndex]->PhysicsUpdate(Time::deltaTime > 0.033f ? 0.033f : Time::deltaTime); } if (collisionEnabled) { CheckForCollisions(); } return true; }
void JelloMesh::Update(double dt, const World& world, const vec3& externalForces) { m_externalForces = externalForces; CheckForCollisions(m_vparticles, world); ComputeForces(m_vparticles); ResolveContacts(m_vparticles); ResolveCollisions(m_vparticles); switch (m_integrationType) { case EULER: EulerIntegrate(dt); break; case MIDPOINT: MidPointIntegrate(dt); break; case RK4: RK4Integrate(dt); break; } }
char PongGameLoop(void) { unsigned long dt; unsigned long thisTime; thisTime = GLIB_GetGameMillis(); dt = thisTime - g_lastTime; g_lastTime = thisTime; if (GetBitUInt8(&g_pongState, PONG_PLAYING)) { UpdateBall(&g_pongBall, dt); UpdatePlayerPaddle(&g_player, dt); UpdateCompPaddle(&g_comp, dt); HandleInput(); CheckForCollisions(); } RenderPong(dt); return 1; }
// ---------------------------------------------------------------------------- // Name: UpdateGameScreen // // Desc: Updates the game. Processes ball and paddle movement as well as // collisions and key presses. // ---------------------------------------------------------------------------- GameState CGame::UpdateGameScreen( FLOAT fElapsedTime ) { FLOAT x, y; BOOL l, r; D3DVECTOR d; GameState NextState = GameScreen; // Go back to the title screen if escape is pressed. if( m_bEscape && !m_pInput->KeyDown( DIK_ESCAPE ) ) { NextState = TitleScreen; m_bEscape = FALSE; } else if( !m_bEscape && m_pInput->KeyDown( DIK_ESCAPE ) ) { m_bEscape = TRUE; } // Get the deltas for how much the mouse moved and what buttons were // pressed. m_pInput->GetMouse( &l, &r, &x, &y ); // Position the paddle. m_vPaddlePos.x += (x * 0.1f * fElapsedTime); // Make sure the paddle cannot be moved outside of the game boundaries. // TODO: Refactor this so that magic numbers are NOT used. if( (m_vPaddlePos.x - 0.15f) <= (-0.9f) ) m_vPaddlePos.x = -0.75f; if( (m_vPaddlePos.x + 0.15f) >= (0.9f) ) m_vPaddlePos.x = 0.75f; m_pPaddle->SetPosition( m_vPaddlePos.x, m_vPaddlePos.y, m_vPaddlePos.z ); // Position the ball. CheckForCollisions( fElapsedTime ); // Bounce the ball off the sides of the walls. // TODO: Refactor this so that magic numbers are NOT used. if( (m_vBallPos.x + 0.03f) >= (0.99f) ) { m_vBallVel.x = -m_vBallVel.x; m_vBallPos.x = 0.95f; } if( (m_vBallPos.x - 0.03f) <= (-1.0f) ) { m_vBallVel.x = -m_vBallVel.x; m_vBallPos.x = -0.96f; } if( (m_vBallPos.y + 0.03f) >= (1.0f) ) { m_vBallVel.y = -m_vBallVel.y; m_vBallPos.y = 0.96f; } if( (m_vBallPos.y - 0.03f) <= (-1.0f) ) { m_vBallVel.y = -m_vBallVel.y; m_vBallPos.y = -0.96f; } // Find out how the ball bounces off the paddle. d.x = m_vPaddlePos.x - m_vBallPos.x; d.y = m_vPaddlePos.y - m_vBallPos.y; d.z = m_vPaddlePos.z - m_vBallPos.z; d = VecNormalize( d ); d.x = m_vBallPos.x + (d.x * 0.03); d.y = m_vBallPos.y + (d.y * 0.03); d.z = m_vBallPos.z + (d.z * 0.03); // TODO: Refactor so that magic numbers are NOT used. if( (d.y <= (m_vPaddlePos.y + 0.02f)) && (d.x >= (m_vPaddlePos.x - 0.25f)) && (d.x <= (m_vPaddlePos.x + 0.25f)) ) { m_vBallVel.y = -m_vBallVel.y; m_vBallPos.y = m_vPaddlePos.y + 0.051f; } if( (m_vBallPos.y < (m_vPaddlePos.y - 0.2f)) ) { NextState = TitleScreen; } m_pBall->SetPosition( m_vBallPos.x, m_vBallPos.y, m_vBallPos.z ); // Make sure the camera is oriented just right. m_pCamera->Position( 0.0f, 0.0f, -2.5f ); m_pDevice->SetTransform( D3DTS_VIEW, &m_pCamera->GetViewMatrix() ); // End the game if all the bricks have been destroyed. if( !m_dwTotalBricks ) NextState = TitleScreen; m_fSecondCount += fElapsedTime; m_dwNewFPS++; if( m_fSecondCount >= 1.0f ) { // Calculate an FPS. Deprecated. m_dwOldFPS = m_dwNewFPS; m_dwNewFPS = 0; // Increase the ball start timer. m_dwBallTimer++; m_fSecondCount = 0.0f; } if( m_dwBallTimer == 2 ) { // If 3 seconds have passed, then start the ball moving. m_vBallVel.x = 0.7f; m_vBallVel.y = 0.6f; } return NextState; }
void CPhysEnv::Simulate(float DeltaTime, BOOL running) { float CurrentTime = 0.0f; float TargetTime = DeltaTime; tParticle *tempSys; int collisionState; while(CurrentTime < DeltaTime) { if (running) { ComputeForces(m_CurrentSys); // IN ORDER TO MAKE THINGS RUN FASTER, I HAVE THIS LITTLE TRICK // IF THE SYSTEM IS DOING A BINARY SEARCH FOR THE COLLISION POINT, // I FORCE EULER'S METHOD ON IT. OTHERWISE, LET THE USER CHOOSE. // THIS DOESN'T SEEM TO EFFECT STABILITY EITHER WAY if (m_CollisionRootFinding) { EulerIntegrate(TargetTime-CurrentTime); } else { switch (m_IntegratorType) { case EULER_INTEGRATOR: EulerIntegrate(TargetTime-CurrentTime); break; case MIDPOINT_INTEGRATOR: MidPointIntegrate(TargetTime-CurrentTime); break; case HEUN_INTEGRATOR: HeunIntegrate(TargetTime-CurrentTime); break; case RK4_INTEGRATOR: RK4Integrate(TargetTime-CurrentTime); break; case RK4_ADAPTIVE_INTEGRATOR: RK4AdaptiveIntegrate(TargetTime-CurrentTime); break; case FEHLBERG: FehlbergIntegrate(TargetTime-CurrentTime); break; } } } collisionState = CheckForCollisions(m_TargetSys); if(collisionState == PENETRATING) { // TELL THE SYSTEM I AM LOOKING FOR A COLLISION SO IT WILL USE EULER m_CollisionRootFinding = TRUE; // we simulated too far, so subdivide time and try again TargetTime = (CurrentTime + TargetTime) / 2.0f; // blow up if we aren't moving forward each step, which is // probably caused by interpenetration at the frame start assert(fabs(TargetTime - CurrentTime) > EPSILON); } else { // either colliding or clear if(collisionState == COLLIDING) { int Counter = 0; do { ResolveCollisions(m_TargetSys); Counter++; } while((CheckForCollisions(m_TargetSys) == COLLIDING) && (Counter < 100)); assert(Counter < 100); m_CollisionRootFinding = FALSE; // FOUND THE COLLISION POINT } // we made a successful step, so swap configurations // to "save" the data for the next step CurrentTime = TargetTime; TargetTime = DeltaTime; // SWAP MY TWO PARTICLE SYSTEM BUFFERS SO I CAN DO IT AGAIN tempSys = m_CurrentSys; m_CurrentSys = m_TargetSys; m_TargetSys = tempSys; } } }
void UpdateSimulation(void) { double dt = _TIMESTEP; int i; double f, dl; Vector pt1, pt2; int j; Vector r; Vector F; Vector v1, v2, vr; if (FrameCounter >= _RENDER_FRAME_COUNT) { ClearBackBuffer(); DrawLine(0, _WINHEIGHT - _GROUND_PLANE, _WINWIDTH, _WINHEIGHT - _GROUND_PLANE, 3, RGB(0, 0, 0)); DrawObstacles(); } for (i = 0; i < _NUM_OBJECTS; i++) { Objects[i].vSprings.x = 0; Objects[i].vSprings.y = 0; Objects[i].vSprings.z = 0; } for (i = 0; i < _NUM_SPRINGS; i++) { j = Springs[i].End1; pt1 = Objects[j].vPosition; v1 = Objects[j].vVelocity; j = Springs[i].End2; pt2 = Objects[j].vPosition; v2 = Objects[j].vVelocity; vr = v2 - v1; r = pt2 - pt1; dl = r.Magnitude() - Springs[i].InitialLength; f = Springs[i].k* dl; r.Normalize(); F = (r*f) + (Springs[i].d*(vr*r))*r; j = Springs[i].End1; if (Objects[j].bLocked == false) Objects[j].vSprings += F; j = Springs[i].End2; if (Objects[j].bLocked == false) Objects[j].vSprings -= F; } for (i = 0; i < _NUM_OBJECTS; i++) { Objects[i].bCollision = CheckForCollisions(&(Objects[i])); Objects[i].CalcLoads(); Objects[i].UpdateBodyEuler(dt); if (FrameCounter >= _RENDER_FRAME_COUNT) { Objects[i].Draw(); if (i < _NUM_OBJECTS - 1) Objects[i].DrawObjectLine(Objects[i + 1].vPosition); } if (Objects[i].vPosition.x > _WINWIDTH) Objects[i].vPosition.x = 0; if (Objects[i].vPosition.x < 0) Objects[i].vPosition.x = _WINWIDTH; if (Objects[i].vPosition.y < 0) Objects[i].vPosition.y = _WINHEIGHT; } if (FrameCounter >= _RENDER_FRAME_COUNT) { CopyBackBufferToWindow(); FrameCounter = 0; } else FrameCounter++; }
/* ================ idPhysics_RigidBody::Evaluate Evaluate the impulse based rigid body physics. When a collision occurs an impulse is applied at the moment of impact but the remaining time after the collision is ignored. ================ */ bool idPhysics_RigidBody::Evaluate( int timeStepMSec, int endTimeMSec ) { rigidBodyPState_t next; idAngles angles; trace_t collision; idVec3 impulse; idEntity *ent; idVec3 oldOrigin, masterOrigin; idMat3 oldAxis, masterAxis; float timeStep; bool collided, cameToRest = false; timeStep = MS2SEC( timeStepMSec ); current.lastTimeStep = timeStep; if ( hasMaster ) { oldOrigin = current.i.position; oldAxis = current.i.orientation; self->GetMasterPosition( masterOrigin, masterAxis ); current.i.position = masterOrigin + current.localOrigin * masterAxis; if ( isOrientated ) { current.i.orientation = current.localAxis * masterAxis; } else { current.i.orientation = current.localAxis; } clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); current.i.linearMomentum = mass * ( ( current.i.position - oldOrigin ) / timeStep ); current.i.angularMomentum = inertiaTensor * ( ( current.i.orientation * oldAxis.Transpose() ).ToAngularVelocity() / timeStep ); current.externalForce.Zero(); current.externalTorque.Zero(); return ( current.i.position != oldOrigin || current.i.orientation != oldAxis ); } // if the body is at rest if ( current.atRest >= 0 || timeStep <= 0.0f ) { DebugDraw(); return false; } // if putting the body to rest if ( dropToFloor ) { DropToFloorAndRest(); current.externalForce.Zero(); current.externalTorque.Zero(); return true; } #ifdef RB_TIMINGS timer_total.Start(); #endif // move the rigid body velocity into the frame of a pusher // current.i.linearMomentum -= current.pushVelocity.SubVec3( 0 ) * mass; // current.i.angularMomentum -= current.pushVelocity.SubVec3( 1 ) * inertiaTensor; clipModel->Unlink(); next = current; // calculate next position and orientation Integrate( timeStep, next ); #ifdef RB_TIMINGS timer_collision.Start(); #endif // check for collisions from the current to the next state collided = CheckForCollisions( timeStep, next, collision ); #ifdef RB_TIMINGS timer_collision.Stop(); #endif // set the new state current = next; if ( collided ) { // apply collision impulse if ( CollisionImpulse( collision, impulse ) ) { current.atRest = gameLocal.time; } } // update the position of the clip model clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation ); DebugDraw(); if ( !noContact ) { #ifdef RB_TIMINGS timer_collision.Start(); #endif // get contacts EvaluateContacts(); #ifdef RB_TIMINGS timer_collision.Stop(); #endif // check if the body has come to rest if ( TestIfAtRest() ) { // put to rest Rest(); cameToRest = true; } else { // apply contact friction ContactFriction( timeStep ); } } if ( current.atRest < 0 ) { ActivateContactEntities(); } if ( collided ) { // if the rigid body didn't come to rest or the other entity is not at rest ent = gameLocal.entities[collision.c.entityNum]; if ( ent && ( !cameToRest || !ent->IsAtRest() ) ) { // apply impact to other entity ent->ApplyImpulse( self, collision.c.id, collision.c.point, -impulse ); } } // move the rigid body velocity back into the world frame // current.i.linearMomentum += current.pushVelocity.SubVec3( 0 ) * mass; // current.i.angularMomentum += current.pushVelocity.SubVec3( 1 ) * inertiaTensor; current.pushVelocity.Zero(); current.lastTimeStep = timeStep; current.externalForce.Zero(); current.externalTorque.Zero(); if ( IsOutsideWorld() ) { gameLocal.Warning( "rigid body moved outside world bounds for entity '%s' type '%s' at (%s)", self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) ); Rest(); } #ifdef RB_TIMINGS timer_total.Stop(); if ( rb_showTimings->integer == 1 ) { gameLocal.Printf( "%12s: t %u cd %u\n", self->name.c_str(), timer_total.Milliseconds(), timer_collision.Milliseconds() ); lastTimerReset = 0; } else if ( rb_showTimings->integer == 2 ) { numRigidBodies++; if ( endTimeMSec > lastTimerReset ) { gameLocal.Printf( "rb %d: t %u cd %u\n", numRigidBodies, timer_total.Milliseconds(), timer_collision.Milliseconds() ); } } if ( endTimeMSec > lastTimerReset ) { lastTimerReset = endTimeMSec; numRigidBodies = 0; timer_total.Clear(); timer_collision.Clear(); } #endif return true; }
//----------------------------------------------------------------------------- // Purpose: Main frame function, updates the state of the world and performs rendering //----------------------------------------------------------------------------- void CSpaceWarServer::RunFrame() { // Run any Steam Game Server API callbacks SteamGameServer_RunCallbacks(); // Update our server details SendUpdatedServerDetailsToSteam(); // Timeout stale player connections, also update player count data uint32 uPlayerCount = 0; for( uint32 i=0; i < MAX_PLAYERS_PER_SERVER; ++i ) { // If there is no ship, skip if ( !m_rgClientData[i].m_bActive ) continue; if ( m_pGameEngine->GetGameTickCount() - m_rgClientData[i].m_ulTickCountLastData > SERVER_TIMEOUT_MILLISECONDS ) { OutputDebugString( "Timing out player connection\n" ); RemovePlayerFromServer( i ); } else { ++uPlayerCount; } } m_uPlayerCount = uPlayerCount; switch ( m_eGameState ) { case k_EServerWaitingForPlayers: // Wait a few seconds (so everyone can join if a lobby just started this server) if ( m_pGameEngine->GetGameTickCount() - m_ulStateTransitionTime >= MILLISECONDS_BETWEEN_ROUNDS ) { // Just keep waiting until at least one ship is active for( uint32 i = 0; i < MAX_PLAYERS_PER_SERVER; ++i ) { if ( m_rgClientData[i].m_bActive ) { // Transition to active OutputDebugString( "Server going active after waiting for players\n" ); SetGameState( k_EServerActive ); } } } break; case k_EServerDraw: case k_EServerWinner: // Update all the entities... m_pSun->RunFrame(); for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i ) { if ( m_rgpShips[i] ) m_rgpShips[i]->RunFrame(); } // NOTE: no collision detection, because the round is really over, objects are now invulnerable // After 5 seconds start the next round if ( m_pGameEngine->GetGameTickCount() - m_ulStateTransitionTime >= MILLISECONDS_BETWEEN_ROUNDS ) { ResetPlayerShips(); SetGameState( k_EServerActive ); } break; case k_EServerActive: // Update all the entities... m_pSun->RunFrame(); for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i ) { if ( m_rgpShips[i] ) m_rgpShips[i]->RunFrame(); } // Check for collisions which could lead to a winner this round CheckForCollisions(); break; case k_EServerExiting: break; default: OutputDebugString( "Unhandled game state in CSpaceWarServer::RunFrame\n" ); } // Send client updates (will internal limit itself to the tick rate desired) SendUpdateDataToAllClients(); }