partial void UpdateProjSpecific(float deltaTime) { LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime)); foreach (var deformation in SpriteDeformations) { if (deformation.DeformationParams.UseMovementSine) { if (this is AnimController animator) { //deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos + MathHelper.Pi); deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.DeformationParams.Frequency + MathHelper.Pi * deformation.DeformationParams.SineOffset); } } else { deformation.Update(deltaTime); } } }
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null) { float MaxVel = NetConfig.MaxPhysicsBodyVelocity; float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; msg.Write(SimPosition.X); msg.Write(SimPosition.Y); #if DEBUG if (Math.Abs(FarseerBody.LinearVelocity.X) > MaxVel || Math.Abs(FarseerBody.LinearVelocity.Y) > MaxVel) { DebugConsole.ThrowError($"Entity velocity out of range ({(UserData?.ToString() ?? "null")}, {FarseerBody.LinearVelocity})"); } #endif msg.Write(FarseerBody.Awake); msg.Write(FarseerBody.FixedRotation); if (!FarseerBody.FixedRotation) { msg.WriteRangedSingle(MathUtils.WrapAngleTwoPi(FarseerBody.Rotation), 0.0f, MathHelper.TwoPi, 8); } if (FarseerBody.Awake) { FarseerBody.Enabled = true; FarseerBody.LinearVelocity = new Vector2( MathHelper.Clamp(FarseerBody.LinearVelocity.X, -MaxVel, MaxVel), MathHelper.Clamp(FarseerBody.LinearVelocity.Y, -MaxVel, MaxVel)); msg.WriteRangedSingle(FarseerBody.LinearVelocity.X, -MaxVel, MaxVel, 12); msg.WriteRangedSingle(FarseerBody.LinearVelocity.Y, -MaxVel, MaxVel, 12); if (!FarseerBody.FixedRotation) { FarseerBody.AngularVelocity = MathHelper.Clamp(FarseerBody.AngularVelocity, -MaxAngularVel, MaxAngularVel); msg.WriteRangedSingle(FarseerBody.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); } } msg.WritePadBits(); }
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null) { float MaxVel = NetConfig.MaxPhysicsBodyVelocity; float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; msg.Write(SimPosition.X); msg.Write(SimPosition.Y); #if DEBUG if (Math.Abs(body.LinearVelocity.X) > MaxVel || Math.Abs(body.LinearVelocity.Y) > MaxVel) { DebugConsole.ThrowError("Item velocity out of range (" + body.LinearVelocity + ")"); } #endif msg.Write(FarseerBody.Awake); msg.Write(FarseerBody.FixedRotation); if (!FarseerBody.FixedRotation) { msg.WriteRangedSingle(MathUtils.WrapAngleTwoPi(body.Rotation), 0.0f, MathHelper.TwoPi, 8); } if (FarseerBody.Awake) { body.Enabled = true; body.LinearVelocity = new Vector2( MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel)); msg.WriteRangedSingle(body.LinearVelocity.X, -MaxVel, MaxVel, 12); msg.WriteRangedSingle(body.LinearVelocity.Y, -MaxVel, MaxVel, 12); if (!FarseerBody.FixedRotation) { body.AngularVelocity = MathHelper.Clamp(body.AngularVelocity, -MaxAngularVel, MaxAngularVel); msg.WriteRangedSingle(body.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); } } msg.WritePadBits(); }
void UpdateSineAnim(float deltaTime) { if (CurrentSwimParams == null) { return; } movement = TargetMovement; if (movement.LengthSquared() > 0.00001f) { Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, 0.5f); } //limbs are disabled when simple physics is enabled, no need to move them if (SimplePhysicsEnabled) { return; } MainLimb.PullJointEnabled = true; //MainLimb.PullJointWorldAnchorB = Collider.SimPosition; if (movement.LengthSquared() < 0.00001f) { WalkPos = MathHelper.SmoothStep(WalkPos, MathHelper.PiOver2, deltaTime * 5); MainLimb.PullJointWorldAnchorB = Collider.SimPosition; return; } Vector2 transformedMovement = reverse ? -movement : movement; float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2; float mainLimbAngle = 0; if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue) { mainLimbAngle = TorsoAngle.Value; } else if (MainLimb.type == LimbType.Head && HeadAngle.HasValue) { mainLimbAngle = HeadAngle.Value; } mainLimbAngle *= Dir; while (MainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi) { movementAngle += MathHelper.TwoPi; } while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi) { movementAngle -= MathHelper.TwoPi; } if (CurrentSwimParams.RotateTowardsMovement) { Collider.SmoothRotate(movementAngle, CurrentSwimParams.SteerTorque); if (TorsoAngle.HasValue) { Limb torso = GetLimb(LimbType.Torso); if (torso != null) { SmoothRotateWithoutWrapping(torso, movementAngle + TorsoAngle.Value * Dir, MainLimb, TorsoTorque); } } if (HeadAngle.HasValue) { Limb head = GetLimb(LimbType.Head); if (head != null) { SmoothRotateWithoutWrapping(head, movementAngle + HeadAngle.Value * Dir, MainLimb, HeadTorque); } } if (TailAngle.HasValue) { Limb tail = GetLimb(LimbType.Tail); if (tail != null) { SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque); } } } else { movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2; if (reverse) { movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi); } if (MainLimb.type == LimbType.Head && HeadAngle.HasValue) { Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque); } else if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue) { Collider.SmoothRotate(TorsoAngle.Value * Dir, CurrentSwimParams.SteerTorque); } if (TorsoAngle.HasValue) { Limb torso = GetLimb(LimbType.Torso); torso?.body.SmoothRotate(TorsoAngle.Value * Dir, TorsoTorque); } if (HeadAngle.HasValue) { Limb head = GetLimb(LimbType.Head); head?.body.SmoothRotate(HeadAngle.Value * Dir, HeadTorque); } if (TailAngle.HasValue) { Limb tail = GetLimb(LimbType.Tail); tail?.body.SmoothRotate(TailAngle.Value * Dir, TailTorque); } } var waveLength = Math.Abs(CurrentSwimParams.WaveLength * RagdollParams.JointScale); var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude); if (waveLength > 0 && waveAmplitude > 0) { WalkPos -= transformedMovement.Length() / Math.Abs(waveLength); WalkPos = MathUtils.WrapAngleTwoPi(WalkPos); } foreach (var limb in Limbs) { switch (limb.type) { case LimbType.LeftFoot: case LimbType.RightFoot: if (CurrentSwimParams.FootAnglesInRadians.ContainsKey(limb.limbParams.ID)) { SmoothRotateWithoutWrapping(limb, movementAngle + CurrentSwimParams.FootAnglesInRadians[limb.limbParams.ID] * Dir, MainLimb, FootTorque); } break; case LimbType.Tail: if (waveLength > 0 && waveAmplitude > 0) { float waveRotation = (float)Math.Sin(WalkPos); limb.body.ApplyTorque(waveRotation * limb.Mass * CurrentSwimParams.TailTorque * waveAmplitude); } break; } } for (int i = 0; i < Limbs.Length; i++) { if (Limbs[i].SteerForce <= 0.0f) { continue; } Vector2 pullPos = Limbs[i].PullJointWorldAnchorA; Limbs[i].body.ApplyForce(movement * Limbs[i].SteerForce * Limbs[i].Mass, pullPos); } Vector2 mainLimbDiff = MainLimb.PullJointWorldAnchorB - MainLimb.SimPosition; if (CurrentSwimParams.UseSineMovement) { MainLimb.PullJointWorldAnchorB = Vector2.SmoothStep( MainLimb.PullJointWorldAnchorB, Collider.SimPosition, mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : (float)Math.Abs(Math.Sin(WalkPos))); } else { //MainLimb.PullJointWorldAnchorB = Collider.SimPosition; MainLimb.PullJointWorldAnchorB = Vector2.Lerp( MainLimb.PullJointWorldAnchorB, Collider.SimPosition, mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : 0.5f); } floorY = Limbs[0].SimPosition.Y; }
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; } }
public static VertexPositionTexture[] GenerateWallShapes(List <VoronoiCell> cells, Level level) { float outWardThickness = 30.0f; List <VertexPositionTexture> verticeList = new List <VertexPositionTexture>(); foreach (VoronoiCell cell in cells) { CompareCCW compare = new CompareCCW(cell.Center); foreach (GraphEdge edge in cell.Edges) { if (edge.Cell1 != null && edge.Cell1.Body == null && edge.Cell1.CellType != CellType.Empty) { edge.Cell1 = null; } if (edge.Cell2 != null && edge.Cell2.Body == null && edge.Cell2.CellType != CellType.Empty) { edge.Cell2 = null; } if (compare.Compare(edge.Point1, edge.Point2) == -1) { var temp = edge.Point1; edge.Point1 = edge.Point2; edge.Point2 = temp; } } } foreach (VoronoiCell cell in cells) { foreach (GraphEdge edge in cell.Edges) { if (!edge.IsSolid) { continue; } GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1 == e.Point1 || edge.Point1 == e.Point2)); GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2 == e.Point1 || edge.Point2 == e.Point2)); Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero; float inwardThickness1 = 100; float inwardThickness2 = 100; if (leftEdge != null && !leftEdge.IsSolid) { leftNormal = edge.Point1 == leftEdge.Point1 ? Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) : Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2); inwardThickness1 = Vector2.Distance(leftEdge.Point1, leftEdge.Point2) / 2; } else { leftNormal = Vector2.Normalize(cell.Center - edge.Point1); inwardThickness1 = Vector2.Distance(edge.Point1, cell.Center) / 2; } if (!MathUtils.IsValid(leftNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid left normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { GameMain.World.RemoveBody(cell.Body); cell.Body = null; } leftNormal = Vector2.UnitX; break; } if (rightEdge != null && !rightEdge.IsSolid) { rightNormal = edge.Point2 == rightEdge.Point1 ? Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) : Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2); inwardThickness2 = Vector2.Distance(rightEdge.Point1, rightEdge.Point2) / 2; } else { rightNormal = Vector2.Normalize(cell.Center - edge.Point2); inwardThickness2 = Vector2.Distance(edge.Point2, cell.Center) / 2; } if (!MathUtils.IsValid(rightNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid right normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { GameMain.World.RemoveBody(cell.Body); cell.Body = null; } rightNormal = Vector2.UnitX; break; } float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - cell.Center)); float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - cell.Center)); //handle wrapping around 0/360 if (point1UV - point2UV > MathHelper.Pi) { point2UV += MathHelper.TwoPi; } //the texture wraps around the cell 4 times //TODO: define the uv scale in level generation parameters? point1UV = point1UV / MathHelper.TwoPi * 4; point2UV = point2UV / MathHelper.TwoPi * 4; for (int i = 0; i < 2; i++) { Vector2[] verts = new Vector2[3]; VertexPositionTexture[] vertPos = new VertexPositionTexture[3]; if (i == 0) { verts[0] = edge.Point1 - leftNormal * outWardThickness; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point1 + leftNormal * inwardThickness1; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.0f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point1UV, 0.5f)); } else { verts[0] = edge.Point1 + leftNormal * inwardThickness1; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point2 + rightNormal * inwardThickness2; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.5f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point2UV, 0.5f)); } verticeList.AddRange(vertPos); } } } return(verticeList.ToArray()); }
void UpdateSineAnim(float deltaTime) { if (CurrentSwimParams == null) { return; } movement = TargetMovement; if (movement.LengthSquared() > 0.00001f) { float t = 0.5f; if (CurrentSwimParams.RotateTowardsMovement && VectorExtensions.Angle(VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2), movement) > MathHelper.PiOver2) { // Reduce the linear movement speed when not facing the movement direction t /= 5; } Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t); } //limbs are disabled when simple physics is enabled, no need to move them if (SimplePhysicsEnabled) { return; } var mainLimb = MainLimb; mainLimb.PullJointEnabled = true; //mainLimb.PullJointWorldAnchorB = Collider.SimPosition; if (movement.LengthSquared() < 0.00001f) { WalkPos = MathHelper.SmoothStep(WalkPos, MathHelper.PiOver2, deltaTime * 5); mainLimb.PullJointWorldAnchorB = Collider.SimPosition; return; } Vector2 transformedMovement = reverse ? -movement : movement; float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2; float mainLimbAngle = 0; if (mainLimb.type == LimbType.Torso && TorsoAngle.HasValue) { mainLimbAngle = TorsoAngle.Value; } else if (mainLimb.type == LimbType.Head && HeadAngle.HasValue) { mainLimbAngle = HeadAngle.Value; } mainLimbAngle *= Dir; while (mainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi) { movementAngle += MathHelper.TwoPi; } while (mainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi) { movementAngle -= MathHelper.TwoPi; } if (CurrentSwimParams.RotateTowardsMovement) { Collider.SmoothRotate(movementAngle, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); if (TorsoAngle.HasValue) { Limb torso = GetLimb(LimbType.Torso); if (torso != null) { SmoothRotateWithoutWrapping(torso, movementAngle + TorsoAngle.Value * Dir, mainLimb, TorsoTorque); } } if (HeadAngle.HasValue) { Limb head = GetLimb(LimbType.Head); if (head != null) { SmoothRotateWithoutWrapping(head, movementAngle + HeadAngle.Value * Dir, mainLimb, HeadTorque); } } if (TailAngle.HasValue) { Limb tail = GetLimb(LimbType.Tail); if (tail != null) { float?mainLimbTargetAngle = null; if (mainLimb.type == LimbType.Torso) { mainLimbTargetAngle = TorsoAngle; } else if (mainLimb.type == LimbType.Head) { mainLimbTargetAngle = HeadAngle; } float torque = TailTorque; float maxMultiplier = CurrentSwimParams.TailTorqueMultiplier; if (mainLimbTargetAngle.HasValue && maxMultiplier > 1) { float diff = Math.Abs(mainLimb.Rotation - tail.Rotation); float offset = Math.Abs(mainLimbTargetAngle.Value - TailAngle.Value); torque *= MathHelper.Lerp(1, maxMultiplier, MathUtils.InverseLerp(0, MathHelper.PiOver2, diff - offset)); } SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, mainLimb, torque); } } } else { movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2; if (reverse) { movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi); } if (mainLimb.type == LimbType.Head && HeadAngle.HasValue) { Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); } else if (mainLimb.type == LimbType.Torso && TorsoAngle.HasValue) { Collider.SmoothRotate(TorsoAngle.Value * Dir, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); } if (TorsoAngle.HasValue) { Limb torso = GetLimb(LimbType.Torso); torso?.body.SmoothRotate(TorsoAngle.Value * Dir, TorsoTorque); } if (HeadAngle.HasValue) { Limb head = GetLimb(LimbType.Head); head?.body.SmoothRotate(HeadAngle.Value * Dir, HeadTorque); } if (TailAngle.HasValue) { Limb tail = GetLimb(LimbType.Tail); tail?.body.SmoothRotate(TailAngle.Value * Dir, TailTorque); } } var waveLength = Math.Abs(CurrentSwimParams.WaveLength * RagdollParams.JointScale); var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude * character.SpeedMultiplier); if (waveLength > 0 && waveAmplitude > 0) { WalkPos -= transformedMovement.Length() / Math.Abs(waveLength); WalkPos = MathUtils.WrapAngleTwoPi(WalkPos); } foreach (var limb in Limbs) { if (limb.IsSevered) { continue; } if (Math.Abs(limb.Params.ConstantTorque) > 0) { limb.body.SmoothRotate(movementAngle + MathHelper.ToRadians(limb.Params.ConstantAngle) * Dir, limb.Params.ConstantTorque, wrapAngle: true); } switch (limb.type) { case LimbType.LeftFoot: case LimbType.RightFoot: if (CurrentSwimParams.FootAnglesInRadians.ContainsKey(limb.Params.ID)) { SmoothRotateWithoutWrapping(limb, movementAngle + CurrentSwimParams.FootAnglesInRadians[limb.Params.ID] * Dir, mainLimb, FootTorque); } break; case LimbType.Tail: if (waveLength > 0 && waveAmplitude > 0) { float waveRotation = (float)Math.Sin(WalkPos); limb.body.ApplyTorque(waveRotation * limb.Mass * waveAmplitude); } break; } } for (int i = 0; i < Limbs.Length; i++) { var limb = Limbs[i]; if (limb.IsSevered) { continue; } if (limb.SteerForce <= 0.0f) { continue; } if (!Collider.PhysEnabled) { continue; } Vector2 pullPos = limb.PullJointWorldAnchorA; limb.body.ApplyForce(movement * limb.SteerForce * limb.Mass * Math.Max(character.SpeedMultiplier, 1), pullPos); } Vector2 mainLimbDiff = mainLimb.PullJointWorldAnchorB - mainLimb.SimPosition; if (CurrentSwimParams.UseSineMovement) { mainLimb.PullJointWorldAnchorB = Vector2.SmoothStep( mainLimb.PullJointWorldAnchorB, Collider.SimPosition, mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : (float)Math.Abs(Math.Sin(WalkPos))); } else { //mainLimb.PullJointWorldAnchorB = Collider.SimPosition; mainLimb.PullJointWorldAnchorB = Vector2.Lerp( mainLimb.PullJointWorldAnchorB, Collider.SimPosition, mainLimbDiff.LengthSquared() > 10.0f ? 1.0f : 0.5f); } floorY = Limbs[0].SimPosition.Y; }
private void SetDamage(int sectionIndex, float damage, Character attacker = null, bool createNetworkEvent = true) { if (Submarine != null && Submarine.GodMode || Indestructible) { return; } if (!Prefab.Body) { return; } if (!MathUtils.IsValid(damage)) { return; } damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health); #if SERVER if (GameMain.Server != null && createNetworkEvent && damage != Sections[sectionIndex].damage) { GameMain.Server.CreateEntityEvent(this); } bool noGaps = true; for (int i = 0; i < Sections.Length; i++) { if (i != sectionIndex && SectionIsLeaking(i)) { noGaps = false; break; } } #endif if (damage < Prefab.Health * LeakThreshold) { if (Sections[sectionIndex].gap != null) { #if SERVER //the structure doesn't have any other gap, log the structure being fixed if (noGaps && attacker != null) { GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall repaired by " + attacker.Name, ServerLog.MessageType.ItemInteraction); } #endif DebugConsole.Log("Removing gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") from wall " + ID); //remove existing gap if damage is below leak threshold Sections[sectionIndex].gap.Open = 0.0f; Sections[sectionIndex].gap.Remove(); Sections[sectionIndex].gap = null; } } else { if (Sections[sectionIndex].gap == null) { Rectangle gapRect = Sections[sectionIndex].rect; float diffFromCenter; if (IsHorizontal) { diffFromCenter = (gapRect.Center.X - this.rect.Center.X) / (float)this.rect.Width * BodyWidth; if (BodyWidth > 0.0f) { gapRect.Width = (int)(BodyWidth * (gapRect.Width / (float)this.rect.Width)); } if (BodyHeight > 0.0f) { gapRect.Height = (int)BodyHeight; } } else { diffFromCenter = ((gapRect.Y - gapRect.Height / 2) - (this.rect.Y - this.rect.Height / 2)) / (float)this.rect.Height * BodyHeight; if (BodyWidth > 0.0f) { gapRect.Width = (int)BodyWidth; } if (BodyHeight > 0.0f) { gapRect.Height = (int)(BodyHeight * (gapRect.Height / (float)this.rect.Height)); } } if (FlippedX) { diffFromCenter = -diffFromCenter; } if (BodyRotation != 0.0f) { Vector2 structureCenter = Position; Vector2 gapPos = structureCenter + new Vector2( (float)Math.Cos(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation), (float)Math.Sin(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation)) * diffFromCenter; gapRect = new Rectangle((int)(gapPos.X - gapRect.Width / 2), (int)(gapPos.Y + gapRect.Height / 2), gapRect.Width, gapRect.Height); } gapRect.X -= 10; gapRect.Y += 10; gapRect.Width += 20; gapRect.Height += 20; bool horizontalGap = !IsHorizontal; if (Prefab.BodyRotation != 0.0f) { //rotation within a 90 deg sector (e.g. 100 -> 10, 190 -> 10, -10 -> 80) float sectorizedRotation = MathUtils.WrapAngleTwoPi(BodyRotation) % MathHelper.PiOver2; //diagonal if 30 < angle < 60 bool diagonal = sectorizedRotation > MathHelper.Pi / 6 && sectorizedRotation < MathHelper.Pi / 3; //gaps on the lower half of a diagonal wall are horizontal, ones on the upper half are vertical if (diagonal) { horizontalGap = gapRect.Y - gapRect.Height / 2 < Position.Y; } } Sections[sectionIndex].gap = new Gap(gapRect, horizontalGap, Submarine); //free the ID, because if we give gaps IDs we have to make sure they always match between the clients and the server and //that clients create them in the correct order along with every other entity created/removed during the round //which COULD be done via entityspawner, but it's unnecessary because we never access these gaps by ID Sections[sectionIndex].gap.FreeID(); Sections[sectionIndex].gap.ShouldBeSaved = false; Sections[sectionIndex].gap.ConnectedWall = this; DebugConsole.Log("Created gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") on wall " + ID); //AdjustKarma(attacker, 300); #if SERVER //the structure didn't have any other gaps yet, log the breach if (noGaps && attacker != null) { GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall breached by " + attacker.Name, ServerLog.MessageType.ItemInteraction); } #endif } float gapOpen = (damage / Prefab.Health - LeakThreshold) * (1.0f / (1.0f - LeakThreshold)); Sections[sectionIndex].gap.Open = gapOpen; } float damageDiff = damage - Sections[sectionIndex].damage; bool hadHole = SectionBodyDisabled(sectionIndex); Sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health); //otherwise it's possible to infinitely gain karma by welding fixed things if (attacker != null && damageDiff != 0.0f) { AdjustKarma(attacker, damageDiff); #if CLIENT if (GameMain.Client == null) { #endif if (damageDiff < 0.0f) { attacker.Info.IncreaseSkillLevel("mechanical", -damageDiff * SkillIncreaseMultiplier / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f), SectionPosition(sectionIndex, true)); } #if CLIENT } #endif } bool hasHole = SectionBodyDisabled(sectionIndex); if (hadHole == hasHole) { return; } UpdateSections(); }
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; } } }
public static List <VertexPositionTexture> GenerateWallEdgeVertices(List <VoronoiCell> cells, Level level, float zCoord) { float outWardThickness = level.GenerationParams.WallEdgeExpandOutwardsAmount; List <VertexPositionTexture> vertices = new List <VertexPositionTexture>(); foreach (VoronoiCell cell in cells) { Vector2 minVert = cell.Edges[0].Point1; Vector2 maxVert = cell.Edges[0].Point1; float circumference = 0.0f; foreach (GraphEdge edge in cell.Edges) { circumference += Vector2.Distance(edge.Point1, edge.Point2); minVert = new Vector2( Math.Min(minVert.X, edge.Point1.X), Math.Min(minVert.Y, edge.Point1.Y)); maxVert = new Vector2( Math.Max(maxVert.X, edge.Point1.X), Math.Max(maxVert.Y, edge.Point1.Y)); } Vector2 center = (minVert + maxVert) / 2; foreach (GraphEdge edge in cell.Edges) { if (!edge.IsSolid) { continue; } GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2))); var leftAdjacentCell = leftEdge?.AdjacentCell(cell); if (leftAdjacentCell != null) { var adjEdge = leftAdjacentCell.Edges.Find(e => e != leftEdge && e.IsSolid && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2))); if (adjEdge != null) { leftEdge = adjEdge; } } GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2))); var rightAdjacentCell = rightEdge?.AdjacentCell(cell); if (rightAdjacentCell != null) { var adjEdge = rightAdjacentCell.Edges.Find(e => e != rightEdge && e.IsSolid && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2))); if (adjEdge != null) { rightEdge = adjEdge; } } Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero; float inwardThickness1 = level.GenerationParams.WallEdgeExpandInwardsAmount; float inwardThickness2 = level.GenerationParams.WallEdgeExpandInwardsAmount; if (leftEdge != null && !leftEdge.IsSolid) { leftNormal = edge.Point1.NearlyEquals(leftEdge.Point1) ? Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) : Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2); } else if (leftEdge != null) { leftNormal = -Vector2.Normalize(edge.GetNormal(cell) + leftEdge.GetNormal(leftAdjacentCell ?? cell)); if (!MathUtils.IsValid(leftNormal)) { leftNormal = -edge.GetNormal(cell); } } else { leftNormal = Vector2.Normalize(cell.Center - edge.Point1); } inwardThickness1 = Math.Min(Vector2.Distance(edge.Point1, cell.Center), inwardThickness1); if (!MathUtils.IsValid(leftNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid left normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { if (GameMain.World.BodyList.Contains(cell.Body)) { GameMain.World.Remove(cell.Body); } cell.Body = null; } leftNormal = Vector2.UnitX; break; } if (rightEdge != null && !rightEdge.IsSolid) { rightNormal = edge.Point2.NearlyEquals(rightEdge.Point1) ? Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) : Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2); } else if (rightEdge != null) { rightNormal = -Vector2.Normalize(edge.GetNormal(cell) + rightEdge.GetNormal(rightAdjacentCell ?? cell)); if (!MathUtils.IsValid(rightNormal)) { rightNormal = -edge.GetNormal(cell); } } else { rightNormal = Vector2.Normalize(cell.Center - edge.Point2); } inwardThickness2 = Math.Min(Vector2.Distance(edge.Point2, cell.Center), inwardThickness2); if (!MathUtils.IsValid(rightNormal)) { #if DEBUG DebugConsole.ThrowError("Invalid right normal"); #endif GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, "Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")"); if (cell.Body != null) { if (GameMain.World.BodyList.Contains(cell.Body)) { GameMain.World.Remove(cell.Body); } cell.Body = null; } rightNormal = Vector2.UnitX; break; } float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - center)); float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - center)); //handle wrapping around 0/360 if (point1UV - point2UV > MathHelper.Pi) { point1UV -= MathHelper.TwoPi; } int textureRepeatCount = (int)Math.Max(circumference / 2 / level.GenerationParams.WallEdgeTextureWidth, 1); point1UV = point1UV / MathHelper.TwoPi * textureRepeatCount; point2UV = point2UV / MathHelper.TwoPi * textureRepeatCount; for (int i = 0; i < 2; i++) { Vector2[] verts = new Vector2[3]; VertexPositionTexture[] vertPos = new VertexPositionTexture[3]; if (i == 0) { verts[0] = edge.Point1 - leftNormal * outWardThickness; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point1 + leftNormal * inwardThickness1; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 0.0f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point1UV, 1.0f)); } else { verts[0] = edge.Point1 + leftNormal * inwardThickness1; verts[1] = edge.Point2 - rightNormal * outWardThickness; verts[2] = edge.Point2 + rightNormal * inwardThickness2; vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 1.0f)); vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f)); vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point2UV, 1.0f)); } vertices.AddRange(vertPos); } } } return(vertices); }
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 && character.SelectedItems[i].body != 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); } }