void RigidBody::CreateBody() { if (!impl->world || impl->body || !ParentEntity()) return; CheckForPlaceableAndTerrain(); CreateCollisionShape(); btVector3 localInertia; float m; int collisionFlags; impl->GetProperties(localInertia, m, collisionFlags); impl->body = new btRigidBody(m, impl, impl->shape, localInertia); // TEST: Adjust the threshold of when to sleep the object - for reducing network bandwidth. // impl->body->setSleepingThresholds(0.2f, 0.5f); // Bullet defaults are 0.8 and 1.0. impl->body->setUserPointer(this); impl->body->setCollisionFlags(collisionFlags); impl->world->BulletWorld()->addRigidBody(impl->body, (short)collisionLayer.Get(), (short)collisionMask.Get()); impl->body->activate(); UpdateGravity(); }
void GPlayer::Step(float dt) { CCPoint oldVelocity = velocity; CCPoint oldPosition = GetPlayerPosition(); CCPoint pos = sprite->getPosition(); pos = pos + velocity; sprite->setPosition(pos); if(applyGravity) velocity = velocity + gravity; if( oldVelocity.y == 0.0 && velocity.y != 0.0 && state == RUN) { state = JMP1; //CCLog("set player state JMP1"); } //check and set gravity UpdateGravity(); //velocity and gravity have the same direction if( (oldPosition.y <= gravity_line_y && pos.y > gravity_line_y) || (oldPosition.y > gravity_line_y && pos.y <= gravity_line_y) ) { SwitchGravity(); JumpDown(); CCLog("flip gravity!"); }else if(oldVelocity.y * velocity.y <= 0.0 && velocity.y * gravity.y > 0.0) { //CCLog("player's old velocity.y %f new velocity.y %f)", oldVelocity.y, velocity.y); JumpDown(); } //CCLog("player step position(%f, %f) velocity(%f, %f) gravity(%f, %f) state %d", // pos.x, pos.y, velocity.x, velocity.y, gravity.x, gravity.y, state); }
void RigidBody::SetGravityOverride(const Vector3& gravity) { if (gravity != gravityOverride_) { gravityOverride_ = gravity; UpdateGravity(); MarkNetworkUpdate(); } }
void RigidBody::SetUseGravity(bool enable) { if (enable != useGravity_) { useGravity_ = enable; UpdateGravity(); MarkNetworkUpdate(); } }
void RigidBody::AttributesChanged() { if (impl->disconnected) return; bool isShapeTriMeshOrConvexHull = (shapeType.Get() == TriMesh || shapeType.Get() == ConvexHull); bool bodyRead = false; bool meshRequested = false; // Create body now if does not exist yet if (!impl->body) CreateBody(); // If body was not created (we do not actually have a physics world), exit if (!impl->body) return; if (mass.ValueChanged() || collisionLayer.ValueChanged() || collisionMask.ValueChanged()) { // Read body to the world in case static/dynamic classification changed, or if collision mask changed ReaddBody(); bodyRead = true; } if (friction.ValueChanged()) impl->body->setFriction(friction.Get()); if (rollingFriction.ValueChanged()) impl->body->setRollingFriction(rollingFriction.Get()); if (restitution.ValueChanged()) impl->body->setRestitution(friction.Get()); if (linearDamping.ValueChanged() || angularDamping.ValueChanged()) impl->body->setDamping(linearDamping.Get(), angularDamping.Get()); if (linearFactor.ValueChanged()) impl->body->setLinearFactor(linearFactor.Get()); if (angularFactor.ValueChanged()) impl->body->setAngularFactor(angularFactor.Get()); if (shapeType.ValueChanged() || size.ValueChanged()) { if (shapeType.Get() != impl->cachedShapeType || !size.Get().Equals(impl->cachedSize)) { // If shape does not involve mesh, can create it directly. Otherwise request the mesh if (!isShapeTriMeshOrConvexHull) { CreateCollisionShape(); impl->cachedShapeType = shapeType.Get(); impl->cachedSize = size.Get(); } // If shape type has changed from TrimMesh <--> ConvexHull refresh the mesh shape. else if (shapeType.Get() != impl->cachedShapeType) { RequestMesh(); meshRequested = true; } // If size changed but no reload of mesh shape was done, update its scale. else if (!size.Get().Equals(impl->cachedSize)) UpdateScale(); } } // Request mesh if its id changes if (collisionMeshRef.ValueChanged() && isShapeTriMeshOrConvexHull && !meshRequested) RequestMesh(); // Readd body to the world in case phantom or kinematic classification changed if (!bodyRead && (phantom.ValueChanged() || kinematic.ValueChanged())) ReaddBody(); if (drawDebug.ValueChanged()) { bool enable = drawDebug.Get(); if (impl->body) { int collisionFlags = impl->body->getCollisionFlags(); if (enable) collisionFlags &= ~btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT; else collisionFlags |= btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT; impl->body->setCollisionFlags(collisionFlags); } // Refresh PhysicsWorld's knowledge of debug-enabled rigidbodies if (impl->world) { if (enable) impl->world->debugRigidBodies_.Insert(this); else impl->world->debugRigidBodies_.Erase(this); } } if (linearVelocity.ValueChanged() && !impl->disconnected) { impl->body->setLinearVelocity(linearVelocity.Get()); impl->body->activate(); } if (angularVelocity.ValueChanged() && !impl->disconnected) { impl->body->setAngularVelocity(DegToRad(angularVelocity.Get())); impl->body->activate(); } if (useGravity.ValueChanged()) UpdateGravity(); }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_netActionSync.UpdateObject(this); CryAutoCriticalSection lk(m_lock); CVehicleMovementBase::ProcessMovement(deltaTime); if (!(m_actorId && m_isEnginePowered)) { IPhysicalEntity* pPhysics = GetPhysics(); if (m_latFriction != 1.3f) SetLatFriction(1.3f); if (m_axleFriction != m_axleFrictionMax) UpdateAxleFriction(0.f, false, deltaTime); m_action.bHandBrake = 1; m_action.pedal = 0; m_action.steer = 0; pPhysics->Action(&m_action, 1); return; } IPhysicalEntity* pPhysics = GetPhysics(); MARK_UNUSED m_action.clutch; Matrix34 worldTM( m_PhysPos.q ); worldTM.AddTranslation( m_PhysPos.pos ); const Matrix34 invWTM = worldTM.GetInvertedFast(); Vec3 localVel = invWTM.TransformVector(m_PhysDyn.v); Vec3 localW = invWTM.TransformVector(m_PhysDyn.w); float speed = m_PhysDyn.v.len(); float speedRatio = min(1.f, speed/m_maxSpeed); float actionPedal = abs(m_movementAction.power) > 0.001f ? m_movementAction.power : 0.f; // tank specific: // avoid steering input around 0.5 (ask Anton) float actionSteer = m_movementAction.rotateYaw; float absSteer = abs(actionSteer); float steerSpeed = (absSteer < 0.01f && abs(m_currSteer) > 0.01f) ? m_steerSpeedRelax : m_steerSpeed; if (steerSpeed == 0.f) { m_currSteer = (float)sgn(actionSteer); } else { if (m_movementAction.isAI) { m_currSteer = actionSteer; } else { m_currSteer += min(abs(actionSteer-m_currSteer), deltaTime*steerSpeed) * sgn(actionSteer-m_currSteer); } } Limit(m_currSteer, -m_steerLimit, m_steerLimit); if (abs(m_currSteer) > 0.0001f) { // if steering, apply full throttle to have enough turn power actionPedal = (float)sgn(actionPedal); if (actionPedal == 0.f) { // allow steering-on-teh-spot only above maxReverseSpeed (to avoid sudden reverse of controls) const float maxReverseSpeed = -1.5f; actionPedal = max(0.f, min(1.f, 1.f-(localVel.y/maxReverseSpeed))); // todo float steerLim = 0.8f; Limit(m_currSteer, -steerLim*m_steerLimit, steerLim*m_steerLimit); } } if (!pPhysics->GetStatus(&m_vehicleStatus)) return; int currGear = m_vehicleStatus.iCurGear - 1; // indexing for convenience: -1,0,1,2,.. UpdateAxleFriction(m_movementAction.power, true, deltaTime); UpdateSuspension(deltaTime); float absPedal = abs(actionPedal); // pedal ramping if (m_pedalSpeed == 0.f) m_currPedal = actionPedal; else { m_currPedal += deltaTime * m_pedalSpeed * sgn(actionPedal - m_currPedal); m_currPedal = clamp_tpl(m_currPedal, -absPedal, absPedal); } // only apply pedal after threshold is exceeded if (currGear == 0 && fabs_tpl(m_currPedal) < m_pedalThreshold) m_action.pedal = 0; else m_action.pedal = m_currPedal; // change pedal amount based on damages float damageMul = 0.0f; { if (m_movementAction.isAI) { damageMul = 1.0f - 0.30f * m_damage; m_action.pedal *= damageMul; } else { // request from Sten: damage shouldn't affect reversing so much. float effectiveDamage = m_damage; if(m_action.pedal < -0.1f) effectiveDamage = 0.4f * m_damage; m_action.pedal *= GetWheelCondition(); damageMul = 1.0f - 0.7f*effectiveDamage; m_action.pedal *= damageMul; } } // reverse steering value for backward driving float effSteer = m_currSteer * sgn(actionPedal); // update lateral friction float latSlipMinGoal = 0.f; float latFricMinGoal = m_latFricMin; if (abs(effSteer) > 0.01f && !m_movementAction.brake) { latSlipMinGoal = m_latSlipMin; // use steering friction, but not when countersteering if (sgn(effSteer) != sgn(localW.z)) latFricMinGoal = m_latFricMinSteer; } Interpolate(m_currentSlipMin, latSlipMinGoal, 3.f, deltaTime); if (latFricMinGoal < m_currentFricMin) m_currentFricMin = latFricMinGoal; else Interpolate(m_currentFricMin, latFricMinGoal, 3.f, deltaTime); float fractionSpeed = min(1.f, max(0.f, m_avgLateralSlip-m_currentSlipMin) / (m_latSlipMax-m_currentSlipMin)); float latFric = fractionSpeed * (m_latFricMax-m_currentFricMin) + m_currentFricMin; if ( m_movementAction.brake && m_movementAction.isAI ) { // it is natural for ai, apply differnt friction value while handbreaking latFric = m_latFricMax; } if (latFric != m_latFriction) { SetLatFriction(latFric); } const static float maxSteer = gf_PI/4.f; // fix maxsteer, shouldn't change m_action.steer = m_currSteer * maxSteer; if (m_steeringImpulseMin > 0.f && m_wheelContactsLeft != 0 && m_wheelContactsRight != 0) { const float maxW = 0.3f*gf_PI; float steer = abs(m_currSteer)>0.001f ? m_currSteer : 0.f; float desired = steer * maxW; float curr = -localW.z; float err = desired - curr; // err>0 means correction to right Limit(err, -maxW, maxW); if (abs(err) > 0.01f) { float amount = m_steeringImpulseMin + speedRatio*(m_steeringImpulseMax-m_steeringImpulseMin); // bigger correction for relaxing if (desired == 0.f || (desired*curr>0 && abs(desired)<abs(curr))) amount = m_steeringImpulseRelaxMin + speedRatio*(m_steeringImpulseRelaxMax-m_steeringImpulseRelaxMin); float corr = -err * amount * m_PhysDyn.mass * deltaTime; pe_action_impulse imp; imp.iApplyTime = 0; imp.angImpulse = worldTM.GetColumn2() * corr; pPhysics->Action(&imp, THREAD_SAFE); } } m_action.bHandBrake = (m_movementAction.brake) ? 1 : 0; if (currGear > 0 && m_vehicleStatus.iCurGear < m_currentGear) { // when shifted down, disengage clutch immediately to avoid power/speed dropdown m_action.clutch = 1.f; } pPhysics->Action(&m_action, 1); if (Boosting()) ApplyBoost(speed, 1.2f*m_maxSpeed*GetWheelCondition()*damageMul, m_boostStrength, deltaTime); if (m_wheelContacts <= 1 && speed > 5.f) { ApplyAirDamp(DEG2RAD(20.f), DEG2RAD(10.f), deltaTime, THREAD_SAFE); UpdateGravity(-9.81f * 1.4f); } if (m_netActionSync.PublishActions( CNetworkMovementStdWheeled(this) )) CHANGED_NETWORK_STATE(m_pVehicle, eEA_GameClientDynamic ); }
void RigidBody::AddBodyToWorld() { if (!physicsWorld_) return; URHO3D_PROFILE(AddBodyToWorld); if (mass_ < 0.0f) mass_ = 0.0f; if (body_) RemoveBodyFromWorld(); else { // Correct inertia will be calculated below btVector3 localInertia(0.0f, 0.0f, 0.0f); body_ = new btRigidBody(mass_, this, shiftedCompoundShape_, localInertia); body_->setUserPointer(this); // Check for existence of the SmoothedTransform component, which should be created by now in network client mode. // If it exists, subscribe to its change events smoothedTransform_ = GetComponent<SmoothedTransform>(); if (smoothedTransform_) { SubscribeToEvent(smoothedTransform_, E_TARGETPOSITION, URHO3D_HANDLER(RigidBody, HandleTargetPosition)); SubscribeToEvent(smoothedTransform_, E_TARGETROTATION, URHO3D_HANDLER(RigidBody, HandleTargetRotation)); } // Check if CollisionShapes already exist in the node and add them to the compound shape. // Do not update mass yet, but do it once all shapes have been added PODVector<CollisionShape*> shapes; node_->GetComponents<CollisionShape>(shapes); for (PODVector<CollisionShape*>::Iterator i = shapes.Begin(); i != shapes.End(); ++i) (*i)->NotifyRigidBody(false); // Check if this node contains Constraint components that were waiting for the rigid body to be created, and signal them // to create themselves now PODVector<Constraint*> constraints; node_->GetComponents<Constraint>(constraints); for (PODVector<Constraint*>::Iterator i = constraints.Begin(); i != constraints.End(); ++i) (*i)->CreateConstraint(); } UpdateMass(); UpdateGravity(); int flags = body_->getCollisionFlags(); if (trigger_) flags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; else flags &= ~btCollisionObject::CF_NO_CONTACT_RESPONSE; if (kinematic_) flags |= btCollisionObject::CF_KINEMATIC_OBJECT; else flags &= ~btCollisionObject::CF_KINEMATIC_OBJECT; body_->setCollisionFlags(flags); body_->forceActivationState(kinematic_ ? DISABLE_DEACTIVATION : ISLAND_SLEEPING); if (!IsEnabledEffective()) return; btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld(); world->addRigidBody(body_, (short)collisionLayer_, (short)collisionMask_); inWorld_ = true; readdBody_ = false; if (mass_ > 0.0f) Activate(); else { SetLinearVelocity(Vector3::ZERO); SetAngularVelocity(Vector3::ZERO); } }