I'm guessing this one comes from the player's position not being updated immediately after the input is processed, so that's where most of the remaining error came from. Also added some rounding to the horizontal velocity when approaching 0, and changed something that depended on the head limb to use the collider instead, which should hopefully further reduce the chance of syncing errors.
1170 lines
44 KiB
C#
1170 lines
44 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
using FarseerPhysics;
|
|
using Microsoft.Xna.Framework;
|
|
using Barotrauma.Items.Components;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class HumanoidAnimController : AnimController
|
|
{
|
|
public bool Crouching;
|
|
|
|
private bool aiming;
|
|
|
|
private float walkAnimSpeed;
|
|
|
|
private float movementLerp;
|
|
|
|
private float thighTorque;
|
|
|
|
private float cprAnimState;
|
|
|
|
private float inWaterTimer;
|
|
private bool swimming;
|
|
|
|
protected override float TorsoPosition
|
|
{
|
|
get
|
|
{
|
|
return Crouching ? base.TorsoPosition - base.HeadPosition * 0.3f : base.TorsoPosition;
|
|
}
|
|
}
|
|
|
|
protected override float TorsoAngle
|
|
{
|
|
get
|
|
{
|
|
return Crouching ? base.TorsoAngle + 0.5f : base.TorsoAngle;
|
|
}
|
|
}
|
|
|
|
public HumanoidAnimController(Character character, XElement element)
|
|
: base(character, element)
|
|
{
|
|
walkAnimSpeed = ToolBox.GetAttributeFloat(element, "walkanimspeed", 4.0f);
|
|
walkAnimSpeed = MathHelper.ToRadians(walkAnimSpeed);
|
|
|
|
movementLerp = ToolBox.GetAttributeFloat(element, "movementlerp", 0.4f);
|
|
|
|
thighTorque = ToolBox.GetAttributeFloat(element, "thightorque", -5.0f);
|
|
}
|
|
|
|
public override void UpdateAnim(float deltaTime)
|
|
{
|
|
if (Frozen) return;
|
|
|
|
levitatingCollider = true;
|
|
ColliderIndex = Crouching ? 1 : 0;
|
|
if (!Crouching && ColliderIndex == 1) Crouching = true;
|
|
|
|
if (!character.AllowMovement)
|
|
{
|
|
levitatingCollider = false;
|
|
Collider.FarseerBody.FixedRotation = false;
|
|
|
|
/*if (character.IsRemotePlayer)
|
|
{
|
|
MainLimb.pullJoint.WorldAnchorB = Collider.SimPosition;
|
|
MainLimb.pullJoint.Enabled = true;
|
|
}
|
|
else
|
|
{*/
|
|
Collider.LinearVelocity = (GetLimb(LimbType.Waist).SimPosition - Collider.SimPosition) * 20.0f;
|
|
Collider.SmoothRotate(GetLimb(LimbType.Torso).Rotation);
|
|
//}
|
|
|
|
if (stunTimer > 0)
|
|
{
|
|
stunTimer -= deltaTime;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//stun (= disable the animations) if the ragdoll receives a large enough impact
|
|
if (strongestImpact > 0.0f)
|
|
{
|
|
character.StartStun(MathHelper.Min(strongestImpact * 0.5f, 5.0f));
|
|
strongestImpact = 0.0f;
|
|
return;
|
|
}
|
|
|
|
|
|
if (!character.IsRemotePlayer || true)
|
|
{
|
|
//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.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;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Collider.FarseerBody.Enabled = false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
void UpdateStanding()
|
|
{
|
|
Vector2 handPos;
|
|
|
|
//if you're allergic to magic numbers, stop reading now
|
|
|
|
Limb leftFoot = GetLimb(LimbType.LeftFoot);
|
|
Limb rightFoot = GetLimb(LimbType.RightFoot);
|
|
Limb head = GetLimb(LimbType.Head);
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
|
|
Limb waist = GetLimb(LimbType.Waist);
|
|
|
|
Limb leftHand = GetLimb(LimbType.LeftHand);
|
|
Limb rightHand = GetLimb(LimbType.RightHand);
|
|
|
|
Limb leftLeg = GetLimb(LimbType.LeftLeg);
|
|
Limb rightLeg = GetLimb(LimbType.RightLeg);
|
|
|
|
float getUpSpeed = 0.3f;
|
|
float walkCycleSpeed = movement.X * walkAnimSpeed;
|
|
if (stairs != null)
|
|
{
|
|
TargetMovement = new Vector2(MathHelper.Clamp(TargetMovement.X, -1.5f, 1.5f), TargetMovement.Y);
|
|
|
|
/*if ((TargetMovement.X > 0.0f && stairs.StairDirection == Direction.Right) ||
|
|
TargetMovement.X < 0.0f && stairs.StairDirection == Direction.Left)
|
|
{
|
|
TargetMovement *= 1.7f;
|
|
//walkCycleSpeed *= 1.0f;
|
|
}*/
|
|
}
|
|
|
|
Vector2 colliderPos = GetColliderBottom();
|
|
if (Math.Abs(TargetMovement.X) > 1.0f)
|
|
{
|
|
float slowdownAmount = 0.0f;
|
|
if (currentHull != null)
|
|
{
|
|
//full slowdown (1.5f) when water is up to the torso
|
|
surfaceY = ConvertUnits.ToSimUnits(currentHull.Surface);
|
|
slowdownAmount = MathHelper.Clamp((surfaceY - colliderPos.Y) / torsoPosition, 0.0f, 1.0f) * 1.5f;
|
|
}
|
|
|
|
float maxSpeed = Math.Max(TargetMovement.Length() - slowdownAmount, 1.0f);
|
|
TargetMovement = Vector2.Normalize(TargetMovement) * maxSpeed;
|
|
}
|
|
|
|
float walkPosX = (float)Math.Cos(walkPos);
|
|
float walkPosY = (float)Math.Sin(walkPos);
|
|
float runningModifier = (float)Math.Max(Math.Min(Math.Abs(TargetMovement.X), 3.0f) / 1.5f, 1.0);
|
|
|
|
Vector2 stepSize = new Vector2(
|
|
this.stepSize.X * walkPosX * runningModifier,
|
|
this.stepSize.Y * walkPosY * runningModifier * runningModifier);
|
|
|
|
if (Crouching) stepSize *= 0.5f;
|
|
|
|
float footMid = colliderPos.X;// (leftFoot.SimPosition.X + rightFoot.SimPosition.X) / 2.0f;
|
|
|
|
movement = overrideTargetMovement == Vector2.Zero ?
|
|
MathUtils.SmoothStep(movement, TargetMovement * walkSpeed, movementLerp) :
|
|
overrideTargetMovement;
|
|
|
|
movement.Y = 0.0f;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Limb leg = GetLimb((i == 0) ? LimbType.LeftThigh : LimbType.RightThigh);// : leftLeg;
|
|
|
|
float shortestAngle = leg.Rotation - torso.Rotation;
|
|
|
|
if (Math.Abs(shortestAngle) < 2.5f) continue;
|
|
|
|
if (Math.Abs(shortestAngle) > 5.0f)
|
|
{
|
|
TargetDir = TargetDir == Direction.Right ? Direction.Left : Direction.Right;
|
|
}
|
|
else
|
|
{
|
|
|
|
leg.body.ApplyTorque(shortestAngle * 10.0f);
|
|
|
|
leg = GetLimb((i == 0) ? LimbType.LeftLeg : LimbType.RightLeg);
|
|
leg.body.ApplyTorque(-shortestAngle * 10.0f);
|
|
}
|
|
}
|
|
|
|
if (onGround && (!character.IsRemotePlayer || GameMain.Server != null))
|
|
{
|
|
//move slower if collider isn't upright
|
|
float rotationFactor = (float)Math.Abs(Math.Cos(Collider.Rotation));
|
|
|
|
Collider.LinearVelocity = new Vector2(
|
|
movement.X * rotationFactor,
|
|
Collider.LinearVelocity.Y > 0.0f ? Collider.LinearVelocity.Y * 0.5f : Collider.LinearVelocity.Y);
|
|
}
|
|
|
|
getUpSpeed = getUpSpeed * Math.Max(head.SimPosition.Y - colliderPos.Y, 0.5f);
|
|
|
|
torso.pullJoint.Enabled = true;
|
|
head.pullJoint.Enabled = true;
|
|
waist.pullJoint.Enabled = true;
|
|
|
|
if (stairs != null)
|
|
{
|
|
torso.pullJoint.WorldAnchorB = new Vector2(
|
|
MathHelper.SmoothStep(torso.SimPosition.X, footMid + movement.X * 0.25f, getUpSpeed * 0.8f),
|
|
MathHelper.SmoothStep(torso.SimPosition.Y, colliderPos.Y + TorsoPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 2.0f));
|
|
|
|
|
|
head.pullJoint.WorldAnchorB = new Vector2(
|
|
MathHelper.SmoothStep(head.SimPosition.X, footMid + movement.X * (Crouching ? 0.6f : 0.25f), getUpSpeed * 0.8f),
|
|
MathHelper.SmoothStep(head.SimPosition.Y, colliderPos.Y + HeadPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 2.0f));
|
|
|
|
waist.pullJoint.WorldAnchorB = waist.SimPosition;// +movement * 0.3f;
|
|
}
|
|
else
|
|
{
|
|
if (!onGround) movement = Vector2.Zero;
|
|
|
|
torso.pullJoint.WorldAnchorB =
|
|
MathUtils.SmoothStep(torso.SimPosition,
|
|
new Vector2(footMid + movement.X * 0.2f, colliderPos.Y + TorsoPosition), getUpSpeed);
|
|
|
|
head.pullJoint.WorldAnchorB =
|
|
MathUtils.SmoothStep(head.SimPosition,
|
|
new Vector2(footMid + movement.X * (Crouching && Math.Sign(movement.X) == Math.Sign(Dir) ? 0.6f : 0.2f), colliderPos.Y + HeadPosition), getUpSpeed * 1.2f);
|
|
|
|
waist.pullJoint.WorldAnchorB = waist.SimPosition + movement * 0.06f;
|
|
}
|
|
|
|
if (!onGround)
|
|
{
|
|
Vector2 move = torso.pullJoint.WorldAnchorB - torso.SimPosition;
|
|
|
|
foreach (Limb limb in Limbs)
|
|
{
|
|
MoveLimb(limb, limb.SimPosition+move, 15.0f, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//moving horizontally
|
|
if (TargetMovement.X != 0.0f)
|
|
{
|
|
//progress the walking animation
|
|
walkPos -= (walkCycleSpeed / runningModifier) * 0.8f;
|
|
|
|
MoveLimb(leftFoot,
|
|
colliderPos + new Vector2(
|
|
stepSize.X,
|
|
(stepSize.Y > 0.0f) ? stepSize.Y : -0.15f),
|
|
15.0f, true);
|
|
|
|
MoveLimb(rightFoot,
|
|
colliderPos + new Vector2(
|
|
-stepSize.X,
|
|
(-stepSize.Y > 0.0f) ? -stepSize.Y : -0.15f),
|
|
15.0f, true);
|
|
|
|
leftFoot.body.SmoothRotate(leftLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier);
|
|
rightFoot.body.SmoothRotate(rightLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier);
|
|
|
|
if (runningModifier > 1.0f)
|
|
{
|
|
if (walkPosY > 0.0f)
|
|
{
|
|
GetLimb(LimbType.LeftThigh).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * thighTorque);
|
|
}
|
|
else
|
|
{
|
|
GetLimb(LimbType.RightThigh).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * thighTorque);
|
|
}
|
|
}
|
|
|
|
if (legTorque > 0.0f)
|
|
{
|
|
if (Math.Sign(walkPosX) != Math.Sign(movement.X))
|
|
{
|
|
GetLimb(LimbType.LeftLeg).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier);
|
|
}
|
|
else
|
|
{
|
|
GetLimb(LimbType.RightLeg).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier);
|
|
}
|
|
}
|
|
|
|
//calculate the positions of hands
|
|
handPos = torso.SimPosition;
|
|
handPos.X = -walkPosX * 0.4f;
|
|
|
|
float lowerY = -1.0f + (runningModifier - 1.0f) * 0.8f;
|
|
|
|
handPos.Y = lowerY + (float)(Math.Abs(Math.Sin(walkPos - Math.PI * 1.5f) * 0.15 * runningModifier));
|
|
|
|
Vector2 posAddition = new Vector2(-movement.X * 0.015f * runningModifier, 0.0f);
|
|
|
|
if (!rightHand.Disabled)
|
|
{
|
|
HandIK(rightHand, torso.SimPosition + posAddition +
|
|
new Vector2(
|
|
-handPos.X,
|
|
(Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), 0.7f * runningModifier);
|
|
}
|
|
|
|
if (!leftHand.Disabled)
|
|
{
|
|
HandIK(leftHand, torso.SimPosition + posAddition +
|
|
new Vector2(
|
|
handPos.X,
|
|
(Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), 0.7f * runningModifier);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//float movementFactor = (movement.X / 4.0f) * movement.X * Math.Sign(movement.X);
|
|
|
|
for (int i = -1; i < 2; i += 2)
|
|
{
|
|
Vector2 footPos = colliderPos;
|
|
|
|
if (Crouching)
|
|
{
|
|
footPos = new Vector2(
|
|
waist.SimPosition.X + Math.Sign(stepSize.X * i) * Dir * 0.3f,
|
|
colliderPos.Y - 0.1f);
|
|
}
|
|
else
|
|
{
|
|
footPos = new Vector2(GetCenterOfMass().X + stepSize.X * i * 0.2f, colliderPos.Y - 0.1f);
|
|
}
|
|
|
|
|
|
var foot = i == -1 ? rightFoot : leftFoot;
|
|
|
|
MoveLimb(foot, footPos, Math.Abs(foot.SimPosition.X - footPos.X) * 100.0f, true);
|
|
}
|
|
|
|
leftFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 50.0f);
|
|
rightFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 50.0f);
|
|
|
|
if (!rightHand.Disabled)
|
|
{
|
|
rightHand.body.SmoothRotate(0.0f, 5.0f);
|
|
|
|
var rightArm = GetLimb(LimbType.RightArm);
|
|
rightArm.body.SmoothRotate(0.0f, 20.0f);
|
|
}
|
|
|
|
if (!leftHand.Disabled)
|
|
{
|
|
leftHand.body.SmoothRotate(0.0f, 5.0f);
|
|
|
|
var leftArm = GetLimb(LimbType.LeftArm);
|
|
leftArm.body.SmoothRotate(0.0f, 20.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateStandingSimple()
|
|
{
|
|
movement = MathUtils.SmoothStep(movement, TargetMovement, movementLerp);
|
|
|
|
if (inWater && movement.LengthSquared() > 0.00001f)
|
|
{
|
|
movement = Vector2.Normalize(movement);
|
|
}
|
|
if (Math.Abs(movement.X)<0.005f)
|
|
{
|
|
movement.X = 0.0f;
|
|
}
|
|
}
|
|
|
|
private void ClimbOverObstacles()
|
|
{
|
|
if (Collider.FarseerBody.ContactList == null || Math.Abs(movement.X) < 0.01f) return;
|
|
|
|
//check if the collider is touching a suitable obstacle to climb over
|
|
Vector2? handle = null;
|
|
FarseerPhysics.Dynamics.Contacts.ContactEdge ce = Collider.FarseerBody.ContactList;
|
|
while (ce != null && ce.Contact != null)
|
|
{
|
|
if (ce.Contact.Enabled && ce.Contact.IsTouching && ce.Contact.FixtureA.CollisionCategories.HasFlag(Physics.CollisionWall))
|
|
{
|
|
Vector2 contactNormal;
|
|
FarseerPhysics.Common.FixedArray2<Vector2> contactPos;
|
|
ce.Contact.GetWorldManifold(out contactNormal, out contactPos);
|
|
|
|
//only climb if moving towards the obstacle
|
|
if (Math.Sign(contactPos[0].X - Collider.SimPosition.X) == Math.Sign(movement.X) &&
|
|
(handle == null || contactPos[0].Y > ((Vector2)handle).Y))
|
|
{
|
|
handle = contactPos[0];
|
|
}
|
|
}
|
|
|
|
ce = ce.Next;
|
|
}
|
|
|
|
if (handle == null) return;
|
|
|
|
float colliderBottomY = GetColliderBottom().Y;
|
|
|
|
//the contact point should be higher than the bottom of the collider
|
|
if (((Vector2)handle).Y < colliderBottomY + 0.01f ||
|
|
((Vector2)handle).Y > Collider.SimPosition.Y) return;
|
|
|
|
//find the height of the floor below the torso
|
|
//(if moving towards towards an obstacle that's low enough to climb over, the torso should be above it)
|
|
float obstacleY = GetFloorY(GetLimb(LimbType.Torso));
|
|
|
|
if (obstacleY > colliderBottomY)
|
|
{
|
|
//higher vertical velocity for taller obstacles
|
|
Collider.LinearVelocity += Vector2.UnitY * (((Vector2)handle).Y - colliderBottomY + 0.01f) * 50;
|
|
onGround = true;
|
|
}
|
|
}
|
|
|
|
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.0f) TargetMovement /= targetSpeed;
|
|
|
|
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.15f;
|
|
footPos = Collider.SimPosition - new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f;
|
|
|
|
var rightThigh = GetLimb(LimbType.RightThigh);
|
|
var leftThigh = GetLimb(LimbType.LeftThigh);
|
|
|
|
rightThigh.body.SmoothRotate(torso.Rotation + (float)Math.Sin(walkPos) * 0.3f, 2.0f);
|
|
leftThigh.body.SmoothRotate(torso.Rotation - (float)Math.Sin(walkPos) * 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 / 3.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);
|
|
}
|
|
}
|
|
|
|
void UpdateClimbing()
|
|
{
|
|
if (character.SelectedConstruction == null || character.SelectedConstruction.GetComponent<Ladder>() == null)
|
|
{
|
|
Anim = Animation.None;
|
|
return;
|
|
}
|
|
|
|
onGround = false;
|
|
IgnorePlatforms = true;
|
|
|
|
Vector2 tempTargetMovement = TargetMovement;
|
|
|
|
tempTargetMovement.Y = Math.Min(tempTargetMovement.Y, 1.0f);
|
|
|
|
movement = MathUtils.SmoothStep(movement, tempTargetMovement, 0.3f);
|
|
|
|
Limb leftFoot = GetLimb(LimbType.LeftFoot);
|
|
Limb rightFoot = GetLimb(LimbType.RightFoot);
|
|
Limb head = GetLimb(LimbType.Head);
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
|
|
Limb waist = GetLimb(LimbType.Waist);
|
|
|
|
Limb leftHand = GetLimb(LimbType.LeftHand);
|
|
Limb rightHand = GetLimb(LimbType.RightHand);
|
|
|
|
Vector2 ladderSimPos = ConvertUnits.ToSimUnits(
|
|
character.SelectedConstruction.Rect.X + character.SelectedConstruction.Rect.Width / 2.0f,
|
|
character.SelectedConstruction.Rect.Y);
|
|
|
|
float stepHeight = ConvertUnits.ToSimUnits(30.0f);
|
|
|
|
if (currentHull == null && character.SelectedConstruction.Submarine != null)
|
|
{
|
|
ladderSimPos += character.SelectedConstruction.Submarine.SimPosition;
|
|
}
|
|
else if (currentHull.Submarine != null && currentHull.Submarine != character.SelectedConstruction.Submarine)
|
|
{
|
|
ladderSimPos += character.SelectedConstruction.Submarine.SimPosition - currentHull.Submarine.SimPosition;
|
|
}
|
|
|
|
MoveLimb(head, new Vector2(ladderSimPos.X - 0.27f * Dir, Collider.SimPosition.Y + 0.9f - colliderHeightFromFloor), 10.5f);
|
|
MoveLimb(torso, new Vector2(ladderSimPos.X - 0.27f * Dir, Collider.SimPosition.Y + 0.7f - colliderHeightFromFloor), 10.5f);
|
|
MoveLimb(waist, new Vector2(ladderSimPos.X - 0.35f * Dir, Collider.SimPosition.Y + 0.6f - colliderHeightFromFloor), 10.5f);
|
|
|
|
Collider.MoveToPos(new Vector2(ladderSimPos.X - 0.2f * Dir, Collider.SimPosition.Y), 10.5f);
|
|
|
|
bool slide = targetMovement.Y < -1.1f;
|
|
|
|
Vector2 handPos = new Vector2(
|
|
ladderSimPos.X,
|
|
Collider.SimPosition.Y + 0.8f + movement.Y * 0.1f - ladderSimPos.Y);
|
|
|
|
handPos.Y = Math.Min(-0.2f, handPos.Y) - colliderHeightFromFloor;
|
|
|
|
MoveLimb(leftHand,
|
|
new Vector2(handPos.X,
|
|
(slide ? handPos.Y : MathUtils.Round(handPos.Y - stepHeight, stepHeight * 2.0f) + stepHeight) + ladderSimPos.Y),
|
|
5.2f);
|
|
|
|
MoveLimb(rightHand,
|
|
new Vector2(handPos.X,
|
|
(slide ? handPos.Y : MathUtils.Round(handPos.Y, stepHeight * 2.0f)) + ladderSimPos.Y),
|
|
5.2f);
|
|
|
|
leftHand.body.ApplyTorque(Dir * 2.0f);
|
|
rightHand.body.ApplyTorque(Dir * 2.0f);
|
|
|
|
Vector2 footPos = new Vector2(
|
|
handPos.X - Dir * 0.05f,
|
|
Collider.SimPosition.Y + 0.9f - colliderHeightFromFloor - stepHeight * 2.7f - ladderSimPos.Y - 0.7f);
|
|
|
|
//if (movement.Y < 0) footPos.Y += 0.05f;
|
|
|
|
MoveLimb(leftFoot,
|
|
new Vector2(footPos.X,
|
|
(slide ? footPos.Y : MathUtils.Round(footPos.Y + stepHeight, stepHeight * 2.0f) - stepHeight) + ladderSimPos.Y),
|
|
15.5f, true);
|
|
|
|
MoveLimb(rightFoot,
|
|
new Vector2(footPos.X,
|
|
(slide ? footPos.Y : MathUtils.Round(footPos.Y, stepHeight * 2.0f)) + ladderSimPos.Y),
|
|
15.5f, true);
|
|
|
|
//apply torque to the legs to make the knees bend
|
|
Limb leftLeg = GetLimb(LimbType.LeftLeg);
|
|
Limb rightLeg = GetLimb(LimbType.RightLeg);
|
|
|
|
leftLeg.body.ApplyTorque(Dir * -8.0f);
|
|
rightLeg.body.ApplyTorque(Dir * -8.0f);
|
|
|
|
float movementFactor = (handPos.Y / stepHeight) * (float)Math.PI;
|
|
movementFactor = 0.8f + (float)Math.Abs(Math.Sin(movementFactor));
|
|
|
|
Vector2 subSpeed = currentHull != null || character.SelectedConstruction.Submarine == null
|
|
? Vector2.Zero : character.SelectedConstruction.Submarine.Velocity;
|
|
|
|
Vector2 climbForce = new Vector2(0.0f, movement.Y + 0.3f) * movementFactor;
|
|
//if (climbForce.Y > 0.5f) climbForce.Y = Math.Max(climbForce.Y, 1.3f);
|
|
|
|
//apply forces to the collider to move the Character up/down
|
|
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
|
head.body.SmoothRotate(0.0f);
|
|
|
|
if (!character.SelectedConstruction.Prefab.Triggers.Any())
|
|
{
|
|
character.SelectedConstruction = null;
|
|
return;
|
|
}
|
|
|
|
Rectangle trigger = character.SelectedConstruction.Prefab.Triggers.FirstOrDefault();
|
|
trigger = character.SelectedConstruction.TransformTrigger(trigger);
|
|
|
|
bool notClimbing = false;
|
|
if (character.IsRemotePlayer)
|
|
{
|
|
notClimbing = character.IsKeyDown(InputType.Left) || character.IsKeyDown(InputType.Right);
|
|
}
|
|
else
|
|
{
|
|
notClimbing = Math.Abs(targetMovement.X) > 0.05f ||
|
|
(TargetMovement.Y < 0.0f && ConvertUnits.ToSimUnits(trigger.Height) + handPos.Y < HeadPosition) ||
|
|
(TargetMovement.Y > 0.0f && handPos.Y > 0.1f);
|
|
}
|
|
|
|
if (notClimbing)
|
|
{
|
|
Anim = Animation.None;
|
|
character.SelectedConstruction = null;
|
|
IgnorePlatforms = false;
|
|
}
|
|
|
|
}
|
|
|
|
private void UpdateCPR(float deltaTime)
|
|
{
|
|
if (character.SelectedCharacter == null)
|
|
{
|
|
Anim = Animation.None;
|
|
return;
|
|
}
|
|
|
|
Crouching = true;
|
|
|
|
Vector2 diff = character.SelectedCharacter.SimPosition - character.SimPosition;
|
|
var targetHead = character.SelectedCharacter.AnimController.GetLimb(LimbType.Head);
|
|
|
|
Vector2 headDiff = targetHead == null ? diff : targetHead.SimPosition - character.SimPosition;
|
|
|
|
targetMovement = new Vector2(diff.X, 0.0f);
|
|
TargetDir = headDiff.X > 0.0f ? Direction.Right : Direction.Left;
|
|
|
|
UpdateStanding();
|
|
|
|
Vector2 handPos = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso).SimPosition + Vector2.UnitY * 0.2f;
|
|
|
|
Grab(handPos, handPos);
|
|
|
|
float yPos = (float)Math.Sin(cprAnimState) * 0.1f;
|
|
cprAnimState += deltaTime * 8.0f;
|
|
|
|
var head = GetLimb(LimbType.Head);
|
|
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.6f + yPos);
|
|
head.pullJoint.Enabled = true;
|
|
}
|
|
public override void DragCharacter(Character target, LimbType rightHandTarget = LimbType.RightHand, LimbType leftHandTarget = LimbType.LeftHand)
|
|
{
|
|
if (target == null) return;
|
|
|
|
Limb leftHand = GetLimb(LimbType.LeftHand);
|
|
Limb rightHand = GetLimb(LimbType.RightHand);
|
|
|
|
//only grab with one hand when swimming
|
|
leftHand.Disabled = true;
|
|
if (!inWater) rightHand.Disabled = true;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
LimbType type = i == 0 ? leftHandTarget : rightHandTarget;
|
|
Limb targetLimb = target.AnimController.GetLimb(type);
|
|
|
|
Limb pullLimb = GetLimb(i == 0 ? LimbType.LeftHand : LimbType.RightHand);
|
|
|
|
if (i == 1 && inWater)
|
|
{
|
|
targetLimb.pullJoint.Enabled = false;
|
|
}
|
|
else
|
|
{
|
|
Vector2 diff = ConvertUnits.ToSimUnits(targetLimb.WorldPosition - pullLimb.WorldPosition);
|
|
|
|
pullLimb.pullJoint.Enabled = true;
|
|
pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff;
|
|
pullLimb.pullJoint.MaxForce = 10000.0f;
|
|
|
|
targetLimb.pullJoint.Enabled = true;
|
|
targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff;
|
|
targetLimb.pullJoint.MaxForce = 10000.0f;
|
|
|
|
target.AnimController.movement -= diff;
|
|
}
|
|
}
|
|
|
|
float dist = Vector2.Distance(target.SimPosition, Collider.SimPosition);
|
|
|
|
//limit movement if moving away from the target
|
|
if (Vector2.Dot(target.SimPosition - Collider.SimPosition, targetMovement)<0)
|
|
{
|
|
targetMovement *= MathHelper.Clamp(2.0f - dist, 0.0f, 1.0f);
|
|
}
|
|
|
|
target.AnimController.IgnorePlatforms = IgnorePlatforms;
|
|
|
|
if (!target.AllowMovement)
|
|
{
|
|
target.AnimController.TargetMovement = TargetMovement;
|
|
}
|
|
else if (target is AICharacter)
|
|
{
|
|
target.AnimController.TargetMovement = Vector2.Lerp(
|
|
target.AnimController.TargetMovement,
|
|
(character.SimPosition + Vector2.UnitX * Dir) - target.SimPosition, 0.5f);
|
|
}
|
|
}
|
|
|
|
public void Grab(Vector2 rightHandPos, Vector2 leftHandPos)
|
|
{
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Limb pullLimb = (i == 0) ? GetLimb(LimbType.LeftHand) : GetLimb(LimbType.RightHand);
|
|
|
|
pullLimb.Disabled = true;
|
|
|
|
pullLimb.pullJoint.Enabled = true;
|
|
pullLimb.pullJoint.WorldAnchorB = (i == 0) ? rightHandPos : leftHandPos;
|
|
pullLimb.pullJoint.MaxForce = 500.0f;
|
|
}
|
|
|
|
}
|
|
|
|
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle)
|
|
{
|
|
Holdable holdable = item.GetComponent<Holdable>();
|
|
|
|
if (character.IsUnconscious || character.Stun > 0.0f) aim = false;
|
|
|
|
//calculate the handle positions
|
|
Matrix itemTransfrom = Matrix.CreateRotationZ(item.body.Rotation);
|
|
Vector2[] transformedHandlePos = new Vector2[2];
|
|
transformedHandlePos[0] = Vector2.Transform(handlePos[0], itemTransfrom);
|
|
transformedHandlePos[1] = Vector2.Transform(handlePos[1], itemTransfrom);
|
|
|
|
Limb head = GetLimb(LimbType.Head);
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
Limb leftHand = GetLimb(LimbType.LeftHand);
|
|
Limb rightHand = GetLimb(LimbType.RightHand);
|
|
|
|
Vector2 itemPos = aim ? aimPos : holdPos;
|
|
|
|
bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent<Controller>() != null;
|
|
|
|
|
|
float itemAngle;
|
|
if (Anim != Animation.Climbing && !usingController && stunTimer <= 0.0f && aim && itemPos != Vector2.Zero)
|
|
{
|
|
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
|
|
|
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
|
|
|
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * Dir;
|
|
|
|
itemAngle = (torso.body.Rotation + holdAngle * Dir);
|
|
|
|
if (holdable.ControlPose)
|
|
{
|
|
head.body.SmoothRotate(itemAngle);
|
|
|
|
if (TargetMovement == Vector2.Zero && inWater)
|
|
{
|
|
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
|
|
torso.body.ApplyForce(torso.body.LinearVelocity * -0.5f);
|
|
}
|
|
|
|
aiming = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
itemAngle = (torso.body.Rotation + holdAngle * Dir);
|
|
}
|
|
|
|
Vector2 shoulderPos = limbJoints[2].WorldAnchorA;
|
|
Vector2 transformedHoldPos = shoulderPos;
|
|
|
|
if (itemPos == Vector2.Zero || Anim == Animation.Climbing || usingController)
|
|
{
|
|
if (character.SelectedItems[1] == item)
|
|
{
|
|
transformedHoldPos = leftHand.pullJoint.WorldAnchorA - transformedHandlePos[1];
|
|
itemAngle = (leftHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
|
|
}
|
|
if (character.SelectedItems[0] == item)
|
|
{
|
|
transformedHoldPos = rightHand.pullJoint.WorldAnchorA - transformedHandlePos[0];
|
|
itemAngle = (rightHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (character.SelectedItems[0] == item)
|
|
{
|
|
rightHand.Disabled = true;
|
|
}
|
|
if (character.SelectedItems[1] == item)
|
|
{
|
|
leftHand.Disabled = true;
|
|
}
|
|
|
|
|
|
itemPos.X = itemPos.X * Dir;
|
|
|
|
Matrix torsoTransform = Matrix.CreateRotationZ(itemAngle);
|
|
|
|
transformedHoldPos += Vector2.Transform(itemPos, torsoTransform);
|
|
}
|
|
|
|
item.body.ResetDynamics();
|
|
|
|
Vector2 currItemPos = (character.SelectedItems[0] == item) ?
|
|
rightHand.pullJoint.WorldAnchorA - transformedHandlePos[0] :
|
|
leftHand.pullJoint.WorldAnchorA - transformedHandlePos[1];
|
|
item.SetTransform(currItemPos, itemAngle);
|
|
|
|
//item.SetTransform(MathUtils.SmoothStep(item.body.SimPosition, transformedHoldPos + bodyVelocity, 0.5f), itemAngle);
|
|
|
|
if (Anim == Animation.Climbing) return;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
if (character.SelectedItems[i] != item) continue;
|
|
if (itemPos == Vector2.Zero) continue;
|
|
|
|
Limb hand = (i == 0) ? rightHand : leftHand;
|
|
|
|
HandIK(hand, transformedHoldPos + transformedHandlePos[i]);
|
|
}
|
|
}
|
|
|
|
private void HandIK(Limb hand, Vector2 pos, float force = 1.0f)
|
|
{
|
|
Vector2 shoulderPos = limbJoints[2].WorldAnchorA;
|
|
|
|
Limb arm = (hand.type == LimbType.LeftHand) ? GetLimb(LimbType.LeftArm) : GetLimb(LimbType.RightArm);
|
|
|
|
//hand length
|
|
float a = 37.0f;
|
|
|
|
//arm length
|
|
float b = 28.0f;
|
|
|
|
//distance from shoulder to holdpos
|
|
float c = ConvertUnits.ToDisplayUnits(Vector2.Distance(pos, shoulderPos));
|
|
c = MathHelper.Clamp(a + b - 1, b - a, c);
|
|
|
|
float ang2 = MathUtils.VectorToAngle(pos - shoulderPos) + MathHelper.PiOver2;
|
|
|
|
float armAngle = MathUtils.SolveTriangleSSS(a, b, c);
|
|
float handAngle = MathUtils.SolveTriangleSSS(b, a, c);
|
|
|
|
arm.body.SmoothRotate((ang2 - armAngle * Dir), 20.0f * force);
|
|
hand.body.SmoothRotate((ang2 + handAngle * Dir), 100.0f * force);
|
|
}
|
|
|
|
public override void Flip()
|
|
{
|
|
base.Flip();
|
|
|
|
walkPos = -walkPos;
|
|
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
|
|
Vector2 difference;
|
|
|
|
Matrix torsoTransform = Matrix.CreateRotationZ(torso.Rotation);
|
|
|
|
for (int i = 0; i < character.SelectedItems.Length; i++)
|
|
{
|
|
if (character.SelectedItems[i] != null)
|
|
{
|
|
difference = character.SelectedItems[i].body.SimPosition - torso.SimPosition;
|
|
difference = Vector2.Transform(difference, torsoTransform);
|
|
difference.Y = -difference.Y;
|
|
|
|
character.SelectedItems[i].body.SetTransform(
|
|
torso.SimPosition + Vector2.Transform(difference, -torsoTransform),
|
|
MathUtils.WrapAngleTwoPi(-character.SelectedItems[i].body.Rotation));
|
|
}
|
|
}
|
|
|
|
foreach (Limb limb in Limbs)
|
|
{
|
|
bool mirror = false;
|
|
bool flipAngle = false;
|
|
bool wrapAngle = false;
|
|
|
|
switch (limb.type)
|
|
{
|
|
case LimbType.LeftHand:
|
|
case LimbType.LeftArm:
|
|
case LimbType.RightHand:
|
|
case LimbType.RightArm:
|
|
mirror = true;
|
|
flipAngle = true;
|
|
break;
|
|
case LimbType.LeftThigh:
|
|
case LimbType.LeftLeg:
|
|
case LimbType.LeftFoot:
|
|
case LimbType.RightThigh:
|
|
case LimbType.RightLeg:
|
|
case LimbType.RightFoot:
|
|
mirror = Crouching && !inWater;
|
|
flipAngle = (limb.DoesFlip || Crouching) && !inWater;
|
|
wrapAngle = !inWater;
|
|
break;
|
|
default:
|
|
flipAngle = limb.DoesFlip && !inWater;
|
|
wrapAngle = !inWater;
|
|
break;
|
|
}
|
|
|
|
Vector2 position = limb.SimPosition;
|
|
|
|
if ((limb.pullJoint == null || !limb.pullJoint.Enabled) && mirror)
|
|
{
|
|
difference = limb.body.SimPosition - torso.SimPosition;
|
|
difference = Vector2.Transform(difference, torsoTransform);
|
|
difference.Y = -difference.Y;
|
|
|
|
position = torso.SimPosition + Vector2.Transform(difference, -torsoTransform);
|
|
|
|
//TrySetLimbPosition(limb, limb.SimPosition, );
|
|
}
|
|
|
|
float angle = flipAngle ? -limb.body.Rotation : limb.body.Rotation;
|
|
if (wrapAngle) angle = MathUtils.WrapAnglePi(angle);
|
|
|
|
TrySetLimbPosition(limb, Collider.SimPosition, position);
|
|
|
|
limb.body.SetTransform(limb.body.SimPosition, angle);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|