コード例 #1
0
        public void MoveToTargetPosition(bool lerp = true)
        {
            if (targetPosition == null)
            {
                return;
            }

            if (lerp)
            {
                if (Vector2.DistanceSquared((Vector2)targetPosition, body.Position) < 10.0f * 10.0f)
                {
                    drawOffset   = -((Vector2)targetPosition - (body.Position + drawOffset));
                    prevPosition = (Vector2)targetPosition;
                }
                else
                {
                    drawOffset = Vector2.Zero;
                }
                if (targetRotation.HasValue)
                {
                    rotationOffset = -MathUtils.GetShortestAngle(body.Rotation + rotationOffset, targetRotation.Value);
                }
            }

            SetTransform((Vector2)targetPosition, targetRotation == null ? body.Rotation : (float)targetRotation);
            targetPosition = null;
            targetRotation = null;
        }
コード例 #2
0
        public bool IsWithinSector(Vector2 worldPosition)
        {
            if (sectorRad >= MathHelper.TwoPi)
            {
                return(true);
            }
            Vector2 diff = worldPosition - WorldPosition;

            return(MathUtils.GetShortestAngle(MathUtils.VectorToAngle(diff), MathUtils.VectorToAngle(sectorDir)) <= sectorRad * 0.5f);
        }
コード例 #3
0
        /// <summary>
        /// rotate the body towards the target rotation in the "shortest direction"
        /// </summary>
        public void SmoothRotate(float targetRotation, float force = 10.0f)
        {
            float nextAngle = body.Rotation + body.AngularVelocity * (float)Timing.Step;

            float angle = MathUtils.GetShortestAngle(nextAngle, targetRotation);

            float torque = angle * 60.0f * (force / 100.0f);

            if (body.IsKinematic)
            {
                body.AngularVelocity = torque;
            }
            else
            {
                body.ApplyTorque(body.Mass * torque);
            }
        }
コード例 #4
0
        /// <summary>
        /// Rotate the body towards the target rotation in the "shortest direction", taking into account the current angular velocity to prevent overshooting.
        /// </summary>
        /// <param name="targetRotation">Desired rotation in radians</param>
        /// <param name="force">How fast the body should be rotated. Does not represent any real unit, you may want to experiment with different values to get the desired effect.</param>
        /// <param name="wrapAngle">Should the angles be wrapped. Set to false if it makes a difference whether the angle of the body is 0.0f or 360.0f.</param>
        public void SmoothRotate(float targetRotation, float force = 10.0f, bool wrapAngle = true)
        {
            float nextAngle = body.Rotation + body.AngularVelocity * (float)Timing.Step;
            float angle = wrapAngle ? 
                MathUtils.GetShortestAngle(nextAngle, targetRotation) : 
                MathHelper.Clamp(targetRotation - nextAngle, -MathHelper.Pi, MathHelper.Pi);
            float torque = angle * 60.0f * (force / 100.0f);

            if (body.IsKinematic)
            {
                if (!IsValidValue(torque, "torque")) return;
                body.AngularVelocity = torque;
            }
            else
            {
                ApplyTorque(body.Mass * torque);
            }
        }
コード例 #5
0
        public bool SectorHit(Vector2 armorSector, Vector2 simPosition)
        {
            if (armorSector == Vector2.Zero)
            {
                return(false);
            }

            float rot = body.Rotation;

            if (Dir == -1)
            {
                rot -= MathHelper.Pi;
            }

            Vector2 armorLimits = new Vector2(rot - armorSector.X * Dir, rot - armorSector.Y * Dir);

            float mid       = (armorLimits.X + armorLimits.Y) / 2.0f;
            float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(simPosition - SimPosition), mid);

            return(Math.Abs(angleDiff) < (armorSector.Y - armorSector.X) / 2.0f);
        }
