// Origional mover that set the objects position to move to the target. // The problem was that gravity would keep trying to push the object down so // the overall downward velocity would increase to infinity. // Called just before the simulation step. Update the vertical position for hoverness. void Mover(float timeStep) { // Don't do hovering while the object is selected. if (!isActive) { return; } OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) // 'movePosition' is where we'd like the prim to be at this moment. OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); // If we are very close to our target, turn off the movement motor. if (m_targetMotor.ErrorIsZero()) { m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; // Setting the position does not cause the physics engine to generate a property update. Force it. m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } else { m_controllingPrim.ForcePosition = movePosition; // Setting the position does not cause the physics engine to generate a property update. Force it. m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); }
// Called just before the simulation step. Update the vertical position for hoverness. void Mover(float timeStep) { // Don't do movement while the object is selected. if (!isActive) { return; } // TODO: Decide if the step parameters should be changed depending on the avatar's // state (flying, colliding, ...). There is code in ODE to do this. // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity // specified for the avatar is the one that should be used. For falling, if the avatar // is not flying and is not colliding then it is presumed to be falling and the Z // component is not fooled with (thus allowing gravity to do its thing). // When the avatar is standing, though, the user has specified a velocity of zero and // the avatar should be standing. But if the avatar is pushed by something in the world // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity // errors can creap in and the avatar will slowly float off in some direction. // So, the problem is that, when an avatar is standing, we cannot tell creaping error // from real pushing. // The code below uses whether the collider is static or moving to decide whether to zero motion. m_velocityMotor.Step(timeStep); m_controllingPrim.IsStationary = false; // If we're not supposed to be moving, make sure things are zero. if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) { // The avatar shouldn't be moving m_velocityMotor.Zero(); if (m_controllingPrim.IsColliding) { // If we are colliding with a stationary object, presume we're standing and don't move around if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.VolumeDetect) // new //if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) { m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); m_controllingPrim.IsStationary = true; m_controllingPrim.ZeroMotion(true /* inTaintTime */); } // Standing has more friction on the ground if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) { m_controllingPrim.Friction = BSParam.AvatarStandingFriction; m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); } } else { if (m_controllingPrim.Flying) { // Flying and not colliding and velocity nearly zero. m_controllingPrim.ZeroMotion(true /* inTaintTime */); } else { //We are falling but are not touching any keys make sure not falling too fast if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) { OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass; m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce); } } } m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); } else { // Supposed to be moving. OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; if (m_controllingPrim.Friction != BSParam.AvatarFriction) { // Probably starting up walking. Set friction to moving friction. m_controllingPrim.Friction = BSParam.AvatarFriction; m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); } // If falling, we keep the world's downward vector no matter what the other axis specify. // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) { if (m_controllingPrim.RawVelocity.Z < 0) { stepVelocity.Z = m_controllingPrim.RawVelocity.Z; } } // Colliding and not flying with an upward force. The avatar must be trying to jump. if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) { // We allow the upward force to happen for this many frames. m_jumpFrames = BSParam.AvatarJumpFrames; m_jumpVelocity = stepVelocity.Z; } // The case where the avatar is not colliding and is not flying is special. // The avatar is either falling or jumping and the user can be applying force to the avatar // (force in some direction or force up or down). // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. // If the user is trying to apply upward force but we're not colliding, assume the avatar // is trying to jump and don't apply the upward force if not touching the ground any more. if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) { // If upward velocity is being applied, this must be a jump and only allow that to go on so long if (m_jumpFrames > 0) { // Since not touching the ground, only apply upward force for so long. m_jumpFrames--; stepVelocity.Z = m_jumpVelocity; } else { // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast. if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) { stepVelocity.Z = BSParam.AvatarTerminalVelocity; } else { stepVelocity.Z = m_controllingPrim.RawVelocity.Z; } } // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } //Alicia: Maintain minimum height when flying. // SL has a flying effect that keeps the avatar flying above the ground by some margin if (m_controllingPrim.Flying) { float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition) + BSParam.AvatarFlyingGroundMargin; if (m_controllingPrim.Position.Z < hover_height) { stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce; } } // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; // Should we check for move force being small and forcing velocity to zero? // Add special movement force to allow avatars to walk up stepped surfaces. moveForce += WalkUpStairs(); m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); // i think this fix is working .. :-) if (moveForce.IsFinite()) { m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); } } // a bit of jump processing... if (m_preJumpStart != 0 && Util.EnvironmentTickCountSubtract(m_preJumpStart) > 300) { m_controllingPrim.IsPreJumping = false; m_controllingPrim.IsJumping = true; m_preJumpStart = 0; OMV.Vector3 target = m_jumpDirection; target.X *= 1.5f; target.Y *= 1.5f; target.Z *= 2.5f; //Scale so that we actually jump SetVelocityAndTargetInternal(m_controllingPrim.RawVelocity, target, false, 1); m_jumpStart = Util.EnvironmentTickCount(); } if (!m_jumpFallState && m_jumpStart != 0 && Util.EnvironmentTickCountSubtract(m_jumpStart) > 500) { OMV.Vector3 newTarget = m_controllingPrim.RawVelocity; newTarget.X *= 1.5f; //Scale so that the jump looks correct newTarget.Y *= 1.5f; newTarget.Z *= -0.2f; SetVelocityAndTargetInternal(m_controllingPrim.RawVelocity, newTarget, false, 3); m_jumpFallState = true; } else if (m_jumpFallState && m_jumpStart != 0 && m_controllingPrim.IsColliding && Util.EnvironmentTickCountSubtract(m_jumpStart) > 1500 || (m_jumpStart != 0 && Util.EnvironmentTickCountSubtract(m_jumpStart) > 10000)) //Fallback { //Reset everything in case something went wrong m_disallowTargetVelocitySet = false; m_jumpFallState = false; m_controllingPrim.IsPreJumping = false; m_controllingPrim.IsJumping = false; m_jumpStart = 0; m_preJumpStart = 0; } }