From 23fabc6460b705f8efe73887dc8e919d72ea7078 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Fri, 1 Jun 2018 21:25:10 -1000 Subject: [PATCH 01/15] Add Vector3d operators; Add Scan tooltip to clarify axes of a Vector3d value; --- Core/Game/Abilities/Essential/Scan.cs | 2 +- Core/Simulation/Math/Vector3d.cs | 49 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Core/Game/Abilities/Essential/Scan.cs b/Core/Game/Abilities/Essential/Scan.cs index 4d7406ca..3696621f 100644 --- a/Core/Game/Abilities/Essential/Scan.cs +++ b/Core/Game/Abilities/Essential/Scan.cs @@ -88,7 +88,7 @@ public virtual Vector3d[] ProjectileOffsets { protected bool _trackAttackAngle = true; [FixedNumberAngle, SerializeField] protected long _attackAngle = FixedMath.TenDegrees; - [SerializeField] + [SerializeField, Tooltip ("Important: With Vector3d, the Z axis represents height!")] protected Vector3d _projectileOffset; [SerializeField] protected Vector3d[] _secondaryProjectileOffsets; diff --git a/Core/Simulation/Math/Vector3d.cs b/Core/Simulation/Math/Vector3d.cs index 9408c364..2877ecf0 100755 --- a/Core/Simulation/Math/Vector3d.cs +++ b/Core/Simulation/Math/Vector3d.cs @@ -108,5 +108,54 @@ public void Read (Reader reader) { y = reader.ReadLong(); z = reader.ReadLong(); } + + #region Operators + + public static Vector3d operator +(Vector3d v1, Vector3d v2) + { + return new Vector3d(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); + } + + public static Vector3d operator -(Vector3d v1, Vector3d v2) + { + return new Vector3d(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + public static Vector3d operator *(Vector3d v1, long mag) + { + return new Vector3d((v1.x * mag) >> FixedMath.SHIFT_AMOUNT, (v1.y * mag) >> FixedMath.SHIFT_AMOUNT, (v1.z * mag) >> FixedMath.SHIFT_AMOUNT); + } + + public static Vector3d operator *(Vector3d v1, int mag) + { + return new Vector3d((v1.x * mag), (v1.y * mag), (v1.z * mag)); + } + + public static Vector3d operator /(Vector3d v1, long div) + { + return new Vector3d(((v1.x << FixedMath.SHIFT_AMOUNT) / div), (v1.y << FixedMath.SHIFT_AMOUNT) / div, (v1.z << FixedMath.SHIFT_AMOUNT) / div); + } + + public static Vector3d operator /(Vector3d v1, int div) + { + return new Vector3d((v1.x / div), v1.y / div, v1.z / div); + } + + public static Vector3d operator >>(Vector3d v1, int shift) + { + return new Vector3d(v1.x >> shift, v1.y >> shift, v1.z >> shift); + } + + public static bool operator ==(Vector3d v1, Vector3d v2) + { + return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z; + } + + public static bool operator !=(Vector3d v1, Vector3d v2) + { + return v1.x != v2.x || v1.y != v2.y || v1.z != v2.z; + } + + #endregion } } \ No newline at end of file From 24737fa1e47a1ddcba62e00d66932c4a1e526104 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Fri, 1 Jun 2018 22:11:57 -1000 Subject: [PATCH 02/15] [Huge Optimization] Implement collision check frequency culling based on time since the last collision. --- Core/Simulation/Physics/Core/CollisionPair.cs | 81 ++++++++++++++----- Core/Simulation/Physics/Core/LSBody.cs | 4 + Core/Simulation/Physics/Core/PartitionNode.cs | 1 - .../Simulation/Physics/Core/PhysicsManager.cs | 7 ++ 4 files changed, 73 insertions(+), 20 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 579a17a1..82c922a8 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -21,6 +21,9 @@ public class CollisionPair public uint PartitionVersion; public ushort _Version = 1; + internal ushort TimeSinceLastCollision; + internal short CullCounter; + public bool _isColliding; public bool IsColliding { @@ -44,6 +47,7 @@ public bool IsColliding { public void Initialize (LSBody b1, LSBody b2) { + IsValid = true; if (!IsValid) return; @@ -101,6 +105,16 @@ public void Initialize (LSBody b1, LSBody b2) if (DoPhysics) { } + + + if (Body1.PreventCulling || Body2.PreventCulling) + CullCounter = -1; + else + //Immediately check collision + CullCounter = 0; + //But don't have many checks until the bodies collide + TimeSinceLastCollision = PhysicsManager.CullingTimeSinceLastCollisionDefault; + Active = true; _Version++; } @@ -231,29 +245,58 @@ void DistributeCircle_Poly (LSBody circle, LSBody poly) public void CheckAndDistributeCollision () { + if (CullCounter <= 0) { + IsCollidingChanged = false; - if (!Active) { - return; - } - if (_ranIndex < 0) { - _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); - } - LastFrame = LockstepManager.FrameCount; - CurrentCollisionPair = this; + if (!Active) { + return; + } + if (_ranIndex < 0) { + _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); + } + LastFrame = LockstepManager.FrameCount; + CurrentCollisionPair = this; - IsCollidingChanged = false; - if (CheckHeight ()) { - bool result = CheckCollision (); - if (result != IsColliding) { - IsColliding = result; - IsCollidingChanged = true; + IsCollidingChanged = false; + + if (CheckHeight ()) { + bool result = CheckCollision (); + + if (result != IsColliding) { + IsColliding = result; + IsCollidingChanged = true; + } + if (CheckCollision ()) { + DistributeCollision (); + } + } + Body1.NotifyContact (Body2, IsColliding, IsCollidingChanged); + Body2.NotifyContact (Body1, IsColliding, IsCollidingChanged); + if (IsColliding == false) { + //A negative cull counter means a Body is preventing culling + if (CullCounter >= 0) { + //Set number of frames until next collision check + CullCounter = (short)(TimeSinceLastCollision / PhysicsManager.CullingFrequencyStep); + if (CullCounter > PhysicsManager.CullingFrequencyMax) + CullCounter = PhysicsManager.CullingFrequencyMax; + } + } + } else { + //Culled and counter 1 step closer until checking again + CullCounter--; + if (Body1.Agent == null) { + if (Body2.Agent.Data.Name == "TestHero") + Debug.Log (CullCounter); } - if (CheckCollision ()) { - DistributeCollision (); - } + + } + + //For further culling of collisions + if (IsColliding) { + TimeSinceLastCollision = 0; + } else { + TimeSinceLastCollision++; } - Body1.NotifyContact (Body2, IsColliding, IsCollidingChanged); - Body2.NotifyContact (Body1, IsColliding, IsCollidingChanged); } public bool CheckHeight () diff --git a/Core/Simulation/Physics/Core/LSBody.cs b/Core/Simulation/Physics/Core/LSBody.cs index 84e1f987..19a8cda7 100755 --- a/Core/Simulation/Physics/Core/LSBody.cs +++ b/Core/Simulation/Physics/Core/LSBody.cs @@ -28,6 +28,8 @@ public partial class LSBody [SerializeField] public Vector2d _velocity; + [SerializeField, Tooltip ("Useful for fast-moving objects that might pass through if not checked for a frame.")] + private bool _preventCulling = false; #endregion #region Lockstep variables @@ -122,6 +124,8 @@ public Vector2d Velocity { internal uint RaycastVersion { get; set; } + internal bool PreventCulling { get { return _preventCulling; } } + #endregion internal Vector3 _visualPosition; diff --git a/Core/Simulation/Physics/Core/PartitionNode.cs b/Core/Simulation/Physics/Core/PartitionNode.cs index 34785307..12e51dbd 100755 --- a/Core/Simulation/Physics/Core/PartitionNode.cs +++ b/Core/Simulation/Physics/Core/PartitionNode.cs @@ -77,7 +77,6 @@ public void Distribute () id2 = ContainedImmovableObjects [k]; ProcessPair (); } - } diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index f4d5ff31..e9b12681 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -20,6 +20,13 @@ public static class PhysicsManager public const bool SimulatePhysics = true; + //After a certain amount of frames have passed without collision, culling frequency will increase + internal const int CullingFrequencyStep = LockstepManager.FrameRate; + //Maximum amount of frames to wait between checks + internal const int CullingFrequencyMax = LockstepManager.FrameRate / 4; + //Optimally the rate to increase culling requency is higher when the CollisionPair is first created + //but this is much cheaper and effective optimization + internal const int CullingTimeSinceLastCollisionDefault = LockstepManager.FrameRate * CullingFrequencyMax / 4; static double FixedDeltaTime { get { From aac8474deb92e29eb02729b9b22336a149e0b1c0 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Fri, 1 Jun 2018 22:15:49 -1000 Subject: [PATCH 03/15] Add TODO for further improvements to collision check culling --- Core/Simulation/Physics/Core/CollisionPair.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 82c922a8..356275e9 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -107,6 +107,10 @@ public void Initialize (LSBody b1, LSBody b2) } + //TODO: The time between collision checks might cause goofy behavior + //Maybe use a distance or velocity heuristic for culling instead of time since last collision + //It wouldn't be able to replace partitions because of raycasts and fast-moving objects + //Let's see if this works well or if something better is needed. if (Body1.PreventCulling || Body2.PreventCulling) CullCounter = -1; else From cee9522bc962faf2e8c3eae0c1412dbe13957417 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 12:22:30 -1000 Subject: [PATCH 04/15] Improve auto-turning behavior... less sensitive and erratic now. --- Core/Game/Abilities/Essential/Turn.cs | 31 +++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/Core/Game/Abilities/Essential/Turn.cs b/Core/Game/Abilities/Essential/Turn.cs index 3993dd10..32efb8b6 100644 --- a/Core/Game/Abilities/Essential/Turn.cs +++ b/Core/Game/Abilities/Essential/Turn.cs @@ -26,7 +26,8 @@ protected override void OnSetup () turnSin = _turnRate.y; turnCos = _turnRate.x; - collisionTurnThreshold = Agent.Body.Radius / LockstepManager.FrameRate; + + collisionTurnThreshold = Agent.Body.Radius / (LockstepManager.FrameRate / 2); collisionTurnThreshold *= collisionTurnThreshold; Agent.Body.onContact += HandleContact; } @@ -41,10 +42,23 @@ protected override void OnInitialize () bufferStartTurn = false; } + bool isColliding; + void CheckAutoturn () { + if (isColliding) { + isColliding = false; + //autoturn direction will be culmination of positional changes + if (targetReached == true && Agent.IsCasting == false && !(Agent.Body.Immovable || Agent.Body.IsTrigger)) { + Vector2d delta = this.Agent.Body._position - this.Agent.Body.LastPosition; + if (delta.FastMagnitude () > collisionTurnThreshold) { + delta.Normalize (); + this.StartTurnDirection (delta); + } + } + } + } protected override void OnSimulate () { - if (targetReached == false) { if (cachedBeginCheck != 0) { { @@ -66,6 +80,7 @@ protected override void OnSimulate () } } + protected override void OnLateSimulate () { if (targetReached == false) { @@ -73,6 +88,9 @@ protected override void OnLateSimulate () if (check == 0 || ((cachedBeginCheck < 0) != (check < 0))) { Arrive (); } + } else { + CheckAutoturn (); + } if (bufferStartTurn) { bufferStartTurn = false; @@ -136,13 +154,8 @@ protected override void OnStopCast () private void HandleContact (LSBody other) { - if (targetReached == true && Agent.IsCasting == false && !(Agent.Body.Immovable || Agent.Body.IsTrigger)) { - Vector2d delta = this.Agent.Body._position - this.Agent.Body.LastPosition; - if (delta.FastMagnitude () > collisionTurnThreshold) { - delta.Normalize (); - this.StartTurnDirection (delta); - } - } + isColliding = true; + } } } \ No newline at end of file From 735af75aafa85428abdcac997cc0877aea2da355 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 15:43:19 -1000 Subject: [PATCH 05/15] Implement distance-based CollisionPair check culls; Increase Partition size; --- Core/Simulation/Physics/Core/CollisionPair.cs | 85 +++++++++---------- Core/Simulation/Physics/Core/LSBody.cs | 6 ++ Core/Simulation/Physics/Core/Legacy/LSBody.cs | 1 + Core/Simulation/Physics/Core/Partition.cs | 5 +- Core/Simulation/Physics/Core/PartitionNode.cs | 3 +- .../Simulation/Physics/Core/PhysicsManager.cs | 45 ++++++++-- 6 files changed, 92 insertions(+), 53 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 356275e9..4991751d 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -14,14 +14,14 @@ public class CollisionPair { public LSBody Body1; public LSBody Body2; - private long CacheSqrDistance; + private long FastCollideDistance; + private long FastDistance; private CollisionType LeCollisionType; private bool DoPhysics = true; public bool Active; public uint PartitionVersion; public ushort _Version = 1; - internal ushort TimeSinceLastCollision; internal short CullCounter; public bool _isColliding; @@ -69,8 +69,8 @@ public void Initialize (LSBody b1, LSBody b2) PenetrationX = 0; PenetrationY = 0; - CacheSqrDistance = b1.Radius + b2.Radius; - CacheSqrDistance *= CacheSqrDistance; + FastCollideDistance = b1.Radius + b2.Radius; + FastCollideDistance *= FastCollideDistance; LeCollisionType = CollisionType.None; if (Body1.Shape == ColliderType.None || Body2.Shape == ColliderType.None) { @@ -107,6 +107,7 @@ public void Initialize (LSBody b1, LSBody b2) } + //TODO: Space out checks when culled //TODO: The time between collision checks might cause goofy behavior //Maybe use a distance or velocity heuristic for culling instead of time since last collision //It wouldn't be able to replace partitions because of raycasts and fast-moving objects @@ -116,8 +117,6 @@ public void Initialize (LSBody b1, LSBody b2) else //Immediately check collision CullCounter = 0; - //But don't have many checks until the bodies collide - TimeSinceLastCollision = PhysicsManager.CullingTimeSinceLastCollisionDefault; Active = true; _Version++; @@ -249,20 +248,21 @@ void DistributeCircle_Poly (LSBody circle, LSBody poly) public void CheckAndDistributeCollision () { - if (CullCounter <= 0) { - IsCollidingChanged = false; + if (!Active) { + return; + } - if (!Active) { - return; - } - if (_ranIndex < 0) { - _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); - } - LastFrame = LockstepManager.FrameCount; - CurrentCollisionPair = this; - - IsCollidingChanged = false; + if (_ranIndex < 0) { + _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); + } + IsCollidingChanged = false; + LastFrame = LockstepManager.FrameCount; + CurrentCollisionPair = this; + + if (CullCounter <= 0) { + + GenerateCircleValues (); if (CheckHeight ()) { bool result = CheckCollision (); @@ -280,27 +280,25 @@ public void CheckAndDistributeCollision () //A negative cull counter means a Body is preventing culling if (CullCounter >= 0) { //Set number of frames until next collision check - CullCounter = (short)(TimeSinceLastCollision / PhysicsManager.CullingFrequencyStep); - if (CullCounter > PhysicsManager.CullingFrequencyMax) - CullCounter = PhysicsManager.CullingFrequencyMax; + CullCounter = (short)((FastDistance >> FixedMath.SHIFT_AMOUNT) / PhysicsManager.CullFrequencyStep + PhysicsManager.CullDistributor); + Debug.Log (CullCounter); + if (CullCounter > PhysicsManager.CullFrequencyMax) + CullCounter = PhysicsManager.CullFrequencyMax; + else if (CullCounter < 0) + CullCounter = 0; } } } else { - //Culled and counter 1 step closer until checking again - CullCounter--; - if (Body1.Agent == null) { - if (Body2.Agent.Data.Name == "TestHero") - Debug.Log (CullCounter); + if (Body1.PartitionChanged || Body2.PartitionChanged) { + //New partition so collision culling may not be calculated yet + CullCounter = 0; + CheckAndDistributeCollision (); + } else { + //Culled and counter 1 step closer until checking again + CullCounter--; } - } - //For further culling of collisions - if (IsColliding) { - TimeSinceLastCollision = 0; - } else { - TimeSinceLastCollision++; - } } public bool CheckHeight () @@ -421,21 +419,20 @@ public bool CheckCollision () return false; } - public bool CheckCircle () - { - + private void GenerateCircleValues () { DistX = Body1._position.x - Body2._position.x; DistY = Body1._position.y - Body2._position.y; - if ((DistX * DistX + DistY * DistY) <= CacheSqrDistance) { + FastDistance = DistX * DistX + DistY * DistY; + } + private bool CheckCircle () + { + if (FastDistance<= FastCollideDistance) { return true; } - - - return false; } - public bool CheckBox () + private bool CheckBox () { if (Body1.XMin <= Body2.XMax) { if (Body1.XMax >= Body2.XMin) { @@ -450,7 +447,7 @@ public bool CheckBox () return false; } - public static bool CheckBox_Poly (LSBody box, LSBody poly) + private static bool CheckBox_Poly (LSBody box, LSBody poly) { bool Right = poly._position.x > box._position.x; bool Top = poly._position.y > box._position.y; @@ -492,7 +489,7 @@ public static bool CheckBox_Poly (LSBody box, LSBody poly) private static long ClosestAxisProjection; - public static bool CheckCircle_Poly (LSBody circle, LSBody poly) + private static bool CheckCircle_Poly (LSBody circle, LSBody poly) { int EdgeCount = poly.EdgeNorms.Length; ClosestDist = long.MaxValue; @@ -536,7 +533,7 @@ public static bool CheckCircle_Poly (LSBody circle, LSBody poly) static bool Collided; static long xAbs, yAbs; - public void DistributeCircle_Box (LSBody box, LSBody circle) + private void DistributeCircle_Box (LSBody box, LSBody circle) { xMore = circle._position.x > box._position.x; yMore = circle._position.y > box._position.y; diff --git a/Core/Simulation/Physics/Core/LSBody.cs b/Core/Simulation/Physics/Core/LSBody.cs index 19a8cda7..d0d466e4 100755 --- a/Core/Simulation/Physics/Core/LSBody.cs +++ b/Core/Simulation/Physics/Core/LSBody.cs @@ -170,6 +170,10 @@ private void RemoveChild(LSBody child) public Vector2d[] Edges; public Vector2d[] EdgeNorms; + /// + /// Used for preventing culling for the first frame this object is added to a new partition node. + /// + internal bool PartitionChanged {get; set;} public long XMin { get; private set; } @@ -467,6 +471,7 @@ public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDy SetVisuals (); velocityPosition = Vector3.zero; this.ImmovableCollisionDirection = Vector2d.zero; + PartitionChanged = true; } void CheckVariables() @@ -564,6 +569,7 @@ public void Simulate() BuildChangedValues(); + PartitionChanged = false; if (PositionChanged || this.PositionChangedBuffer) { Partition.UpdateObject(this); diff --git a/Core/Simulation/Physics/Core/Legacy/LSBody.cs b/Core/Simulation/Physics/Core/Legacy/LSBody.cs index ec316990..c8756b7b 100755 --- a/Core/Simulation/Physics/Core/Legacy/LSBody.cs +++ b/Core/Simulation/Physics/Core/Legacy/LSBody.cs @@ -182,6 +182,7 @@ private void RemoveChild (LSBody child) public Vector2d[] Edges; public Vector2d[] EdgeNorms; + public bool ChangedPartition { get; set; } public long XMin { get; private set; } diff --git a/Core/Simulation/Physics/Core/Partition.cs b/Core/Simulation/Physics/Core/Partition.cs index 2b227329..c67e4ffd 100644 --- a/Core/Simulation/Physics/Core/Partition.cs +++ b/Core/Simulation/Physics/Core/Partition.cs @@ -15,8 +15,9 @@ public static class Partition { #region Settings public const int DefaultCount = 512; - public const int AdditionalShiftSize = 2; + public const int AdditionalShiftSize = 4; public const int ShiftSize = FixedMath.SHIFT_AMOUNT + AdditionalShiftSize; + public const long BlockSize = 1L << ShiftSize; public static int BoundX { get; private set; } //Lower bound X public static int BoundY { get; private set; } //Lower bound Y //Offset due to partition nodes being centered on grid positions @@ -67,6 +68,7 @@ public static void UpdateObject (LSBody Body, bool repartition = true) Body.PastGridYMin != GridYMin || Body.PastGridYMax != GridYMax)) { + //Remove from all partitions no longer located on for (int o = Body.PastGridXMin; o <= Body.PastGridXMax; o++) { for (int p = Body.PastGridYMin; p <= Body.PastGridYMax; p++) { PartitionNode node = GetNode (o, p); @@ -149,6 +151,7 @@ public static void PartitionObject (LSBody Body, bool gridBoundsCalculated = fal for (int i = GridXMin; i <= GridXMax; i++) { for (int j = GridYMin; j <= GridYMax; j++) { PartitionNode node = GetNode (i, j); + Body.PartitionChanged = true; if (Body.Immovable) { node.AddImmovable (Body.ID); diff --git a/Core/Simulation/Physics/Core/PartitionNode.cs b/Core/Simulation/Physics/Core/PartitionNode.cs index 12e51dbd..5c987e9d 100755 --- a/Core/Simulation/Physics/Core/PartitionNode.cs +++ b/Core/Simulation/Physics/Core/PartitionNode.cs @@ -85,8 +85,9 @@ public void Distribute () void ProcessPair () { Partition.count++; - pair = PhysicsManager.GetCollisionPair (id1, id2); + pair = PhysicsManager.GetCollisionPairRaw (id1, id2); if (pair.IsNotNull ()) { + //Ensures collision pairs are not run twice if (pair.PartitionVersion != Partition._Version) { pair.PartitionVersion = Partition._Version; pair.CheckAndDistributeCollision (); diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index e9b12681..2aef7a71 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -21,13 +21,18 @@ public static class PhysicsManager public const bool SimulatePhysics = true; //After a certain amount of frames have passed without collision, culling frequency will increase - internal const int CullingFrequencyStep = LockstepManager.FrameRate; + internal const long CullFrequencyStep = FixedMath.One * 2; //Maximum amount of frames to wait between checks - internal const int CullingFrequencyMax = LockstepManager.FrameRate / 4; - //Optimally the rate to increase culling requency is higher when the CollisionPair is first created - //but this is much cheaper and effective optimization - internal const int CullingTimeSinceLastCollisionDefault = LockstepManager.FrameRate * CullingFrequencyMax / 4; + internal const int CullFrequencyMax = LockstepManager.FrameRate / 2; + static int _cullDistributor; + internal static int CullDistributor { + get { + if (_cullDistributor > 1) + _cullDistributor = -1; + return _cullDistributor++; + } + } static double FixedDeltaTime { get { return 1d / LockstepManager.FrameRate; @@ -170,8 +175,10 @@ public InstanceCollisionPair(ushort version, CollisionPair pair) public static bool ResetAccumulation {get; private set;} public static void LateSimulate() { - //2 seconds before turning off - int inactiveFrameThreshold = 0; + //TODO: Look into this + //8 seconds before turning off + int inactiveFrameThreshold = LockstepManager.FrameRate * 8; + for (int i = 0; i < RanCollisionPairs.PeakCount; i++) { if (RanCollisionPairs.arrayAllocation[i]) { @@ -222,6 +229,7 @@ public static void LateSimulate() } } } + for (int i = 0; i < DynamicSimObjects.PeakCount; i++) { LSBody b1 = DynamicSimObjects.innerArray[i]; if (b1.IsNotNull()) { @@ -356,8 +364,31 @@ internal static void Dessimilate(LSBody body) body.DynamicID = -1; } } + /// + /// Takes away some safety checks + /// + internal static CollisionPair GetCollisionPairRaw (int ID1, int ID2) { + LSBody body1; + LSBody body2; + if ((body1 = SimObjects[ID1]).IsNotNull() && (body2 = SimObjects[ID2]).IsNotNull()) { + if (body1.ID < body2.ID) { + } else { + var temp = body1; + body1 = body2; + body2 = temp; + } + CollisionPair pair; + if (!body1.CollisionPairs.TryGetValue(body2.ID, out pair)) { + pair = CreatePair(body1, body2); + body1.CollisionPairs.Add(body2.ID, pair); + body2.CollisionPairHolders.Add(body1.ID); + } + return pair; + } + return null; + } public static CollisionPair GetCollisionPair(int ID1, int ID2) { LSBody body1; From ca7e7858b310f76cddaed96e3a864f68e61b3755 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 18:39:21 -1000 Subject: [PATCH 06/15] Fix removal of instance pair when unneeded --- Core/Simulation/Physics/Core/CollisionPair.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 4991751d..d0e8fb8b 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -129,6 +129,10 @@ public void Deactivate () Body2.NotifyContact (Body1, false, IsColliding); } Active = false; + if (_ranIndex >= 0) { + PhysicsManager.RanCollisionPairs.RemoveAt (_ranIndex); + _ranIndex = -1; + } } static long dist, depth; @@ -259,9 +263,7 @@ public void CheckAndDistributeCollision () IsCollidingChanged = false; LastFrame = LockstepManager.FrameCount; CurrentCollisionPair = this; - if (CullCounter <= 0) { - GenerateCircleValues (); if (CheckHeight ()) { bool result = CheckCollision (); @@ -281,7 +283,6 @@ public void CheckAndDistributeCollision () if (CullCounter >= 0) { //Set number of frames until next collision check CullCounter = (short)((FastDistance >> FixedMath.SHIFT_AMOUNT) / PhysicsManager.CullFrequencyStep + PhysicsManager.CullDistributor); - Debug.Log (CullCounter); if (CullCounter > PhysicsManager.CullFrequencyMax) CullCounter = PhysicsManager.CullFrequencyMax; else if (CullCounter < 0) From 011c1a752d15812fbaf8b655ad0f6c84a45551ca Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 20:28:28 -1000 Subject: [PATCH 07/15] Add supplemental time-based CollisionPair culling --- Core/Simulation/Physics/Core/CollisionPair.cs | 44 +++++++++++---- Core/Simulation/Physics/Core/LSBody.cs | 17 +++--- .../Simulation/Physics/Core/PhysicsManager.cs | 54 +++++++++---------- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index d0e8fb8b..d6194c27 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -22,7 +22,10 @@ public class CollisionPair public uint PartitionVersion; public ushort _Version = 1; + //If negative, prevent culling altogether internal short CullCounter; + internal bool PreventDistanceCull; + internal int LastCollidedFrame; public bool _isColliding; @@ -112,12 +115,16 @@ public void Initialize (LSBody b1, LSBody b2) //Maybe use a distance or velocity heuristic for culling instead of time since last collision //It wouldn't be able to replace partitions because of raycasts and fast-moving objects //Let's see if this works well or if something better is needed. - if (Body1.PreventCulling || Body2.PreventCulling) + if (Body1.PreventCulling || Body2.PreventCulling) { + //Never cull CullCounter = -1; - else + } + else { //Immediately check collision CullCounter = 0; - + //If collision distance is too large, don't cull based on distance + PreventDistanceCull = FastCollideDistance > PhysicsManager.CullFastDistanceMax; + } Active = true; _Version++; } @@ -281,13 +288,32 @@ public void CheckAndDistributeCollision () if (IsColliding == false) { //A negative cull counter means a Body is preventing culling if (CullCounter >= 0) { - //Set number of frames until next collision check - CullCounter = (short)((FastDistance >> FixedMath.SHIFT_AMOUNT) / PhysicsManager.CullFrequencyStep + PhysicsManager.CullDistributor); - if (CullCounter > PhysicsManager.CullFrequencyMax) - CullCounter = PhysicsManager.CullFrequencyMax; - else if (CullCounter < 0) - CullCounter = 0; + + if (PreventDistanceCull) { + CullCounter = (short)( + (LockstepManager.FrameCount - LastCollidedFrame) / PhysicsManager.CullTimeStep); + } else { + //Set number of frames until next collision check based on distance + var distanceCull = ( + ((FastDistance - FastCollideDistance) >> FixedMath.SHIFT_AMOUNT) + / PhysicsManager.CullDistanceStep + PhysicsManager.CullDistributor + ); + if (distanceCull > PhysicsManager.CullDistanceMax) + distanceCull = PhysicsManager.CullDistanceMax; + if (distanceCull < 0) + distanceCull = 0; + + var timeCull = (LockstepManager.FrameCount - LastCollidedFrame) / PhysicsManager.CullTimeStep; + if (timeCull > PhysicsManager.CullTimeMax) + timeCull = PhysicsManager.CullTimeMax; + + CullCounter = (short)(distanceCull + timeCull); + } + + } + } else { + LastCollidedFrame = LockstepManager.FrameCount; } } else { if (Body1.PartitionChanged || Body2.PartitionChanged) { diff --git a/Core/Simulation/Physics/Core/LSBody.cs b/Core/Simulation/Physics/Core/LSBody.cs index d0d466e4..7e1f9781 100755 --- a/Core/Simulation/Physics/Core/LSBody.cs +++ b/Core/Simulation/Physics/Core/LSBody.cs @@ -28,6 +28,10 @@ public partial class LSBody [SerializeField] public Vector2d _velocity; + //TODO: Account for teleports when culling. + /// + /// Used to prevent distance culling for very large objects. + /// [SerializeField, Tooltip ("Useful for fast-moving objects that might pass through if not checked for a frame.")] private bool _preventCulling = false; #endregion @@ -275,6 +279,10 @@ internal void NotifyContact(LSBody other, bool isColliding, bool isChanged) [SerializeField, FixedNumber] protected long _radius = FixedMath.Half; + /// + /// Gets the bounding circle radius. + /// + /// The radius. public long Radius { get { return _radius; } } [SerializeField] @@ -386,12 +394,7 @@ public void GenerateBounds() if (Shape == ColliderType.Circle) { _radius = Radius; } else if (Shape == ColliderType.AABox) { - if (HalfHeight == HalfWidth) { - _radius = FixedMath.Sqrt((HalfHeight * HalfHeight * 2) >> FixedMath.SHIFT_AMOUNT); - } else { - _radius = FixedMath.Sqrt((HalfHeight * HalfHeight + HalfWidth * HalfWidth) >> FixedMath.SHIFT_AMOUNT); - } - + _radius = FixedMath.Sqrt((HalfHeight * HalfHeight + HalfWidth * HalfWidth) >> FixedMath.SHIFT_AMOUNT); } else if (Shape == ColliderType.Polygon) { long BiggestSqrRadius = Vertices[0].SqrMagnitude(); for (int i = 1; i < Vertices.Length; i++) { @@ -472,6 +475,8 @@ public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDy velocityPosition = Vector3.zero; this.ImmovableCollisionDirection = Vector2d.zero; PartitionChanged = true; + + } void CheckVariables() diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index 2aef7a71..0a89581b 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -20,10 +20,19 @@ public static class PhysicsManager public const bool SimulatePhysics = true; + #region Culling //After a certain amount of frames have passed without collision, culling frequency will increase - internal const long CullFrequencyStep = FixedMath.One * 2; + //Currently scales to have BlockSize result in CulFrequencyMax + internal const long CullDistanceStep = + (((Partition.BlockSize + FixedMath.One) * (Partition.BlockSize + FixedMath.One)) >> FixedMath.SHIFT_AMOUNT) + / CullDistanceMax; //Maximum amount of frames to wait between checks - internal const int CullFrequencyMax = LockstepManager.FrameRate / 2; + internal const int CullDistanceMax = LockstepManager.FrameRate / 2; + internal const long CullFastDistanceMax = (FixedMath.One * 4) * (FixedMath.One * 4); + + internal const int CullTimeStep = LockstepManager.FrameRate / 8; + internal const int CullTimeMax = LockstepManager.FrameRate / 8; + #endregion static int _cullDistributor; internal static int CullDistributor { @@ -176,7 +185,6 @@ public InstanceCollisionPair(ushort version, CollisionPair pair) public static void LateSimulate() { //TODO: Look into this - //8 seconds before turning off int inactiveFrameThreshold = LockstepManager.FrameRate * 8; @@ -186,47 +194,33 @@ public static void LateSimulate() var pair = RanCollisionPairs[i].Pair; if (instancePair.Version != instancePair.Pair._Version) { - RanCollisionPairs.RemoveAt(i); - pair._ranIndex = -1; - + //pair is removed at Deactivate so no longer possible } else { - if (pair.LastFrame == LockstepManager.FrameCount) { - - } else if (pair._ranIndex >= 0) { -#if false - if (!RanCollisionPairs.SafeRemoveAt(pair._ranIndex, instancePair)) - { - Debug.Log("Removal Failed"); - } -#else + if (pair._ranIndex >= 0) { RanCollisionPairs.RemoveAt(pair._ranIndex); -#endif - pair._ranIndex = -1; - InactiveCollisionPairs.Add(instancePair); } } } } + //Clear the buffer of collision pairs to turn off and pool while (InactiveCollisionPairs.Count > 0) { var instancePair = InactiveCollisionPairs.Peek(); var pair = instancePair.Pair; - if (instancePair.Version != pair._Version) { + + if (pair.Active) { + //It's active again! Get it out of inactives and move on to the next guy. InactiveCollisionPairs.Remove(); + } + + var passedFrames = LockstepManager.FrameCount - pair.LastFrame; + if (passedFrames >= inactiveFrameThreshold) { + InactiveCollisionPairs.Remove (); + FullDeactivateCollisionPair (pair); } else { - int dif = LockstepManager.FrameCount - pair.LastFrame; - if (dif == 0) { - InactiveCollisionPairs.Remove(); - } else { - if (dif >= inactiveFrameThreshold) { - FullDeactivateCollisionPair(pair); - InactiveCollisionPairs.Remove(); - } else { - break; - } - } + break; } } From 74d74204be7e12104d621265899468b5d8e39c80 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 20:33:20 -1000 Subject: [PATCH 08/15] Fix CullTimeStep value and tweaks; --- Core/Simulation/Physics/Core/CollisionPair.cs | 20 +++++++++---------- .../Simulation/Physics/Core/PhysicsManager.cs | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index d6194c27..408e3cec 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -292,22 +292,20 @@ public void CheckAndDistributeCollision () if (PreventDistanceCull) { CullCounter = (short)( (LockstepManager.FrameCount - LastCollidedFrame) / PhysicsManager.CullTimeStep); + if (CullCounter > PhysicsManager.CullTimeMax) + CullCounter = PhysicsManager.CullTimeMax; } else { //Set number of frames until next collision check based on distance - var distanceCull = ( + CullCounter = (short)( ((FastDistance - FastCollideDistance) >> FixedMath.SHIFT_AMOUNT) / PhysicsManager.CullDistanceStep + PhysicsManager.CullDistributor ); - if (distanceCull > PhysicsManager.CullDistanceMax) - distanceCull = PhysicsManager.CullDistanceMax; - if (distanceCull < 0) - distanceCull = 0; - - var timeCull = (LockstepManager.FrameCount - LastCollidedFrame) / PhysicsManager.CullTimeStep; - if (timeCull > PhysicsManager.CullTimeMax) - timeCull = PhysicsManager.CullTimeMax; - - CullCounter = (short)(distanceCull + timeCull); + if (CullCounter > PhysicsManager.CullDistanceMax) + CullCounter = PhysicsManager.CullDistanceMax; + if (CullCounter < 0) + CullCounter = 0; + + } diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index 0a89581b..0bb304cb 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -30,7 +30,7 @@ public static class PhysicsManager internal const int CullDistanceMax = LockstepManager.FrameRate / 2; internal const long CullFastDistanceMax = (FixedMath.One * 4) * (FixedMath.One * 4); - internal const int CullTimeStep = LockstepManager.FrameRate / 8; + internal const int CullTimeStep = LockstepManager.FrameRate * 8; internal const int CullTimeMax = LockstepManager.FrameRate / 8; #endregion From 06c9a8400b201a48741b81e923eb3ff85e1ac6e9 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 21:15:06 -1000 Subject: [PATCH 09/15] Optimize partition settings; --- Core/Simulation/Physics/Core/Partition.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Simulation/Physics/Core/Partition.cs b/Core/Simulation/Physics/Core/Partition.cs index c67e4ffd..833dd7bc 100644 --- a/Core/Simulation/Physics/Core/Partition.cs +++ b/Core/Simulation/Physics/Core/Partition.cs @@ -14,8 +14,8 @@ namespace Lockstep public static class Partition { #region Settings - public const int DefaultCount = 512; - public const int AdditionalShiftSize = 4; + public const int DefaultCount = 256; + public const int AdditionalShiftSize = 3; public const int ShiftSize = FixedMath.SHIFT_AMOUNT + AdditionalShiftSize; public const long BlockSize = 1L << ShiftSize; public static int BoundX { get; private set; } //Lower bound X From 197fed7149d66c15f97212e351f7e4b56edc01f0 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Sat, 2 Jun 2018 21:15:21 -1000 Subject: [PATCH 10/15] Fix and tweak CollisionPair culling; --- Core/Simulation/Physics/Core/CollisionPair.cs | 24 ++++++++++++------- Core/Simulation/Physics/Core/LSBody.cs | 1 - .../Simulation/Physics/Core/PhysicsManager.cs | 8 +++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 408e3cec..87c032e3 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -26,6 +26,7 @@ public class CollisionPair internal short CullCounter; internal bool PreventDistanceCull; internal int LastCollidedFrame; + private long FastDistanceOffset; public bool _isColliding; @@ -124,6 +125,9 @@ public void Initialize (LSBody b1, LSBody b2) CullCounter = 0; //If collision distance is too large, don't cull based on distance PreventDistanceCull = FastCollideDistance > PhysicsManager.CullFastDistanceMax; + LastCollidedFrame = LockstepManager.FrameCount; + FastDistanceOffset = FixedMath.Sqrt (FastCollideDistance >> FixedMath.SHIFT_AMOUNT) + FixedMath.One * 2; + FastDistanceOffset *= FastDistanceOffset; } Active = true; _Version++; @@ -259,11 +263,10 @@ void DistributeCircle_Poly (LSBody circle, LSBody poly) public void CheckAndDistributeCollision () { + if (!Active) { return; } - - if (_ranIndex < 0) { _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); } @@ -296,19 +299,22 @@ public void CheckAndDistributeCollision () CullCounter = PhysicsManager.CullTimeMax; } else { //Set number of frames until next collision check based on distance - CullCounter = (short)( - ((FastDistance - FastCollideDistance) >> FixedMath.SHIFT_AMOUNT) + var distCull = ( + ((FastDistance - FastDistanceOffset) >> FixedMath.SHIFT_AMOUNT) / PhysicsManager.CullDistanceStep + PhysicsManager.CullDistributor ); - if (CullCounter > PhysicsManager.CullDistanceMax) - CullCounter = PhysicsManager.CullDistanceMax; - if (CullCounter < 0) - CullCounter = 0; + if (distCull > PhysicsManager.CullDistanceMax) + distCull = PhysicsManager.CullDistanceMax; + if (distCull < 0) + distCull = 0; + var timeCull = (LockstepManager.FrameCount - LastCollidedFrame) / PhysicsManager.CullTimeStep; + if (timeCull > PhysicsManager.CullTimeMax) + timeCull = PhysicsManager.CullTimeMax; + CullCounter = (short)(timeCull + distCull); } - } } else { LastCollidedFrame = LockstepManager.FrameCount; diff --git a/Core/Simulation/Physics/Core/LSBody.cs b/Core/Simulation/Physics/Core/LSBody.cs index 7e1f9781..5b8b1679 100755 --- a/Core/Simulation/Physics/Core/LSBody.cs +++ b/Core/Simulation/Physics/Core/LSBody.cs @@ -556,7 +556,6 @@ public void BuildBounds() public void Simulate() { - if (VelocityChanged) { VelocityMagnitude = _velocity.Magnitude(); diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index 0bb304cb..08c05463 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -24,14 +24,14 @@ public static class PhysicsManager //After a certain amount of frames have passed without collision, culling frequency will increase //Currently scales to have BlockSize result in CulFrequencyMax internal const long CullDistanceStep = - (((Partition.BlockSize + FixedMath.One) * (Partition.BlockSize + FixedMath.One)) >> FixedMath.SHIFT_AMOUNT) + (((Partition.BlockSize + FixedMath.One * 2) * (Partition.BlockSize + FixedMath.One * 2)) >> FixedMath.SHIFT_AMOUNT) / CullDistanceMax; //Maximum amount of frames to wait between checks - internal const int CullDistanceMax = LockstepManager.FrameRate / 2; + internal const int CullDistanceMax = LockstepManager.FrameRate / 3; internal const long CullFastDistanceMax = (FixedMath.One * 4) * (FixedMath.One * 4); - internal const int CullTimeStep = LockstepManager.FrameRate * 8; - internal const int CullTimeMax = LockstepManager.FrameRate / 8; + internal const int CullTimeStep = LockstepManager.FrameRate * 3; + internal const int CullTimeMax = LockstepManager.FrameRate / 5; #endregion static int _cullDistributor; From fd358ad8d897f7fa22bd1932432430e121a1d6df Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Wed, 6 Jun 2018 21:17:40 -1000 Subject: [PATCH 11/15] Hide timescaledDecelleration value --- Core/Game/Abilities/Essential/Move.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Game/Abilities/Essential/Move.cs b/Core/Game/Abilities/Essential/Move.cs index 7aeed8d5..f8809ee1 100644 --- a/Core/Game/Abilities/Essential/Move.cs +++ b/Core/Game/Abilities/Essential/Move.cs @@ -113,7 +113,7 @@ public void StartLookingForStopPause () { public Vector2d AveragePosition { get; set; } private long timescaledAcceleration; - public long timescaledDecceleration; + private long timescaledDecceleration; bool decellerating; private Vector2d lastTargetPos; From 5c26c60f892c70c399f37d5de1831c3a569f86cd Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Wed, 6 Jun 2018 21:18:07 -1000 Subject: [PATCH 12/15] Add CanMove check --- Core/Game/Abilities/Essential/Scan.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/Game/Abilities/Essential/Scan.cs b/Core/Game/Abilities/Essential/Scan.cs index 3696621f..ccf80045 100644 --- a/Core/Game/Abilities/Essential/Scan.cs +++ b/Core/Game/Abilities/Essential/Scan.cs @@ -516,6 +516,7 @@ public void Engage (LSAgent other) fastRangeToTarget *= fastRangeToTarget; if (!CheckRange ()) { + if (CanMove) cachedMove.StartMove (Target.Body.Position); } } From 66ee8273fd6969c7471e860e3594ea661a398bfd Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Wed, 6 Jun 2018 21:23:23 -1000 Subject: [PATCH 13/15] Implement GhostLSBody system for bodies that can't affect simulation. This feature allows combining position-syncing with LS for objects that need high responsiveness. --- Core/Game/Agents/LSAgent.cs | 5 +- Core/Game/Player/Visuals/Materials.meta | 9 ++ Core/Simulation/Math/Vector2d.cs | 26 +++++ Core/Simulation/Physics/Core/CollisionPair.cs | 85 +++++++------- Core/Simulation/Physics/Core/LSBody.cs | 60 ++++++---- Core/Simulation/Physics/Core/Partition.cs | 12 +- .../Simulation/Physics/Core/PhysicsManager.cs | 13 +-- Core/Simulation/Physics/Ghost.meta | 9 ++ Core/Simulation/Physics/Ghost/Editor.meta | 9 ++ .../{Core => Ghost}/Editor/EditorLSBody.cs | 24 ++-- .../Editor/EditorLSBody.cs.meta | 0 Core/Simulation/Physics/Ghost/GhostLSBody.cs | 16 +++ .../Physics/Ghost/GhostLSBody.cs.meta | 12 ++ .../Physics/Ghost/GhostPhysicsManager.cs | 104 ++++++++++++++++++ .../Physics/Ghost/GhostPhysicsManager.cs.meta | 12 ++ .../Physics/Ghost/UnityGhostLSBody.cs | 23 ++++ .../Physics/Ghost/UnityGhostLSBody.cs.meta | 12 ++ .../FastCollections-master/FastList.cs | 10 ++ Example/Scripts/DefaultNetworkHelper.cs | 5 +- 19 files changed, 363 insertions(+), 83 deletions(-) create mode 100644 Core/Game/Player/Visuals/Materials.meta create mode 100644 Core/Simulation/Physics/Ghost.meta create mode 100644 Core/Simulation/Physics/Ghost/Editor.meta rename Core/Simulation/Physics/{Core => Ghost}/Editor/EditorLSBody.cs (96%) rename Core/Simulation/Physics/{Core => Ghost}/Editor/EditorLSBody.cs.meta (100%) mode change 100755 => 100644 create mode 100644 Core/Simulation/Physics/Ghost/GhostLSBody.cs create mode 100644 Core/Simulation/Physics/Ghost/GhostLSBody.cs.meta create mode 100644 Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs create mode 100644 Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs.meta create mode 100644 Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs create mode 100644 Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs.meta diff --git a/Core/Game/Agents/LSAgent.cs b/Core/Game/Agents/LSAgent.cs index b5d9d91d..50c6c502 100644 --- a/Core/Game/Agents/LSAgent.cs +++ b/Core/Game/Agents/LSAgent.cs @@ -523,7 +523,7 @@ public void SetState(AnimState animState) Animator.CurrentAnimState = animState; } } - + public void ApplyImpulse(AnimImpulse animImpulse, int rate = 0) { if (Animator.IsNotNull()) @@ -557,7 +557,8 @@ private void LoadComponents() { _cachedTransform = base.transform; _cachedGameObject = base.gameObject; - _unityBody = GetComponent(); + //TODO: Ensure that this isn't GhostLSBody or any other bodies attached to the GO + _unityBody = GetComponent (); _animator = GetComponent(); _attachedAbilities = GetComponents(); } diff --git a/Core/Game/Player/Visuals/Materials.meta b/Core/Game/Player/Visuals/Materials.meta new file mode 100644 index 00000000..10ff91e1 --- /dev/null +++ b/Core/Game/Player/Visuals/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 23eff8b45829aee43bd9d31492a6850f +folderAsset: yes +timeCreated: 1522128042 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Simulation/Math/Vector2d.cs b/Core/Simulation/Math/Vector2d.cs index 32bf5aea..4ec139f7 100755 --- a/Core/Simulation/Math/Vector2d.cs +++ b/Core/Simulation/Math/Vector2d.cs @@ -339,7 +339,33 @@ public bool NotZero() { return x.MoreThanEpsilon() || y.MoreThanEpsilon(); } + public void ClampMagnitude (long min, long max) { + long mag = this.FastMagnitude (); + long fastMin; + long fastMax; + long normal; + //Check if normalization is needed and if so, set scale to normalize to + if (mag < (fastMin = min * min)) { + normal = fastMin; + } else if (mag > (fastMax = max * max)) { + normal = fastMax; + } else { + return; + } + mag = FixedMath.Sqrt (mag >> FixedMath.SHIFT_AMOUNT); + + if (mag.MoreThanEpsilon ()) { + //convert from fast multiplied value + normal = FixedMath.Sqrt(normal >> FixedMath.SHIFT_AMOUNT); + //Shift unneeded as fixed fraction canceled through mul then div + x = x * normal / mag; + y = y * normal / mag; + } else { + x = 0; + y = 0; + } + } #endregion #region Static Math diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 87c032e3..e2bf4e2d 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -49,6 +49,9 @@ public bool IsColliding { bool IsValid { get; set; } + //Used for ghost body collisions + internal static bool OnlyAffectBody1 { get; set; } + public void Initialize (LSBody b1, LSBody b2) { @@ -56,14 +59,20 @@ public void Initialize (LSBody b1, LSBody b2) if (!IsValid) return; - if (b1.ID < b2.ID) { + if (OnlyAffectBody1) { Body1 = b1; Body2 = b2; - } else { - Body1 = b2; - Body2 = b1; } - + else { + if (b1.ID < b2.ID) { + Body1 = b1; + Body2 = b2; + } else { + Body1 = b2; + Body2 = b1; + } + } + _ranIndex = -1; _isColliding = false; @@ -75,7 +84,6 @@ public void Initialize (LSBody b1, LSBody b2) FastCollideDistance = b1.Radius + b2.Radius; FastCollideDistance *= FastCollideDistance; - LeCollisionType = CollisionType.None; if (Body1.Shape == ColliderType.None || Body2.Shape == ColliderType.None) { } else if (Body1.Shape == ColliderType.Circle) { @@ -148,54 +156,50 @@ public void Deactivate () static long dist, depth; + private void DistributeCollision () { if (!DoPhysics) return; - switch (LeCollisionType) { case CollisionType.Circle_Circle: DistX = Body1._position.x - Body2._position.x; DistY = Body1._position.y - Body2._position.y; dist = FixedMath.Sqrt ((DistX * DistX + DistY * DistY) >> FixedMath.SHIFT_AMOUNT); - if (dist == 0) { + if (dist == 0 && DistY == 0) { //If objects are on the same position, give them push in random direction const long randomMax = FixedMath.One / 32; - Body1._position.x += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - Body1._position.y += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - Body1.PositionChanged = true; - Body2._position.x += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - Body2._position.y += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - Body2.PositionChanged = true; + DistX += LSUtility.GetRandomLong (randomMax) - randomMax / 2; + DistY += LSUtility.GetRandomLong (randomMax) - randomMax / 2; return; } - - depth = (Body1.Radius + Body2.Radius - dist); + DistX = (DistX * depth / dist); + DistY = (DistY * depth / dist); if (depth <= 0) { return; } - DistX = (DistX * depth / dist); - DistY = (DistY * depth / dist); - //Resolving collision - - + //Note: Immovable bodies don't check collision against each other so this case doesn't need to be considered if (Body1.Immovable || (Body2.Immovable == false && Body1.Priority > Body2.Priority)) { + //Invert adjustment values when Body2 is being moved DistX *= -1; DistY *= -1; DistributeCircle_CirclePriority (Body1, Body2); - } else if (Body2.Immovable || Body2.Priority > Body1.Priority) { - DistributeCircle_CirclePriority (Body2, Body1); } else { - DistX /= 2; - DistY /= 2; - DistributeCircle (Body1); - DistX *= -1; - DistY *= -1; - DistributeCircle (Body2); + if (OnlyAffectBody1) return; + if (Body2.Immovable || Body2.Priority > Body1.Priority) { + DistributeCircle_CirclePriority (Body2, Body1); + } else { + DistX /= 2; + DistY /= 2; + DistributeCircle (Body1); + DistX *= -1; + DistY *= -1; + DistributeCircle (Body2); + } } break; case CollisionType.Circle_AABox: @@ -216,7 +220,7 @@ private void DistributeCollision () } } - void DistributeCircle_CirclePriority (LSBody higherPriority, LSBody lowerPriority) + internal void DistributeCircle_CirclePriority (LSBody higherPriority, LSBody lowerPriority) { @@ -260,7 +264,12 @@ void DistributeCircle_Poly (LSBody circle, LSBody poly) } public int _ranIndex; - + /// + /// Used for GhostLSBodies + /// + internal void NotifyBody1 () { + Body1.NotifyContact (Body2, IsColliding, IsCollidingChanged); + } public void CheckAndDistributeCollision () { @@ -332,12 +341,12 @@ public void CheckAndDistributeCollision () } - public bool CheckHeight () + internal bool CheckHeight () { return Body1.HeightMax >= Body2.HeightMin && Body1.HeightMin <= Body2.HeightMax; } - public bool CheckCollision () + internal bool CheckCollision () { if (!Body1.PositionChangedBuffer && !Body2.PositionChangedBuffer && !Body1.RotationChangedBuffer && !Body2.RotationChangedBuffer) { return IsColliding; @@ -450,8 +459,8 @@ public bool CheckCollision () return false; } - private void GenerateCircleValues () { - DistX = Body1._position.x - Body2._position.x; + internal void GenerateCircleValues () { + if (Body1 == null || Body2 == null) DistY = Body1._position.y - Body2._position.y; FastDistance = DistX * DistX + DistY * DistY; } @@ -621,7 +630,7 @@ private void DistributeCircle_Box (LSBody box, LSBody circle) circle.BuildBounds (); } - public static bool CheckCircle_Box (LSBody box, LSBody circle) + internal static bool CheckCircle_Box (LSBody box, LSBody circle) { Collided = false; @@ -670,7 +679,7 @@ public static bool CheckCircle_Box (LSBody box, LSBody circle) return Collided; } - public static bool CheckPoly_Poly (LSBody poly1, LSBody poly2) + internal static bool CheckPoly_Poly (LSBody poly1, LSBody poly2) { int Poly1EdgeCount = poly1.EdgeNorms.Length; int EdgeCount = Poly1EdgeCount + poly2.EdgeNorms.Length; @@ -694,7 +703,7 @@ public static bool CheckPoly_Poly (LSBody poly1, LSBody poly2) return true; } - public static void ProjectPolygon (long AxisX, long AxisY, LSBody Poly, out long Min, out long Max) + internal static void ProjectPolygon (long AxisX, long AxisY, LSBody Poly, out long Min, out long Max) { Min = Poly.RealPoints [0].Dot (AxisX, AxisY); Max = Min; diff --git a/Core/Simulation/Physics/Core/LSBody.cs b/Core/Simulation/Physics/Core/LSBody.cs index 5b8b1679..7ead5f3b 100755 --- a/Core/Simulation/Physics/Core/LSBody.cs +++ b/Core/Simulation/Physics/Core/LSBody.cs @@ -206,6 +206,7 @@ private void RemoveChild(LSBody child) /// /// TODO: Do away with CollisionPairs? Just dynamically collide... much easier and less memory for mobile. /// Potentially faster especially for less physics objects. + /// E: No longer possible as frame culling is now implemented. /// internal Dictionary CollisionPairs { get { @@ -213,6 +214,7 @@ internal Dictionary CollisionPairs { } } + //TODO: Make this a more efficient collection internal HashSet CollisionPairHolders { get { return _collisionPairHolders ?? (_collisionPairHolders = new HashSet()); @@ -257,22 +259,22 @@ internal void NotifyContact(LSBody other, bool isColliding, bool isChanged) public ColliderType Shape { get { return _shape; } } [SerializeField] - private bool _isTrigger; + protected bool _isTrigger; public bool IsTrigger { get { return _isTrigger; } } [SerializeField] - private int _layer; + protected int _layer; public int Layer { get { return _layer; } } [SerializeField, FixedNumber] - private long _halfWidth = FixedMath.Half; + protected long _halfWidth = FixedMath.Half; public long HalfWidth { get { return _halfWidth; } } [SerializeField, FixedNumber] - public long _halfHeight = FixedMath.Half; + protected long _halfHeight = FixedMath.Half; public long HalfHeight { get { return _halfHeight; } } @@ -294,29 +296,29 @@ public bool GetSavedImmovable () { public bool Immovable { get; private set; } [SerializeField] - private int _basePriority; + protected int _basePriority; public int BasePriority { get { return _basePriority; } } [SerializeField] - private Vector2d[] _vertices; + protected Vector2d[] _vertices; public Vector2d[] Vertices { get { return _vertices; } } [SerializeField, FixedNumber] - private long _height = FixedMath.One; + protected long _height = FixedMath.One; public long Height { get { return _height; } } [SerializeField] - private Transform _positionalTransform; + protected Transform _positionalTransform; public Transform PositionalTransform { get; set; } [SerializeField] - private Transform _rotationalTransform; + protected Transform _rotationalTransform; public Transform RotationalTransform { get; set; } @@ -407,9 +409,15 @@ public void GenerateBounds() FastRadius = this.Radius * this.Radius; } } + public virtual void Initialize (Vector3d StartPosition, Vector2d StartRotation, bool isDynamic = true) { + InitializeVariables (StartPosition, StartRotation, isDynamic); + ID = PhysicsManager.Assimilate(this, isDynamic); + Partition.PartitionObject(this); + } - public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDynamic = true) + public void InitializeVariables(Vector3d StartPosition, Vector2d StartRotation, bool isDynamic = true) { + //TODO: Ensure that this function does not affect any simulation system so that "ghost" bodies can be made Active = true; PositionalTransform = _positionalTransform; RotationalTransform = _rotationalTransform; @@ -442,7 +450,6 @@ public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDy YMin = 0; YMax = 0; - PastGridXMin = int.MaxValue; PastGridXMax = int.MaxValue; PastGridYMin = int.MaxValue; @@ -453,8 +460,7 @@ public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDy BuildBounds(); } - ID = PhysicsManager.Assimilate(this, isDynamic); - Partition.PartitionObject(this); + if (PositionalTransform != null) { CanSetVisualPosition = true; _visualPosition = _position.ToVector3(HeightPos.ToFloat()); @@ -471,14 +477,15 @@ public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDy } else { CanSetVisualRotation = false; } - SetVisuals (); velocityPosition = Vector3.zero; this.ImmovableCollisionDirection = Vector2d.zero; PartitionChanged = true; - + SetVisuals (); } + + void CheckVariables() { @@ -552,10 +559,8 @@ public void BuildBounds() } } } - - - public void Simulate() - { + #region Moddability + public void _SimVelocity () { if (VelocityChanged) { VelocityMagnitude = _velocity.Magnitude(); @@ -570,6 +575,17 @@ public void Simulate() _position.y += _velocity.y / LockstepManager.FrameRate; PositionChanged = true; } + } + public void _SimVisualsCounter () { + if (SettingVisuals) { + _settingVisualsCounter--; + } + } + #endregion + + public void Simulate() + { + _SimVelocity (); BuildChangedValues(); @@ -579,16 +595,14 @@ public void Simulate() Partition.UpdateObject(this); } - if (SettingVisuals) { - _settingVisualsCounter--; - } + _SimVisualsCounter (); } Quaternion GetVisualRot () { return Quaternion.LookRotation (Forward.ToVector3 (0)); } - void BuildChangedValues() + public void BuildChangedValues() { if (PositionChanged || RotationChanged) { diff --git a/Core/Simulation/Physics/Core/Partition.cs b/Core/Simulation/Physics/Core/Partition.cs index 833dd7bc..82ff0bdb 100644 --- a/Core/Simulation/Physics/Core/Partition.cs +++ b/Core/Simulation/Physics/Core/Partition.cs @@ -58,9 +58,7 @@ public static void Deactivate () public static void UpdateObject (LSBody Body, bool repartition = true) { - GetGridBounds (Body); - if ( repartition == false || (Body.PastGridXMin != GridXMin || @@ -82,7 +80,16 @@ public static void UpdateObject (LSBody Body, bool repartition = true) if (repartition) { PartitionObject (Body, true); } + } + } + public static void GetTouchingPartitions (LSBody Body, FastList output) { + GetGridBounds (Body); + for (int i = GridXMin; i <= GridXMax; i++) { + for (int j = GridYMin; j <= GridYMax; j++) { + PartitionNode node = GetNode (i, j); + output.Add (node); + } } } @@ -140,6 +147,7 @@ static int ClampY (int gridY) { public static void PartitionObject (LSBody Body, bool gridBoundsCalculated = false) { + //TODO: Ensure that bodies are partitioned accurately if (gridBoundsCalculated == false) GetGridBounds (Body); diff --git a/Core/Simulation/Physics/Core/PhysicsManager.cs b/Core/Simulation/Physics/Core/PhysicsManager.cs index 08c05463..958b50a1 100644 --- a/Core/Simulation/Physics/Core/PhysicsManager.cs +++ b/Core/Simulation/Physics/Core/PhysicsManager.cs @@ -184,9 +184,8 @@ public InstanceCollisionPair(ushort version, CollisionPair pair) public static bool ResetAccumulation {get; private set;} public static void LateSimulate() { - //TODO: Look into this - int inactiveFrameThreshold = LockstepManager.FrameRate * 8; - + + int inactiveFrameThreshold = LockstepManager.FrameRate * 1; for (int i = 0; i < RanCollisionPairs.PeakCount; i++) { if (RanCollisionPairs.arrayAllocation[i]) { @@ -294,13 +293,13 @@ internal static int Assimilate(LSBody body, bool isDynamic) return id; } - private static FastStack CachedCollisionPairs = new FastStack(); + private static FastStack PooledCollisionPairs = new FastStack(); private static CollisionPair CreatePair(LSBody body1, LSBody body2) { CollisionPair pair; - if (CachedCollisionPairs.Count > 0) { - pair = CachedCollisionPairs.Pop(); + if (PooledCollisionPairs.Count > 0) { + pair = PooledCollisionPairs.Pop(); } else { pair = new CollisionPair(); } @@ -337,7 +336,7 @@ public static void PoolPair(CollisionPair pair) { pair.Deactivate(); if (LockstepManager.PoolingEnabled) - CachedCollisionPairs.Add(pair); + PooledCollisionPairs.Add(pair); } internal static void Dessimilate(LSBody body) diff --git a/Core/Simulation/Physics/Ghost.meta b/Core/Simulation/Physics/Ghost.meta new file mode 100644 index 00000000..266acbed --- /dev/null +++ b/Core/Simulation/Physics/Ghost.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ad7a265f0a3fa644685147acc61e4322 +folderAsset: yes +timeCreated: 1528348534 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Simulation/Physics/Ghost/Editor.meta b/Core/Simulation/Physics/Ghost/Editor.meta new file mode 100644 index 00000000..ac7cbdbd --- /dev/null +++ b/Core/Simulation/Physics/Ghost/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6c3dd7f68ba3e4848bd1eb85e9d783bb +folderAsset: yes +timeCreated: 1528354244 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Simulation/Physics/Core/Editor/EditorLSBody.cs b/Core/Simulation/Physics/Ghost/Editor/EditorLSBody.cs similarity index 96% rename from Core/Simulation/Physics/Core/Editor/EditorLSBody.cs rename to Core/Simulation/Physics/Ghost/Editor/EditorLSBody.cs index 45be5523..7cda1fa8 100644 --- a/Core/Simulation/Physics/Core/Editor/EditorLSBody.cs +++ b/Core/Simulation/Physics/Ghost/Editor/EditorLSBody.cs @@ -2,11 +2,12 @@ using System.Collections; using FastCollections; using UnityEditor; using Lockstep; +using Lockstep.Extras; #if true -namespace Lockstep.Integration +namespace Lockstep.Extras.Integration { - [CustomEditor(typeof(UnityLSBody), true),UnityEditor.CanEditMultipleObjects] - public class EditorLSBody : Editor + [CustomEditor(typeof(UnityGhostLSBody), true),UnityEditor.CanEditMultipleObjects] + public class EditorGhostLSBody : Editor { SerializedProperty Shape; @@ -75,14 +76,19 @@ public override void OnInspectorGUI() { EditorGUI.BeginChangeCheck(); + //TODO: Implement + /* + if (GUILayout.Button ("Copy Main Body")) { + + }*/ if (GUILayout.Button("Reset Transforms")) { for (int i = 0; i < targets.Length; i++) { SerializedObject ser = new SerializedObject(targets [i]); - ser.FindProperty("_internalBody").FindPropertyRelative("_positionalTransform").objectReferenceValue = ((UnityLSBody)targets [i]).transform; - ser.FindProperty("_internalBody").FindPropertyRelative("_rotationalTransform").objectReferenceValue = ((UnityLSBody)targets [i]).transform; + ser.FindProperty("_internalBody").FindPropertyRelative("_positionalTransform").objectReferenceValue = ((UnityGhostLSBody)targets [i]).transform; + ser.FindProperty("_internalBody").FindPropertyRelative("_rotationalTransform").objectReferenceValue = ((UnityGhostLSBody)targets [i]).transform; ser.ApplyModifiedProperties(); } so.Update(); @@ -100,8 +106,8 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); EditorGUILayout.LabelField("General Collider Settings", EditorStyles.boldLabel); - Layer.Draw(); - BasePriority.Draw(); + //Automatically the lowest possible priority + //BasePriority.Draw(); IsTrigger.Draw(); if (IsTrigger.boolValue == false) Immovable.Draw(); @@ -166,8 +172,8 @@ void OnSceneGUI() if (shape == ColliderType.None) return; Handles.color = Color.blue; - LSBody Body = ((UnityLSBody)target).InternalBody; - Transform transform = ((UnityLSBody)target).transform; + LSBody Body = ((UnityGhostLSBody)target).InternalBody; + Transform transform = ((UnityGhostLSBody)target).transform; Vector3 targetPos = transform.position; const int ImprecisionLimit = 100000; if (Mathf.Abs(targetPos.x) >= ImprecisionLimit || diff --git a/Core/Simulation/Physics/Core/Editor/EditorLSBody.cs.meta b/Core/Simulation/Physics/Ghost/Editor/EditorLSBody.cs.meta old mode 100755 new mode 100644 similarity index 100% rename from Core/Simulation/Physics/Core/Editor/EditorLSBody.cs.meta rename to Core/Simulation/Physics/Ghost/Editor/EditorLSBody.cs.meta diff --git a/Core/Simulation/Physics/Ghost/GhostLSBody.cs b/Core/Simulation/Physics/Ghost/GhostLSBody.cs new file mode 100644 index 00000000..cfe83bc9 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/GhostLSBody.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using FastCollections; +namespace Lockstep.Extras { + [System.Serializable] + public class GhostLSBody : LSBody { + public void InitializeGhost (Vector3d StartPosition, Vector2d StartRotation, bool isDynamic = true) + { + InitializeVariables (StartPosition, StartRotation, isDynamic); + //Ensure this object does not modify the position of any other objects upon collision as it should not affect collision + this.Priority = int.MinValue; + GhostPhysicsManager.Instance.Assimilate (this); + } + } +} \ No newline at end of file diff --git a/Core/Simulation/Physics/Ghost/GhostLSBody.cs.meta b/Core/Simulation/Physics/Ghost/GhostLSBody.cs.meta new file mode 100644 index 00000000..42cb2d84 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/GhostLSBody.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 980bc61d016bf9446949c4a7d9c7f72b +timeCreated: 1528350575 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs new file mode 100644 index 00000000..85ec0cf5 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs @@ -0,0 +1,104 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using FastCollections; +using Lockstep; +namespace Lockstep.Extras { + /// + /// Managing bodies that don't affect simulation but can draw values (i.e. collisions) off simulation. + /// This is indeterministic and for visual/gameplay features. + /// + public class GhostPhysicsManager : BehaviourHelper { + public static GhostPhysicsManager Instance {get; private set;} + FastList GhostBodies; + protected override void OnInitialize () + { + Instance = this; + GhostBodies = new FastList (); + } + protected override void OnSimulate () + { + for (int i = 0; i < GhostBodies.Count; i++) { + var ghost = GhostBodies [i]; + GhostSimulateBody (ghost); + CheckCollisions (ghost); + } + bufferPartitionNodes.Clear (); + + } + protected override void OnVisualize () + { + for (int i = 0; i < GhostBodies.Count; i++) { + var ghost = GhostBodies [i]; + ghost.SetVisuals (); + } + } + + void GhostSimulateBody (GhostLSBody ghost) { + //Only simulate stuff that doesn't affect lockstep simulation + ghost._SimVelocity (); + ghost.BuildChangedValues(); + ghost._SimVisualsCounter (); + } + + FastList bufferPartitionNodes = new FastList(); + void CheckCollisions (GhostLSBody ghost) { + + bufferPartitionNodes.FastClear (); + Partition.GetTouchingPartitions (ghost, bufferPartitionNodes); + + //temporarily make collisions only affect body1 (the ghost) + CollisionPair.OnlyAffectBody1 = true; + for (int n = 0; n < bufferPartitionNodes.Count; n++) { + var node = bufferPartitionNodes [n]; + for (int i = 0; i < node.ContainedImmovableObjects.Count; i++) { + var id = node.ContainedImmovableObjects [i]; + ProcessPair (ghost, id); + } + for (int k = 0; k < node.ContainedImmovableObjects.Count; k++) { + var id = node.ContainedImmovableObjects [k]; + ProcessPair (ghost, id); + } + } + CollisionPair.OnlyAffectBody1 = false; + + } + void ProcessPair (GhostLSBody ghost, int ID2) { + var pair = GetCollisionPair (ghost, ID2); + if (pair == null) + return; + pair.GenerateCircleValues (); + if (pair.CheckHeight ()) { + bool result = pair.CheckCollision (); + + if (pair.CheckCollision ()) { + //Note: Ensure that ghost body is lower priority so it doesn't move the other body + //TODO: This is extremely dangerous. Should copy-paste functions be made to not allow room for desync? + pair.CheckAndDistributeCollision (); + } + } + pair.NotifyBody1 (); + + } + + private static CollisionPair GetCollisionPair (GhostLSBody ghost, int ID2) { + LSBody body2; + if ((body2 = PhysicsManager.SimObjects[ID2]).IsNotNull()) { + CollisionPair pair; + if (!ghost.CollisionPairs.TryGetValue(body2.ID, out pair)) { + pair = new CollisionPair (); + ghost.CollisionPairs.Add(body2.ID, pair); + pair.Initialize (ghost, body2); + //Don't modify simulation object + //body2.CollisionPairHolders.Add(body1.ID); + } + return pair; + } + return null; + } + public void Assimilate (GhostLSBody ghostBody) { + GhostBodies.Add (ghostBody); + } + + } +} \ No newline at end of file diff --git a/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs.meta b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs.meta new file mode 100644 index 00000000..e8c1fc33 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8f05c32141ce65e40917ef060412fa77 +timeCreated: 1528348541 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs b/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs new file mode 100644 index 00000000..bd80d133 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +namespace Lockstep.Extras { + public class UnityGhostLSBody : MonoBehaviour { + [SerializeField] + private GhostLSBody _internalBody; + public GhostLSBody InternalBody {get {return _internalBody ?? (_internalBody = new GhostLSBody());}} + public void Initialize(Vector3d StartPosition, Vector2d StartRotation, bool isDynamic = true) + { + if (_internalBody.IsNull()) + _internalBody = new GhostLSBody(); + InternalBody.InitializeGhost (StartPosition,StartRotation,isDynamic); + } + + void Reset () { + if (InternalBody.IsNull()) + _internalBody = new GhostLSBody(); + InternalBody.transform = this.transform; + InternalBody.Reset(); + } + } +} \ No newline at end of file diff --git a/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs.meta b/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs.meta new file mode 100644 index 00000000..c3198ae7 --- /dev/null +++ b/Core/Simulation/Physics/Ghost/UnityGhostLSBody.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 997322f5cb8501a47b8800fba3d97462 +timeCreated: 1528350663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Core/Utility/FastCollections-master/FastList.cs b/Core/Utility/FastCollections-master/FastList.cs index 2e32ce08..6cfc88d9 100644 --- a/Core/Utility/FastCollections-master/FastList.cs +++ b/Core/Utility/FastCollections-master/FastList.cs @@ -59,6 +59,16 @@ public void Add (T item) } + /// + /// Overwrites item at index or expands list with null items until index is valid. + /// + /// Item. + /// Index. + public void AddAt (T item, int index) { + EnsureCapacity (index + 1); + this [index] = item; + } + public void AddRange (FastList items) { int arrayLength = items.Count; diff --git a/Example/Scripts/DefaultNetworkHelper.cs b/Example/Scripts/DefaultNetworkHelper.cs index 6106be10..4257ad30 100644 --- a/Example/Scripts/DefaultNetworkHelper.cs +++ b/Example/Scripts/DefaultNetworkHelper.cs @@ -62,7 +62,7 @@ protected override void OnSendMessageToAll (MessageType messageType, byte [] dat } } - void Update () + void LateUpdate () { if (SimulateLag == false) return; @@ -78,11 +78,12 @@ void Update () return;*/ for (int i = 0; i < Packets.Count; i++) { var packet = Packets [i]; - packet.TimeTillArrival -= Time.unscaledDeltaTime * 1000d; + packet.TimeTillArrival -= Time.unscaledDeltaTime * 1d; if (packet.TimeTillArrival <= 0) { base.OnSendMessageToAll (packet.MessageType, packet.Data); Packets.RemoveAt (i); i--; + } else { Packets [i] = packet; } From 91821a64d8dd7ebac0bcbb98ffea9b432885f1cf Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Thu, 7 Jun 2018 15:11:45 -1000 Subject: [PATCH 14/15] Remove obsolete random - replaced with PositionCycler; --- Core/Simulation/Physics/Core/CollisionPair.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index e2bf4e2d..033e46b0 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -167,13 +167,6 @@ private void DistributeCollision () DistY = Body1._position.y - Body2._position.y; dist = FixedMath.Sqrt ((DistX * DistX + DistY * DistY) >> FixedMath.SHIFT_AMOUNT); - if (dist == 0 && DistY == 0) { - //If objects are on the same position, give them push in random direction - const long randomMax = FixedMath.One / 32; - DistX += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - DistY += LSUtility.GetRandomLong (randomMax) - randomMax / 2; - return; - } depth = (Body1.Radius + Body2.Radius - dist); DistX = (DistX * depth / dist); From c06f6eee757d525c725353ae49fafd0fde184325 Mon Sep 17 00:00:00 2001 From: jpthek9 Date: Thu, 7 Jun 2018 16:08:34 -1000 Subject: [PATCH 15/15] Fix and improve CollisionPair and GhostPhysics systems Add null check; --- Core/Simulation/Grid/Core/GridNode.cs | 3 ++ Core/Simulation/Physics/Core/CollisionPair.cs | 32 +++++++++++-------- Core/Simulation/Physics/Core/Editor.meta | 9 ------ .../Physics/Ghost/GhostPhysicsManager.cs | 12 ++----- 4 files changed, 24 insertions(+), 32 deletions(-) delete mode 100644 Core/Simulation/Physics/Core/Editor.meta diff --git a/Core/Simulation/Grid/Core/GridNode.cs b/Core/Simulation/Grid/Core/GridNode.cs index 7d1aad67..0442564e 100755 --- a/Core/Simulation/Grid/Core/GridNode.cs +++ b/Core/Simulation/Grid/Core/GridNode.cs @@ -346,11 +346,14 @@ public void CalculateHeuristic () public void Add (LSInfluencer influencer) { + if (LinkedScanNode != null) LinkedScanNode.Add (influencer); } public void Remove (LSInfluencer influencer) { + if (LinkedScanNode != null) + LinkedScanNode.Remove (influencer); } diff --git a/Core/Simulation/Physics/Core/CollisionPair.cs b/Core/Simulation/Physics/Core/CollisionPair.cs index 033e46b0..85257fa5 100644 --- a/Core/Simulation/Physics/Core/CollisionPair.cs +++ b/Core/Simulation/Physics/Core/CollisionPair.cs @@ -157,23 +157,26 @@ public void Deactivate () static long dist, depth; - private void DistributeCollision () + internal void DistributeCollision () { if (!DoPhysics) return; switch (LeCollisionType) { case CollisionType.Circle_Circle: - DistX = Body1._position.x - Body2._position.x; - DistY = Body1._position.y - Body2._position.y; - dist = FixedMath.Sqrt ((DistX * DistX + DistY * DistY) >> FixedMath.SHIFT_AMOUNT); + dist = FixedMath.Sqrt (FastDistance >> FixedMath.SHIFT_AMOUNT); depth = (Body1.Radius + Body2.Radius - dist); - DistX = (DistX * depth / dist); - DistY = (DistY * depth / dist); + if (depth <= 0) { return; } + + if (dist == 0) + dist = 1; + //Minimum vector to no longer be colliding + DistX = (DistX * depth / dist); + DistY = (DistY * depth / dist); //Resolving collision //Note: Immovable bodies don't check collision against each other so this case doesn't need to be considered if (Body1.Immovable || (Body2.Immovable == false && Body1.Priority > Body2.Priority)) { @@ -239,7 +242,7 @@ void DistributeCircle (LSBody body) body._position.y += DistY; body.PositionChanged = true; - if (true) { + if (false) { body._velocity.x += DistX / 8; body._velocity.y += DistY / 8; body.VelocityChanged = true; @@ -269,14 +272,16 @@ public void CheckAndDistributeCollision () if (!Active) { return; } - if (_ranIndex < 0) { - _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); + if (OnlyAffectBody1 == false) { + if (_ranIndex < 0) { + _ranIndex = PhysicsManager.RanCollisionPairs.Add (new PhysicsManager.InstanceCollisionPair (_Version, this)); + } } IsCollidingChanged = false; LastFrame = LockstepManager.FrameCount; CurrentCollisionPair = this; if (CullCounter <= 0) { - GenerateCircleValues (); + GenerateInitialValues (); if (CheckHeight ()) { bool result = CheckCollision (); @@ -284,7 +289,7 @@ public void CheckAndDistributeCollision () IsColliding = result; IsCollidingChanged = true; } - if (CheckCollision ()) { + if (result) { DistributeCollision (); } } @@ -452,8 +457,9 @@ internal bool CheckCollision () return false; } - internal void GenerateCircleValues () { - if (Body1 == null || Body2 == null) + internal void GenerateInitialValues () { + //if (Body1 == null || Body2 == null) What? + DistX = Body1._position.x - Body2._position.x; DistY = Body1._position.y - Body2._position.y; FastDistance = DistX * DistX + DistY * DistY; } diff --git a/Core/Simulation/Physics/Core/Editor.meta b/Core/Simulation/Physics/Core/Editor.meta deleted file mode 100644 index 3ae0977b..00000000 --- a/Core/Simulation/Physics/Core/Editor.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 9a122c7608a3c4f509daa4f384619ffa -folderAsset: yes -timeCreated: 1450833968 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs index 85ec0cf5..b42126ed 100644 --- a/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs +++ b/Core/Simulation/Physics/Ghost/GhostPhysicsManager.cs @@ -67,16 +67,8 @@ void ProcessPair (GhostLSBody ghost, int ID2) { var pair = GetCollisionPair (ghost, ID2); if (pair == null) return; - pair.GenerateCircleValues (); - if (pair.CheckHeight ()) { - bool result = pair.CheckCollision (); - - if (pair.CheckCollision ()) { - //Note: Ensure that ghost body is lower priority so it doesn't move the other body - //TODO: This is extremely dangerous. Should copy-paste functions be made to not allow room for desync? - pair.CheckAndDistributeCollision (); - } - } + //CollisionPair.OnlyAffectBody1 should solve simulation-polluting + pair.CheckAndDistributeCollision (); pair.NotifyBody1 (); }