コード例 #6
0
        public override void UpdateAnim(float deltaTime)
        {
            if (Frozen)
            {
                return;
            }
            if (MainLimb == null)
            {
                return;
            }

            if (!character.AllowInput)
            {
                levitatingCollider = false;
                Collider.FarseerBody.FixedRotation = false;
                if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
                {
                    Collider.LinearVelocity            = MainLimb.LinearVelocity;
                    Collider.FarseerBody.FixedRotation = false;
                    Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
                }
                if (character.IsDead && deathAnimTimer < deathAnimDuration)
                {
                    deathAnimTimer += deltaTime;
                    UpdateDying(deltaTime);
                }
                return;
            }
            else
            {
                deathAnimTimer = 0.0f;
            }

            //re-enable collider
            if (!Collider.Enabled)
            {
                var lowestLimb = FindLowestLimb();

                Collider.SetTransform(new Vector2(
                                          Collider.SimPosition.X,
                                          Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
                                      0.0f);

                Collider.Enabled = true;
            }

            ResetPullJoints();

            if (strongestImpact > 0.0f)
            {
                character.Stun  = MathHelper.Clamp(strongestImpact * 0.5f, character.Stun, 5.0f);
                strongestImpact = 0.0f;
            }

            if (inWater && !forceStanding)
            {
                Collider.FarseerBody.FixedRotation = false;
                UpdateSineAnim(deltaTime);
            }
            else if (CanEnterSubmarine && (currentHull != null || forceStanding) && CurrentGroundedParams != null)
            {
                //rotate collider back upright
                float standAngle = dir == Direction.Right ? CurrentGroundedParams.ColliderStandAngleInRadians : -CurrentGroundedParams.ColliderStandAngleInRadians;
                if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, standAngle)) > 0.001f)
                {
                    Collider.AngularVelocity           = MathUtils.GetShortestAngle(Collider.Rotation, standAngle) * 60.0f;
                    Collider.FarseerBody.FixedRotation = false;
                }
                else
                {
                    Collider.FarseerBody.FixedRotation = true;
                }

                UpdateWalkAnim(deltaTime);
            }

            //don't flip or drag when simply physics is enabled
            if (SimplePhysicsEnabled)
            {
                return;
            }

            if (!character.IsRemotePlayer && (character.AIController == null || character.AIController.CanFlip))
            {
                if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
                {
                    if (targetMovement.X > 0.1f && targetMovement.X > Math.Abs(targetMovement.Y) * 0.2f)
                    {
                        TargetDir = Direction.Right;
                    }
                    else if (targetMovement.X < -0.1f && targetMovement.X < -Math.Abs(targetMovement.Y) * 0.2f)
                    {
                        TargetDir = Direction.Left;
                    }
                }
                else
                {
                    float refAngle = 0.0f;
                    Limb  refLimb  = GetLimb(LimbType.Head);
                    if (refLimb == null)
                    {
                        refAngle = CurrentAnimationParams.TorsoAngleInRadians;
                        refLimb  = GetLimb(LimbType.Torso);
                    }
                    else
                    {
                        refAngle = CurrentAnimationParams.HeadAngleInRadians;
                    }

                    float rotation = refLimb.Rotation;
                    if (!float.IsNaN(refAngle))
                    {
                        rotation -= refAngle * Dir;
                    }

                    rotation = MathHelper.ToDegrees(MathUtils.WrapAngleTwoPi(rotation));

                    if (rotation < 0.0f)
                    {
                        rotation += 360;
                    }

                    if (rotation > 20 && rotation < 160)
                    {
                        TargetDir = Direction.Left;
                    }
                    else if (rotation > 200 && rotation < 340)
                    {
                        TargetDir = Direction.Right;
                    }
                }
            }

            if (character.SelectedCharacter != null)
            {
                DragCharacter(character.SelectedCharacter, deltaTime);
            }

            if (!CurrentFishAnimation.Flip || IsStuck)
            {
                return;
            }
            if (character.AIController != null && !character.AIController.CanFlip)
            {
                return;
            }

            flipCooldown -= deltaTime;

            if (TargetDir != Direction.None && TargetDir != dir)
            {
                flipTimer += deltaTime;
                if ((flipTimer > 0.5f && flipCooldown <= 0.0f) || character.IsRemotePlayer)
                {
                    Flip();
                    if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
                    {
                        Mirror();
                    }
                    flipTimer    = 0.0f;
                    flipCooldown = 1.0f;
                }
            }
            else
            {
                flipTimer = 0.0f;
            }
        }
