// 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. private 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},BSActorMoveToTarget.Mover,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},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); }
// Called just before the simulation step. Update the vertical position for hoverness. private 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.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 to walk. Set friction to moving friction. m_controllingPrim.Friction = BSParam.AvatarFriction; m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); } if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) { 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. OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; // 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); m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); } }
// Called just before the simulation step. Update the vertical position for hoverness. private 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_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 collising and velocity nearly zero. m_controllingPrim.ZeroMotion(true /* inTaintTime */); } } 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; } // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } // '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); if (moveForce.IsFinite()) { m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); } } 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; } }
// The avatar's movement is controlled by this motor that speeds up and slows down // the avatar seeking to reach the motor's target speed. // This motor runs as a prestep action for the avatar so it will keep the avatar // standing as well as moving. Destruction of the avatar will destroy the pre-step action. private void SetupMovementMotor() { // Infinite decay and timescale values so motor only changes current to target values. _velocityMotor = new BSVMotor("BSCharacter.Velocity", 0.2f, // time scale BSMotor.Infinite, // decay time scale BSMotor.InfiniteVector, // friction timescale 1f // efficiency ); // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) { // 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. _velocityMotor.Step(timeStep); // If we're not supposed to be moving, make sure things are zero. if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) { // The avatar shouldn't be moving _velocityMotor.Zero(); if (IsColliding) { // If we are colliding with a stationary object, presume we're standing and don't move around if (!ColliderIsMoving) { DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); ZeroMotion(true /* inTaintTime */); } // Standing has more friction on the ground if (Friction != BSParam.AvatarStandingFriction) { Friction = BSParam.AvatarStandingFriction; PhysicsScene.PE.SetFriction(PhysBody, Friction); } } else { if (Flying) { // Flying and not collising and velocity nearly zero. ZeroMotion(true /* inTaintTime */); } } DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); } else { // Supposed to be moving. OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; if (Friction != BSParam.AvatarFriction) { // Probably starting up walking. Set friction to moving friction. Friction = BSParam.AvatarFriction; PhysicsScene.PE.SetFriction(PhysBody, Friction); } // If falling, we keep the world's downward vector no matter what the other axis specify. // The check for _velocity.Z < 0 makes jumping work (temporary upward force). if (!Flying && !IsColliding) { if (_velocity.Z < 0) stepVelocity.Z = _velocity.Z; // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. OMV.Vector3 moveForce = (stepVelocity - _velocity) * 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(); DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); } }); }