If the floor in front of the character is higher than where the character is standing, the character slows down and lifts its feet more. The position of the feet is also clamped below the waist, preventing the character from doing a backwards somersault when running over "fake stairs".
1193 lines
45 KiB
C#
1193 lines
45 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.IsDead || character.IsUnconscious || stunTimer > 0.0f)
|
|
{
|
|
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;
|
|
|
|
float floorPos = GetFloorY(colliderPos + new Vector2(Math.Sign(movement.X) * 0.5f, 1.0f));
|
|
bool onSlope = floorPos > GetColliderBottom().Y + 0.05f;
|
|
|
|
if (stairs != null || onSlope)
|
|
{
|
|
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;
|
|
|
|
for (int i = -1; i < 2; i += 2)
|
|
{
|
|
Limb foot = i == -1 ? leftFoot : rightFoot;
|
|
Limb leg = i == -1 ? leftLeg : rightLeg;
|
|
|
|
Vector2 footPos = stepSize * -i;
|
|
if (stepSize.Y > 0.0f) stepSize.Y = -0.15f;
|
|
|
|
if (onSlope && stairs == null)
|
|
{
|
|
footPos.Y *= 2.0f;
|
|
}
|
|
footPos.Y = Math.Min(waist.SimPosition.Y - colliderPos.Y - 0.4f, footPos.Y);
|
|
|
|
MoveLimb(foot, footPos + colliderPos, 15.0f, true);
|
|
foot.body.SmoothRotate(leg.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);
|
|
}
|
|
|
|
if (stairs == null)
|
|
{
|
|
footPos.Y = Math.Max(Math.Min(floorPos, footPos.Y + 0.5f), footPos.Y);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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 / 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);
|
|
|
|
if (!character.IsRemotePlayer)
|
|
{
|
|
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.Stun > 0.0f || target.IsUnconscious || target.IsDead)
|
|
{
|
|
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);
|
|
}
|
|
|
|
//if on stairs, make the dragged character "climb up" (= collide with stairs)
|
|
if (stairs != null) target.AnimController.TargetMovement = new Vector2 (target.AnimController.TargetMovement.X, 1.0f);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|