コード例 #7
0
        public override void UpdateAnim(float deltaTime)
        {
            if (Frozen)
            {
                return;
            }
            if (MainLimb == null)
            {
                return;
            }
            var mainLimb = MainLimb;

            levitatingCollider = true;

            if (!character.CanMove)
            {
                levitatingCollider = false;
                Collider.FarseerBody.FixedRotation = false;
                if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
                {
                    Collider.Enabled        = false;
                    Collider.LinearVelocity = mainLimb.LinearVelocity;
                    Collider.SetTransformIgnoreContacts(mainLimb.SimPosition, mainLimb.Rotation);
                    //reset pull joints to prevent the character from "hanging" mid-air if pull joints had been active when the character was still moving
                    //(except when dragging, then we need the pull joints)
                    if (!character.CanBeDragged || character.SelectedBy == null)
                    {
                        ResetPullJoints();
                    }
                }
                if (character.IsDead && deathAnimTimer < deathAnimDuration)
                {
                    deathAnimTimer += deltaTime;
                    UpdateDying(deltaTime);
                }
                else if (!InWater && !CanWalk && character.AllowInput)
                {
                    //cannot walk but on dry land -> wiggle around
                    UpdateDying(deltaTime);
                }
                return;
            }
            else
            {
                deathAnimTimer = 0.0f;
            }

            //re-enable collider
            if (!Collider.Enabled)
            {
                var lowestLimb = FindLowestLimb();

                Collider.SetTransform(new Vector2(
                                          Collider.SimPosition.X,
                                          Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
                                      0.0f);

                Collider.Enabled = true;
            }

            ResetPullJoints();

            if (strongestImpact > 0.0f)
            {
                character.Stun  = MathHelper.Clamp(strongestImpact * 0.5f, character.Stun, 5.0f);
                strongestImpact = 0.0f;
            }

            if (inWater && !forceStanding)
            {
                Collider.FarseerBody.FixedRotation = false;
                UpdateSineAnim(deltaTime);
            }
            else if (RagdollParams.CanWalk && (currentHull != null || forceStanding))
            {
                if (CurrentGroundedParams != null)
                {
                    //rotate collider back upright
                    float standAngle = dir == Direction.Right ? CurrentGroundedParams.ColliderStandAngleInRadians : -CurrentGroundedParams.ColliderStandAngleInRadians;
                    if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, standAngle)) > 0.001f)
                    {
                        Collider.AngularVelocity           = MathUtils.GetShortestAngle(Collider.Rotation, standAngle) * 60.0f;
                        Collider.FarseerBody.FixedRotation = false;
                    }
                    else
                    {
                        Collider.FarseerBody.FixedRotation = true;
                    }
                }
                UpdateWalkAnim(deltaTime);
            }

            if (character.SelectedCharacter != null)
            {
                DragCharacter(character.SelectedCharacter, deltaTime);
            }

            //don't flip when simply physics is enabled
            if (SimplePhysicsEnabled)
            {
                return;
            }

            if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip))
            {
                if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
                {
                    if (targetMovement.X > 0.1f && targetMovement.X > Math.Abs(targetMovement.Y) * 0.2f)
                    {
                        TargetDir = Direction.Right;
                    }
                    else if (targetMovement.X < -0.1f && targetMovement.X < -Math.Abs(targetMovement.Y) * 0.2f)
                    {
                        TargetDir = Direction.Left;
                    }
                }
                else
                {
                    float rotation = MathHelper.WrapAngle(Collider.Rotation);
                    rotation = MathHelper.ToDegrees(rotation);
                    if (rotation < 0.0f)
                    {
                        rotation += 360;
                    }
                    if (rotation > 20 && rotation < 160)
                    {
                        TargetDir = Direction.Left;
                    }
                    else if (rotation > 200 && rotation < 340)
                    {
                        TargetDir = Direction.Right;
                    }
                }
            }

            if (!CurrentFishAnimation.Flip)
            {
                return;
            }
            if (IsStuck)
            {
                return;
            }
            if (character.AIController != null && !character.AIController.CanFlip)
            {
                return;
            }

            flipCooldown -= deltaTime;
            if (TargetDir != Direction.None && TargetDir != dir)
            {
                flipTimer += deltaTime;
                // Speed reductions are not taken into account here. It's intentional: an ai character cannot flip if it's heavily paralyzed (for example).
                float requiredSpeed = CurrentAnimationParams.MovementSpeed / 2;
                if (CurrentHull != null)
                {
                    // Enemy movement speeds are halved inside submarines
                    requiredSpeed /= 2;
                }
                bool isMovingFastEnough         = Math.Abs(MainLimb.LinearVelocity.X) > requiredSpeed;
                bool isTryingToMoveHorizontally = Math.Abs(TargetMovement.X) > Math.Abs(TargetMovement.Y);
                if ((flipTimer > CurrentFishAnimation.FlipDelay && flipCooldown <= 0.0f && ((isMovingFastEnough && isTryingToMoveHorizontally) || IsMovingBackwards)) ||
                    character.IsRemotePlayer)
                {
                    Flip();
                    if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
                    {
                        Mirror(CurrentSwimParams != null ? CurrentSwimParams.MirrorLerp : true);
                    }
                    flipTimer    = 0.0f;
                    flipCooldown = CurrentFishAnimation.FlipCooldown;
                }
            }
            else
            {
                flipTimer = 0.0f;
            }
        }
