// Handles logic of contact points stored in array and passes parameters to ApplyFriction() where actual physics calculations are done void UMMTFrictionComponent::PhysicsUpdate(const float& NumberOfContactPoints, const float& DeltaTime, FVector& NormalizedReactionForce, FVector& RollingFrictionForce) { //Gather stats SCOPE_CYCLE_COUNTER(STAT_MMTFrictionPhysicsUpdate); FVector NormalizedReactionForceOut = FVector::ZeroVector; FVector RollingFrictionForceOut = FVector::ZeroVector; if (ContactPointsData.Num() > 0) { if (ContactPointsData[0].IsPointActive) { // Get physics sub-stepping valid transform of the friction component ReferenceFrameTransform = UMMTBPFunctionLibrary::MMTGetTransformComponent( this, NAME_None); // Collisions are often to happen on the edge of the collision mesh, we "project" points on the X axis of the friction component as if collision happened // on the center-line of the track FVector PointLocationCentered = ReferenceFrameTransform.InverseTransformPosition(ContactPointsData[0].ContactPointLocation); PointLocationCentered = ReferenceFrameTransform.TransformPosition(FVector(PointLocationCentered.X, 0.0f, PointLocationCentered.Z)); FVector PointNormalCentered = ReferenceFrameTransform.InverseTransformVector(ContactPointsData[0].ContactPointNormal); PointNormalCentered = ReferenceFrameTransform.TransformVector(FVector(PointNormalCentered.X, 0.0f, PointNormalCentered.Z)); FVector PreNormalForceCentered = ReferenceFrameTransform.InverseTransformVector(ContactPointsData[0].NormalImpulseAtPoint / DeltaTime); PreNormalForceCentered = ReferenceFrameTransform.TransformVector(FVector(PreNormalForceCentered.X, 0.0f, PreNormalForceCentered.Z)); //Apply Friction calculations ApplyFriction(PointLocationCentered, PointNormalCentered, ContactPointsData[0].InducedVelocity, PreNormalForceCentered, ContactPointsData[0].PhysicalSurface, NumberOfContactPoints, DeltaTime, NormalizedReactionForce, RollingFrictionForce); } else { //Return zero vector if point is inactive NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; } // Remove first element as it was processed or wasn't active ContactPointsData.RemoveAt(0, 1, true); } else { //Return zero vector if no points are stored in array NormalizedReactionForce = FVector::ZeroVector; RollingFrictionForce = FVector::ZeroVector; } }
/* * DrawAllUnits * * Draw all the units */ void DrawAllUnits (GdkPixmap *pixmap, GtkWidget *drawing_area) { /* * Move and display the hero */ ApplyFriction (); Move (hero); /* --- Keep him in-bounds. --- */ AdjustSpriteHeight (hero); DisplaySprite (drawing_area, sprite_ship, nShipAdjustment - (sprite_ship->width / 2), (int) hero->y - (sprite_ship->height / 2)); /* * Move and display everyone else */ DisplayOtherUnits (pixmap, drawing_area); }
/************************************************************************************************************* UPDATES KINETMATICS/POSITION: Velocity, Acceleration, Force, Position *************************************************************************************************************/ void PhysicsComponent::Update(float dt) { if (!isActive) return; //Calculate New Acceleration/Velocity this->v_Acceleration = this->v_Force / mass; this->v_Velocity = v_Velocity + v_Acceleration; //Limit if ((fabs)(v_Velocity.x) >= MAX_VELOCITY) v_Velocity.x = ((fabs)(v_Velocity.x) / v_Velocity.x) * MAX_VELOCITY; if ((fabs)(v_Velocity.y) >= MAX_VELOCITY) v_Velocity.y = ((fabs)(v_Velocity.y) / v_Velocity.y) * MAX_VELOCITY; if ((fabs)(v_Acceleration.x) >= MAX_ACCELERATION) v_Acceleration.x = ((fabs)(v_Acceleration.x) / v_Acceleration.x) * MAX_ACCELERATION; if ((fabs)(v_Acceleration.y) >= MAX_ACCELERATION) v_Acceleration.y = ((fabs)(v_Acceleration.y) / v_Acceleration.y) * MAX_ACCELERATION; /*************************************************************************************************************************** Horizontal Force ****************************************************************************************************************************/ if (hasFriction) ApplyFriction(); /*************************************************************************************************************************** Vertical Force ****************************************************************************************************************************/ if (hasGravity) ApplyGravity(); //Update Velocity and Position v_Force.SetZero(); v_Velocity = v_Velocity + v_Acceleration; *v_Pos = (*v_Pos) + v_Velocity * dt; }
void Grenade::Update ( float dt ) { m_fRotation += dt; m_fDetonationTimer -= dt; if(m_fDetonationTimer < 0) { CreateExplosionMessage* exploMsg = new CreateExplosionMessage(m_ptPosition.x, m_ptPosition.y, m_fDamage, m_fRadius); exploMsg->QueueMessage(); // Send the explosion event /*SGD::Event e("GRENADE_EXPLOSION", nullptr, this); e.SendEventNow();*/ // Explode DestroyEntityMessage* pMsg = new DestroyEntityMessage(this); // Queue the message pMsg->QueueMessage(); pMsg = nullptr; } if(m_fRotation > 2 * SGD::PI) m_fRotation = 0.0f; // Compute object speed, that is the norm of the velocity m_fSpeed = m_vtVelocity.ComputeLength (); // Compute the aerodynamic drag force m_vDragForce = m_vtVelocity * (-.5f * m_fSpeed * m_fDragCoefficient * 64); // Apply Friction ApplyFriction ( dt ); // Compute the acceleration using Newton's 2nd Law m_vAcceleration = m_vTotalForces / m_fMass; // Compute the velocity m_vtVelocity += m_vAcceleration * dt; Entity::Update ( dt ); }
void CBE_Floater::SearchManeuver(CCopyEntity* pCopyEnt, SBE_EnemyExtraData *pExtraData) { Vector3& rvDesiredDirection = pCopyEnt->v1; Vector3& rvTargetPosition = pExtraData->vTargetPosition; float& rfSensoringInterval2 = pExtraData->fSensoringInterval2; float& rfCurrentManeuverTime = pExtraData->fCurrentManeuverTime; float& rfTotalManeuverTime = pExtraData->fTotalManeuverTime; Vector3& rvManeuverDir = pExtraData->vManeuverDirection; float fWishSpeed = 6.0f; const float frametime = m_pStage->GetFrameTime(); // if( pCopyEnt->vVelocity == Vector3(0,0,0) ) // return; ApplyFriction( pCopyEnt, 1.5f ); if( m_iRandomSearchManeuver != 0 ) { Vector3 vFromCurrentPosToDest = rvTargetPosition - pCopyEnt->GetWorldPosition(); float fDist = Vec3LengthSq( vFromCurrentPosToDest ); if( 0.20f < rfCurrentManeuverTime - rfTotalManeuverTime || rvManeuverDir == Vector3(0,0,0) || fDist < 0.2f ) { rfCurrentManeuverTime = 0; rfTotalManeuverTime = 1.0f + 0.6f * (float)rand() / (float)RAND_MAX; // set up a target locaion rvTargetPosition = pExtraData->vOriginalPosition + Vector3(1,0,0) * ( 12.0f * (float)rand()/(float)RAND_MAX - 6.0f ) + Vector3(0,1,0) * ( 6.0f * (float)rand()/(float)RAND_MAX - 3.0f ) + Vector3(0,0,1) * ( 12.0f * (float)rand()/(float)RAND_MAX - 6.0f ) + pCopyEnt->GetDirection() * 2.5f; Vec3Normalize( rvManeuverDir, rvManeuverDir ); } else rfCurrentManeuverTime += frametime; if( 0.16f < rfSensoringInterval2 ) { rfSensoringInterval2 = 0.0f; Vec3Normalize( rvManeuverDir, vFromCurrentPosToDest ); } else rfSensoringInterval2 += frametime; if( 0.1f < rfTotalManeuverTime - rfCurrentManeuverTime ) { float fWishSpeed = 4.5f; Accelerate( pCopyEnt, rvManeuverDir, fWishSpeed, 2.0f ); } UpdateDesiredYawAndPitch(pCopyEnt, rvManeuverDir); AimAlong(pCopyEnt, rvManeuverDir); } SlideMove( pCopyEnt ); }
void C4Object::DoMovement() { int32_t iContact=0; bool fAnyContact=false; int iContacts = 0; BYTE fTurned=0,fRedirectYR=0,fNoAttach=0; // Restrictions if (Def->NoHorizontalMove) xdir=0; // Dig free target area C4PropList* pActionDef = GetAction(); if (pActionDef) if (pActionDef->GetPropertyInt(P_DigFree)) { int ctcox, ctcoy; // Shape size square if (pActionDef->GetPropertyInt(P_DigFree)==1) { ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir); ::Landscape.DigFreeRect(ctcox+Shape.GetX(),ctcoy+Shape.GetY(),Shape.Wdt,Shape.Hgt,this); } // Free size round (variable size) else { ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir); int32_t rad = pActionDef->GetPropertyInt(P_DigFree); if (Con<FullCon) rad = rad*6*Con/5/FullCon; ::Landscape.DigFree(ctcox,ctcoy-1,rad,this); } } // store previous movement and ocf C4Real oldxdir(xdir), oldydir(ydir); uint32_t old_ocf = OCF; bool fMoved = false; C4Real new_x = fix_x + xdir; C4Real new_y = fix_y + ydir; SideBounds(new_x); if (!Action.t_attach) // Unattached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = { // Horizontal movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Move to target while (fixtoi(new_x) != fixtoi(fix_x)) { // Next step int step = Sign(new_x - fix_x); uint32_t border_hack_contacts = 0; iContact=ContactCheck(GetX() + step, GetY(), &border_hack_contacts); if (iContact || border_hack_contacts) { fAnyContact=true; iContacts |= t_contact | border_hack_contacts; } if (iContact) { // Abort horizontal movement new_x = fix_x; // Vertical redirection (always) RedirectForce(xdir,ydir,-1); ApplyFriction(ydir,ContactVtxFriction(this)); } else // Free horizontal movement { DoMotion(step, 0); fMoved = true; } } // Vertical movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Movement target new_y = fix_y + ydir; // Movement bounds (vertical) VerticalBounds(new_y); // Move to target while (fixtoi(new_y) != fixtoi(fix_y)) { // Next step int step = Sign(new_y - fix_y); if ((iContact=ContactCheck(GetX(), GetY() + step, nullptr, ydir > 0))) { fAnyContact=true; iContacts |= t_contact; new_y = fix_y; // Vertical contact horizontal friction ApplyFriction(xdir,ContactVtxFriction(this)); // Redirection slide or rotate if (!ContactVtxCNAT(this,CNAT_Left)) RedirectForce(ydir,xdir,-1); else if (!ContactVtxCNAT(this,CNAT_Right)) RedirectForce(ydir,xdir,+1); else { // living things are always capable of keeping their rotation if (OCF & OCF_Rotate) if (iContact==1) if (!Alive) { RedirectForce(ydir,rdir,-ContactVtxWeight(this)); fRedirectYR=1; } ydir=0; } } else // Free vertical movement { DoMotion(0,step); fMoved = true; } } } if (Action.t_attach) // Attached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = { VerticalBounds(new_y); // Move to target do { // Set next step target int step_x = 0, step_y = 0; if (fixtoi(new_x) != GetX()) step_x = Sign(fixtoi(new_x) - GetX()); else if (fixtoi(new_y) != GetY()) step_y = Sign(fixtoi(new_y) - GetY()); int32_t ctx = GetX() + step_x; int32_t cty = GetY() + step_y; // Attachment check if (!Shape.Attach(ctx,cty,Action.t_attach)) fNoAttach=1; else { // Attachment change to ctx/cty overrides target if (ctx != GetX() + step_x) { xdir = Fix0; new_x = itofix(ctx); } if (cty != GetY() + step_y) { ydir = Fix0; new_y = itofix(cty); } } // Contact check & evaluation uint32_t border_hack_contacts = 0; iContact=ContactCheck(ctx,cty,&border_hack_contacts); if (iContact || border_hack_contacts) { fAnyContact=true; iContacts |= border_hack_contacts | t_contact; } if (iContact) { // Abort movement if (ctx != GetX()) { ctx = GetX(); new_x = fix_x; } if (cty != GetY()) { cty = GetY(); new_y = fix_y; } } DoMotion(ctx - GetX(), cty - GetY()); fMoved = true; } while (fixtoi(new_x) != GetX() || fixtoi(new_y) != GetY()); } if(fix_x != new_x || fix_y != new_y) { fMoved = true; if (pSolidMaskData) pSolidMaskData->Remove(true); fix_x = new_x; fix_y = new_y; } // Rotation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (OCF & OCF_Rotate && !!rdir) { C4Real target_r = fix_r + rdir * 5; // Rotation limit if (Def->Rotateable>1) { if (target_r > itofix(Def->Rotateable)) { target_r = itofix(Def->Rotateable); rdir=0; } if (target_r < itofix(-Def->Rotateable)) { target_r = itofix(-Def->Rotateable); rdir=0; } } int32_t ctx=GetX(); int32_t cty=GetY(); // Move to target while (fixtoi(fix_r) != fixtoi(target_r)) { // Save step undos C4Real lcobjr = fix_r; C4Shape lshape=Shape; // Try next step fix_r += Sign(target_r - fix_r); UpdateShape(); // attached rotation: rotate around attachment pos if (Action.t_attach && !fNoAttach) { // more accurately, attachment should be evaluated by a rotation around the attachment vertex // however, as long as this code is only used for some surfaces adjustment for large vehicles, // it's enough to assume rotation around the center ctx=GetX(); cty=GetY(); // evaluate attachment, but do not bother about attachment loss // that will then be done in next execution cycle Shape.Attach(ctx,cty,Action.t_attach); } // check for contact if ((iContact=ContactCheck(ctx,cty))) // Contact { fAnyContact=true; iContacts |= t_contact; // Undo step and abort movement Shape=lshape; target_r = fix_r = lcobjr; // last UpdateShape-call might have changed sector lists! UpdatePos(); // Redirect to GetY() if (iContact==1) if (!fRedirectYR) RedirectForce(rdir,ydir,-1); // Stop rotation rdir=0; } else { fTurned=1; if (ctx != GetX() || cty != GetY()) { fix_x = itofix(ctx); fix_y = itofix(cty); } } } // Circle bounds if (target_r < -FixHalfCircle) { target_r += FixFullCircle; } if (target_r > +FixHalfCircle) { target_r -= FixFullCircle; } fix_r = target_r; } // Reput solid mask if moved by motion if (fMoved || fTurned) UpdateSolidMask(true); // Misc checks =========================================================================================== // InLiquid check // this equals C4Object::UpdateLiquid, but the "fNoAttach=false;"-line if (IsInLiquidCheck()) // In Liquid { if (!InLiquid) // Enter liquid { if (OCF & OCF_HitSpeed2) if (Mass>3) Splash(GetX(),GetY()+1,std::min(Shape.Wdt*Shape.Hgt/10,20),this); fNoAttach=false; InLiquid=1; } } else // Out of liquid { if (InLiquid) // Leave liquid InLiquid=0; } // Contact Action if (fAnyContact) { t_contact = iContacts; ContactAction(); } // Attachment Loss Action if (fNoAttach) NoAttachAction(); // Movement Script Execution if (fAnyContact) { C4AulParSet pars(C4VInt(fixtoi(oldxdir, 100)), C4VInt(fixtoi(oldydir, 100))); if (old_ocf & OCF_HitSpeed1) Call(PSF_Hit, &pars); if (old_ocf & OCF_HitSpeed2) Call(PSF_Hit2, &pars); if (old_ocf & OCF_HitSpeed3) Call(PSF_Hit3, &pars); } // Rotation gfx if (fTurned) UpdateFace(true); else // pos changed? if (fMoved) UpdatePos(); }
/* ================ rvPhysics_Particle::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 rvPhysics_Particle::Evaluate( int timeStepMSec, int endTimeMSec ) { particlePState_t next; float timeStep; float upspeed; timeStep = MS2SEC( timeStepMSec ); // if bound to a master if ( hasMaster ) { idVec3 masterOrigin; idMat3 masterAxis; idVec3 oldOrigin; oldOrigin = current.origin; self->GetMasterPosition( masterOrigin, masterAxis ); current.origin = masterOrigin + current.localOrigin * masterAxis; // RAVEN BEGIN // ddynerman: multiple clip worlds clipModel->Link( self, clipModel->GetId(), current.origin, current.localAxis * masterAxis ); // RAVEN END trace_t tr; gameLocal.Translation( self, tr, oldOrigin, current.origin, clipModel, clipModel->GetAxis(), clipMask, self ); if ( tr.fraction < 1.0f ) { self->Collide ( tr, current.origin - oldOrigin ); } DebugDraw(); return true; } // 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(); return true; } clipModel->Unlink(); // Determine if currently on the ground CheckGround ( ); // Determine the current upward velocity if ( gravityNormal != vec3_zero ) { upspeed = -( current.velocity * gravityNormal ); } else { upspeed = current.velocity.z; } // If not on the ground, or moving upwards, or bouncing and moving toward gravity then do a straight // forward slide move and gravity. if ( !current.onGround || upspeed > 1.0f || (bouncyness > 0.0f && upspeed < -PRT_BOUNCESTOP && !current.inWater) ) { // Force ground off when moving upward if ( upspeed > 0.0f ) { current.onGround = false; } SlideMove( current.origin, current.velocity, current.velocity * timeStep ); if ( current.onGround && upspeed < PRT_BOUNCESTOP ) { current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal; } else { current.velocity += (gravityVector * timeStep); } } else { idVec3 delta; // Slow down due to friction ApplyFriction ( timeStep ); delta = current.velocity * timeStep; current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal; if ( delta == vec3_origin ) { PutToRest( ); } else { SlideMove( current.origin, current.velocity, delta ); } } // update the position of the clip model // RAVEN BEGIN // ddynerman: multiple clip worlds clipModel->Link( self, clipModel->GetId(), current.origin, clipModel->GetAxis() ); // RAVEN END DebugDraw(); // get all the ground contacts EvaluateContacts(); current.pushVelocity.Zero(); if ( IsOutsideWorld() ) { gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) ); PutToRest(); } return true; }