コード例 #8
0
        public static float InterpolateRotation(float previous, float current)
        {
            float angleDiff = MathUtils.GetShortestAngle(previous, current);

            return(previous + angleDiff * (float)alpha);
        }
コード例 #9
0
        public override void UpdateAnim(float deltaTime)
        {
            if (Frozen)
            {
                return;
            }

            if (character.IsDead || character.IsUnconscious || character.Stun > 0.0f)
            {
                Collider.FarseerBody.FixedRotation = false;

                if (character.IsRemotePlayer)
                {
                    if (!SimplePhysicsEnabled)
                    {
                        MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
                        MainLimb.PullJointEnabled      = true;
                    }
                }
                else
                {
                    Vector2 diff = (MainLimb.SimPosition - Collider.SimPosition);
                    if (diff.LengthSquared() > 10.0f * 10.0f)
                    {
                        Collider.SetTransform(MainLimb.SimPosition, MainLimb.Rotation);
                    }
                    else
                    {
                        Collider.LinearVelocity = diff * 60.0f;
                        Collider.SmoothRotate(MainLimb.Rotation);
                    }
                }

                if (character.IsDead && deathAnimTimer < deathAnimDuration)
                {
                    deathAnimTimer += deltaTime;
                    UpdateDying(deltaTime);
                }

                return;
            }

            //re-enable collider
            if (!Collider.Enabled)
            {
                var lowestLimb = FindLowestLimb();

                Collider.SetTransform(new Vector2(
                                          Collider.SimPosition.X,
                                          Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
                                      0.0f);

                Collider.Enabled = true;
            }

            ResetPullJoints();

            if (strongestImpact > 0.0f)
            {
                character.Stun  = MathHelper.Clamp(strongestImpact * 0.5f, character.Stun, 5.0f);
                strongestImpact = 0.0f;
            }


            if (inWater)
            {
                Collider.FarseerBody.FixedRotation = false;
                UpdateSineAnim(deltaTime);
            }
            else if (currentHull != null && CanEnterSubmarine)
            {
                if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, 0.0f)) > 0.001f)
                {
                    //rotate collider back upright
                    Collider.AngularVelocity           = MathUtils.GetShortestAngle(Collider.Rotation, 0.0f) * 60.0f;
                    Collider.FarseerBody.FixedRotation = false;
                }
                else
                {
                    Collider.FarseerBody.FixedRotation = true;
                }

                UpdateWalkAnim(deltaTime);
            }

            //don't flip or drag when simply physics is enabled
            if (SimplePhysicsEnabled)
            {
                return;
            }

            if (!character.IsRemotePlayer)
            {
                if (mirror || !inWater)
                {
                    if (targetMovement.X > 0.1f && targetMovement.X > Math.Abs(targetMovement.Y) * 0.5f)
                    {
                        TargetDir = Direction.Right;
                    }
                    else if (targetMovement.X < -0.1f && targetMovement.X < -Math.Abs(targetMovement.Y) * 0.5f)
                    {
                        TargetDir = Direction.Left;
                    }
                }
                else
                {
                    Limb head = GetLimb(LimbType.Head);
                    if (head == null)
                    {
                        head = GetLimb(LimbType.Torso);
                    }

                    float rotation = MathUtils.WrapAngleTwoPi(head.Rotation);
                    rotation = MathHelper.ToDegrees(rotation);

                    if (rotation < 0.0f)
                    {
                        rotation += 360;
                    }

                    if (rotation > 20 && rotation < 160)
                    {
                        TargetDir = Direction.Left;
                    }
                    else if (rotation > 200 && rotation < 340)
                    {
                        TargetDir = Direction.Right;
                    }
                }
            }

            if (character.SelectedCharacter != null)
            {
                DragCharacter(character.SelectedCharacter);
            }

            if (!flip)
            {
                return;
            }

            flipTimer += deltaTime;

            if (TargetDir != Direction.None && TargetDir != dir)
            {
                if (flipTimer > 1.0f || character.IsRemotePlayer)
                {
                    Flip();
                    if (mirror || !inWater)
                    {
                        Mirror();
                    }
                    flipTimer = 0.0f;
                }
            }
        }
コード例 #10
0
        public override void UpdateAnim(float deltaTime)
        {
            if (Frozen)
            {
                return;
            }

            levitatingCollider = true;
            ColliderIndex      = Crouching ? 1 : 0;
            if (!Crouching && ColliderIndex == 1)
            {
                Crouching = true;
            }

            if (!character.AllowInput)
            {
                levitatingCollider = false;
                Collider.FarseerBody.FixedRotation = false;

                Collider.LinearVelocity = (GetLimb(LimbType.Waist).SimPosition - Collider.SimPosition) * 20.0f;
                Collider.SmoothRotate(GetLimb(LimbType.Torso).Rotation);

                return;
            }

            //stun (= disable the animations) if the ragdoll receives a large enough impact
            if (strongestImpact > 0.0f)
            {
                character.SetStun(MathHelper.Min(strongestImpact * 0.5f, 5.0f));
                strongestImpact = 0.0f;
                return;
            }


            //re-enable collider
            if (!Collider.FarseerBody.Enabled)
            {
                var lowestLimb = FindLowestLimb();

                Collider.SetTransform(new Vector2(
                                          Collider.SimPosition.X,
                                          Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
                                      Collider.Rotation);

                Collider.FarseerBody.ResetDynamics();
                Collider.FarseerBody.Enabled = true;
            }

            if (swimming)
            {
                Collider.FarseerBody.FixedRotation = false;
            }
            else if (!Collider.FarseerBody.FixedRotation)
            {
                if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, 0.0f)) > 0.001f)
                {
                    //rotate collider back upright
                    Collider.AngularVelocity = MathUtils.GetShortestAngle(Collider.Rotation, 0.0f) * 10.0f;

                    Collider.FarseerBody.FixedRotation = false;
                }
                else
                {
                    Collider.FarseerBody.FixedRotation = true;
                }
            }

            if (character.LockHands)
            {
                var leftHand  = GetLimb(LimbType.LeftHand);
                var rightHand = GetLimb(LimbType.RightHand);

                var waist = GetLimb(LimbType.Waist);

                rightHand.Disabled = true;
                leftHand.Disabled  = true;

                Vector2 midPos         = waist.SimPosition;
                Matrix  torsoTransform = Matrix.CreateRotationZ(waist.Rotation);

                midPos += Vector2.Transform(new Vector2(-0.3f * Dir, -0.2f), torsoTransform);

                if (rightHand.pullJoint.Enabled)
                {
                    midPos = (midPos + rightHand.pullJoint.WorldAnchorB) / 2.0f;
                }

                HandIK(rightHand, midPos);
                HandIK(leftHand, midPos);
            }
            else
            {
                if (Anim != Animation.UsingConstruction)
                {
                    ResetPullJoints();
                }
            }

            if (SimplePhysicsEnabled)
            {
                UpdateStandingSimple();
                return;
            }


            switch (Anim)
            {
            case Animation.Climbing:
                levitatingCollider = false;
                UpdateClimbing();
                break;

            case Animation.CPR:
                UpdateCPR(deltaTime);
                break;

            case Animation.UsingConstruction:
            default:

                if (character.SelectedCharacter != null)
                {
                    DragCharacter(character.SelectedCharacter);
                }

                //0.5 second delay for switching between swimming and walking
                //prevents rapid switches between swimming/walking if the water level is fluctuating around the minimum swimming depth
                if (inWater)
                {
                    inWaterTimer = Math.Max(inWaterTimer + deltaTime, 0.5f);
                    if (inWaterTimer >= 1.0f)
                    {
                        swimming = true;
                    }
                }
                else
                {
                    inWaterTimer = Math.Min(inWaterTimer - deltaTime, 0.5f);
                    if (inWaterTimer <= 0.0f)
                    {
                        swimming = false;
                    }
                }

                if (swimming)
                {
                    UpdateSwimming();
                }
                else
                {
                    UpdateStanding();
                }

                break;
            }

            if (TargetDir != dir)
            {
                Flip();
            }

            foreach (Limb limb in Limbs)
            {
                limb.Disabled = false;
            }

            aiming = false;
            if (character.IsRemotePlayer && GameMain.Server == null)
            {
                Collider.LinearVelocity = Vector2.Zero;
            }
        }
コード例 #11
0
        void UpdateSwimming()
        {
            IgnorePlatforms = true;

            Vector2 footPos, handPos;

            float surfaceLimiter = 1.0f;

            Limb head  = GetLimb(LimbType.Head);
            Limb torso = GetLimb(LimbType.Torso);

            if (currentHull != null && (currentHull.Rect.Y - currentHull.Surface > 50.0f))
            {
                surfaceLimiter = (ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 0.4f) - surfaceY);
                surfaceLimiter = Math.Max(1.0f, surfaceLimiter);
                if (surfaceLimiter > 50.0f)
                {
                    return;
                }
            }

            Limb leftHand  = GetLimb(LimbType.LeftHand);
            Limb rightHand = GetLimb(LimbType.RightHand);

            Limb leftFoot  = GetLimb(LimbType.LeftFoot);
            Limb rightFoot = GetLimb(LimbType.RightFoot);

            float rotation = MathHelper.WrapAngle(Collider.Rotation);

            rotation = MathHelper.ToDegrees(rotation);
            if (rotation < 0.0f)
            {
                rotation += 360;
            }

            if (!character.IsRemotePlayer && !aiming && Anim != Animation.UsingConstruction)
            {
                if (rotation > 20 && rotation < 170)
                {
                    TargetDir = Direction.Left;
                }
                else if (rotation > 190 && rotation < 340)
                {
                    TargetDir = Direction.Right;
                }
            }

            float targetSpeed = TargetMovement.Length();

            if (targetSpeed > 0.1f)
            {
                if (!aiming)
                {
                    float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
                    Collider.SmoothRotate(newRotation, 5.0f);
                    //torso.body.SmoothRotate(newRotation);
                }
            }
            else
            {
                if (aiming)
                {
                    Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
                    Vector2 diff     = (mousePos - torso.SimPosition) * Dir;

                    TargetMovement = new Vector2(0.0f, -0.1f);

                    float newRotation = MathUtils.VectorToAngle(diff);
                    Collider.SmoothRotate(newRotation, 5.0f);
                }
            }

            torso.body.SmoothRotate(Collider.Rotation);
            torso.body.MoveToPos(Collider.SimPosition + new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f, 5.0f);

            if (TargetMovement == Vector2.Zero)
            {
                return;
            }

            movement = MathUtils.SmoothStep(movement, TargetMovement, 0.3f);

            //dont try to move upwards if head is already out of water
            if (surfaceLimiter > 1.0f && TargetMovement.Y > 0.0f)
            {
                if (TargetMovement.X == 0.0f)
                {
                    //pull head above water
                    head.body.SmoothRotate(0.0f, 5.0f);

                    walkPos += 0.05f;
                }
                else
                {
                    TargetMovement = new Vector2(
                        (float)Math.Sqrt(targetSpeed * targetSpeed - TargetMovement.Y * TargetMovement.Y)
                        * Math.Sign(TargetMovement.X),
                        Math.Max(TargetMovement.Y, TargetMovement.Y * 0.2f));

                    //turn head above the water
                    head.body.ApplyTorque(Dir);
                }

                movement.Y = movement.Y - (surfaceLimiter - 1.0f) * 0.01f;
            }

            if (!character.IsRemotePlayer || GameMain.Server != null)
            {
                Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement * swimSpeed, movementLerp);
            }

            walkPos += movement.Length() * 0.2f;
            footPos  = Collider.SimPosition - new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f;

            for (int i = -1; i < 2; i += 2)
            {
                var thigh = i == -1 ? GetLimb(LimbType.LeftThigh) : GetLimb(LimbType.RightThigh);
                var leg   = i == -1 ? GetLimb(LimbType.LeftLeg) : GetLimb(LimbType.RightLeg);

                float thighDiff = Math.Abs(MathUtils.GetShortestAngle(torso.Rotation, thigh.Rotation));
                if (thighDiff > MathHelper.PiOver2)
                {
                    //thigh bent too close to the torso -> force the leg to extend
                    float thighTorque = thighDiff * thigh.Mass * Math.Sign(torso.Rotation - thigh.Rotation) * 10.0f;
                    thigh.body.ApplyTorque(thighTorque);
                    leg.body.ApplyTorque(thighTorque);
                }
                else
                {
                    thigh.body.SmoothRotate(torso.Rotation + (float)Math.Sin(walkPos) * i * 0.3f, 2.0f);
                }
            }

            Vector2 transformedFootPos = new Vector2((float)Math.Sin(walkPos) * 0.5f, 0.0f);

            transformedFootPos = Vector2.Transform(
                transformedFootPos,
                Matrix.CreateRotationZ(Collider.Rotation));

            MoveLimb(rightFoot, footPos - transformedFootPos, 1.0f);
            MoveLimb(leftFoot, footPos + transformedFootPos, 1.0f);

            handPos = (torso.SimPosition + head.SimPosition) / 2.0f;

            //at the surface, not moving sideways -> hands just float around
            if (!headInWater && TargetMovement.X == 0.0f && TargetMovement.Y > 0)
            {
                handPos.X = handPos.X + Dir * 0.6f;

                float wobbleAmount = 0.1f;

                if (!rightHand.Disabled)
                {
                    MoveLimb(rightHand, new Vector2(
                                 handPos.X + (float)Math.Sin(walkPos / 1.5f) * wobbleAmount,
                                 handPos.Y + (float)Math.Sin(walkPos / 3.5f) * wobbleAmount - 0.25f), 1.5f);
                }

                if (!leftHand.Disabled)
                {
                    MoveLimb(leftHand, new Vector2(
                                 handPos.X + (float)Math.Sin(walkPos / 2.0f) * wobbleAmount,
                                 handPos.Y + (float)Math.Sin(walkPos / 3.0f) * wobbleAmount - 0.25f), 1.5f);
                }

                return;
            }

            handPos += head.LinearVelocity * 0.1f;

            float handCyclePos = walkPos / 2.0f * -Dir;
            float handPosX     = (float)Math.Cos(handCyclePos) * 0.4f;
            float handPosY     = (float)Math.Sin(handCyclePos) * 1.0f;

            handPosY = MathHelper.Clamp(handPosY, -0.8f, 0.8f);

            Matrix rotationMatrix = Matrix.CreateRotationZ(torso.Rotation);

            if (!rightHand.Disabled)
            {
                Vector2 rightHandPos = new Vector2(-handPosX, -handPosY);
                rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
                rightHandPos   = Vector2.Transform(rightHandPos, rotationMatrix);

                HandIK(rightHand, handPos + rightHandPos, 0.5f);
            }

            if (!leftHand.Disabled)
            {
                Vector2 leftHandPos = new Vector2(handPosX, handPosY);
                leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X);
                leftHandPos   = Vector2.Transform(leftHandPos, rotationMatrix);

                HandIK(leftHand, handPos + leftHandPos, 0.5f);
            }
        }