From 7b1b0f1521bb8285fa9dec74bcaba6c38fe456e5 Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 3 Nov 2023 16:29:52 +0100 Subject: [PATCH 01/14] kinematic: Add second collection that tracks dynamic colliders. --- .../Primitive/PrimitiveColliderInspector.cs | 3 + .../VisualPinball.Unity/Game/PhysicsEngine.cs | 6 +- .../Physics/Collider/ColliderReference.cs | 39 +- .../Physics/NativeColliderIds.cs | 7 + .../Physics/NativeColliderIds.cs.meta | 3 + .../{NativeCollider.cs => NativeColliders.cs} | 1162 ++++++++--------- ...llider.cs.meta => NativeColliders.cs.meta} | 4 +- .../VPT/Bumper/BumperApi.cs | 3 +- .../VisualPinball.Unity/VPT/CollidableApi.cs | 7 +- .../VPT/ColliderComponent.cs | 15 +- .../VPT/Flipper/FlipperApi.cs | 3 +- .../VisualPinball.Unity/VPT/Gate/GateApi.cs | 3 +- .../VPT/HitTarget/DropTargetApi.cs | 3 +- .../VPT/HitTarget/HitTargetApi.cs | 3 +- .../VisualPinball.Unity/VPT/IApi.cs | 3 +- .../VPT/ICollidableComponent.cs | 2 +- .../VPT/Kicker/KickerApi.cs | 3 +- .../VPT/MetalWireGuide/MetalWireGuideApi.cs | 3 +- .../VPT/Playfield/PlayfieldApi.cs | 3 +- .../VPT/Plunger/PlungerApi.cs | 3 +- .../VPT/Primitive/PrimitiveApi.cs | 5 +- .../Primitive/PrimitiveColliderComponent.cs | 4 +- .../VisualPinball.Unity/VPT/Ramp/RampApi.cs | 3 +- .../VPT/Rubber/RubberApi.cs | 3 +- .../VPT/Spinner/SpinnerApi.cs | 3 +- .../VPT/Surface/SurfaceApi.cs | 3 +- .../VPT/Trigger/TriggerApi.cs | 3 +- 27 files changed, 689 insertions(+), 613 deletions(-) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs.meta rename VisualPinball.Unity/VisualPinball.Unity/Physics/{NativeCollider.cs => NativeColliders.cs} (97%) rename VisualPinball.Unity/VisualPinball.Unity/Physics/{NativeCollider.cs.meta => NativeColliders.cs.meta} (97%) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs index 950559d31..3b58ef8f5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs @@ -35,6 +35,7 @@ public class PrimitiveColliderInspector : ColliderInspector _disabledCollisionItems = new(0, Allocator.Persistent); [NonSerialized] private bool _swapBallCollisionHandling; + [NonSerialized] private NativeParallelHashMap _itemTransforms = new(0, Allocator.Persistent); + [NonSerialized] private NativeParallelHashMap _colliderLookup = new(0, Allocator.Persistent); + #endregion #region Transforms @@ -175,11 +178,12 @@ private void Start() var colliderItems = GetComponentsInChildren(); Debug.Log($"Found {colliderItems.Length} collidable items."); var colliders = new ColliderReference(Allocator.TempJob); + var kinematicColliders = new ColliderReference(Allocator.TempJob, true); foreach (var colliderItem in colliderItems) { if (!colliderItem.IsCollidable) { _disabledCollisionItems.Add(colliderItem.ItemId); } - colliderItem.GetColliders(_player, ref colliders, 0); + colliderItem.GetColliders(_player, ref colliders, ref kinematicColliders, 0); } // allocate colliders diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs index 29e1bc729..f912d613c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs @@ -37,7 +37,11 @@ public struct ColliderReference : IDisposable public NativeList Lookup; - public ColliderReference(Allocator allocator) + private bool _trackReferences; + private NativeParallelHashMap> _references; + + + public ColliderReference(Allocator allocator, bool trackReferences = false) { CircleColliders = new NativeList(allocator); FlipperColliders = new NativeList(allocator); @@ -52,6 +56,9 @@ public ColliderReference(Allocator allocator) TriangleColliders = new NativeList(allocator); PlaneColliders = new NativeList(allocator); Lookup = new NativeList(allocator); + + _trackReferences = trackReferences; + _references = new NativeParallelHashMap>(0, allocator); } public void Dispose() @@ -68,6 +75,12 @@ public void Dispose() SpinnerColliders.Dispose(); TriangleColliders.Dispose(); PlaneColliders.Dispose(); + using (var enumerator = _references.GetEnumerator()) { + while (enumerator.MoveNext()) { + enumerator.Current.Value.Dispose(); + } + } + _references.Dispose(); } public int Count => Lookup.Length; @@ -100,9 +113,22 @@ private ICollider LookupCollider(int i) #region Add + private void TrackReference(int itemId, int colliderId) + { + if (!_trackReferences) { + return; + } + + if (!_references.ContainsKey(itemId)) { + _references[itemId] = new NativeList(Allocator.Temp); + } + _references[itemId].Add(colliderId); + } + internal int Add(CircleCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Circle, CircleColliders.Length)); CircleColliders.Add(collider); return collider.Id; @@ -111,6 +137,7 @@ internal int Add(CircleCollider collider) internal int Add(FlipperCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Flipper, FlipperColliders.Length)); FlipperColliders.Add(collider); return collider.Id; @@ -119,6 +146,7 @@ internal int Add(FlipperCollider collider) internal int Add(GateCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Gate, GateColliders.Length)); GateColliders.Add(collider); return collider.Id; @@ -127,6 +155,7 @@ internal int Add(GateCollider collider) internal int Add(Line3DCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Line3D, Line3DColliders.Length)); Line3DColliders.Add(collider); return collider.Id; @@ -135,6 +164,7 @@ internal int Add(Line3DCollider collider) internal int Add(LineSlingshotCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.LineSlingShot, LineSlingshotColliders.Length)); LineSlingshotColliders.Add(collider); return collider.Id; @@ -143,6 +173,7 @@ internal int Add(LineSlingshotCollider collider) internal int Add(LineCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Line, LineColliders.Length)); LineColliders.Add(collider); return collider.Id; @@ -151,6 +182,7 @@ internal int Add(LineCollider collider) internal int Add(LineZCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.LineZ, LineZColliders.Length)); LineZColliders.Add(collider); return collider.Id; @@ -159,6 +191,7 @@ internal int Add(LineZCollider collider) internal int Add(PlungerCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Plunger, PlungerColliders.Length)); PlungerColliders.Add(collider); return collider.Id; @@ -167,6 +200,7 @@ internal int Add(PlungerCollider collider) internal int Add(PointCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Point, PointColliders.Length)); PointColliders.Add(collider); return collider.Id; @@ -175,6 +209,7 @@ internal int Add(PointCollider collider) internal int Add(SpinnerCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Spinner, SpinnerColliders.Length)); SpinnerColliders.Add(collider); return collider.Id; @@ -183,6 +218,7 @@ internal int Add(SpinnerCollider collider) internal int Add(TriangleCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Triangle, TriangleColliders.Length)); TriangleColliders.Add(collider); return collider.Id; @@ -191,6 +227,7 @@ internal int Add(TriangleCollider collider) internal int Add(PlaneCollider collider) { collider.Id = Lookup.Length; + TrackReference(collider.Header.ItemId, collider.Header.Id); Lookup.Add(new ColliderLookup(ColliderType.Plane, PlaneColliders.Length)); PlaneColliders.Add(collider); return collider.Id; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs new file mode 100644 index 000000000..9fe5699b1 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs @@ -0,0 +1,7 @@ +namespace VisualPinball.Unity +{ + public enum NativeColliderIds + { + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs.meta new file mode 100644 index 000000000..b56bb2ba9 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b636e0d45f0474c961c74de3cfd8b11 +timeCreated: 1699020556 \ No newline at end of file diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs similarity index 97% rename from VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs rename to VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs index 73e628c51..bb0cac8d2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs @@ -1,581 +1,581 @@ -// Visual Pinball Engine -// Copyright (C) 2023 freezy and VPE Team -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// ReSharper disable InconsistentNaming - -using System.Diagnostics; -using System; -using Unity.Burst; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Collections; -using Unity.Profiling; -using VisualPinball.Engine.VPT; - -namespace VisualPinball.Unity -{ - [NativeContainer] - [NativeContainerSupportsMinMaxWriteRestriction] - [DebuggerDisplay("Length = {Length}")] - [DebuggerTypeProxy(typeof(NativeCollidersDebugView))] - public unsafe struct NativeColliders : IDisposable - { - #region Members - - private static readonly ProfilerMarker PerfMarker = new("NativeColliders Allocation"); - - public int Length => m_Length; - - /// - /// An array that links the collider IDs (the key) to the position in the respective collider buffer. - /// - [NativeDisableUnsafePtrRestriction] private void* m_LookupBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_CircleColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_FlipperColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_GateColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_Line3DColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_LineSlingshotColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_LineColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_LineZColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_PlungerColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_PointColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_SpinnerColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_TriangleColliderBuffer; - [NativeDisableUnsafePtrRestriction] private void* m_PlaneColliderBuffer; - - private readonly Allocator m_AllocatorLabel; - - private int m_Length; // must be here, and called like that. - -#if ENABLE_UNITY_COLLECTIONS_CHECKS - internal int m_MinIndex; - internal int m_MaxIndex; - internal AtomicSafetyHandle m_Safety; - internal static readonly SharedStatic s_staticSafetyId = SharedStatic.GetOrCreate(); -#endif - - #endregion - - #region Constructor / Allocation - - public NativeColliders(ref ColliderReference colRef, Allocator allocator) - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - // Native allocation is only valid for Temp, Job and Persistent - if (allocator <= Allocator.None) { - throw new ArgumentException("Allocator must be Temp, TempJob or Persistent", nameof(allocator)); - } -#endif - PerfMarker.Begin(); - - m_Length = colRef.Lookup.Length; - - long size = UnsafeUtility.SizeOf() * colRef.Lookup.Length; - m_LookupBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_LookupBuffer, colRef.Lookup.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.FlipperColliders.Length; - m_FlipperColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_FlipperColliderBuffer, colRef.FlipperColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.CircleColliders.Length; - m_CircleColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_CircleColliderBuffer, colRef.CircleColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.GateColliders.Length; - m_GateColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_GateColliderBuffer, colRef.GateColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.Line3DColliders.Length; - m_Line3DColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_Line3DColliderBuffer, colRef.Line3DColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.LineSlingshotColliders.Length; - m_LineSlingshotColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_LineSlingshotColliderBuffer, colRef.LineSlingshotColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.LineColliders.Length; - m_LineColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_LineColliderBuffer, colRef.LineColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.LineZColliders.Length; - m_LineZColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_LineZColliderBuffer, colRef.LineZColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.PlungerColliders.Length; - m_PlungerColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_PlungerColliderBuffer, colRef.PlungerColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.PointColliders.Length; - m_PointColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_PointColliderBuffer, colRef.PointColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.SpinnerColliders.Length; - m_SpinnerColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_SpinnerColliderBuffer, colRef.SpinnerColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.TriangleColliders.Length; - m_TriangleColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_TriangleColliderBuffer, colRef.TriangleColliders.GetUnsafePtr(), size); - - size = UnsafeUtility.SizeOf() * colRef.PlaneColliders.Length; - m_PlaneColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_PlaneColliderBuffer, colRef.PlaneColliders.GetUnsafePtr(), size); - - m_AllocatorLabel = allocator; - - PerfMarker.End(); - -#if ENABLE_UNITY_COLLECTIONS_CHECKS - m_MinIndex = 0; - m_MaxIndex = m_Length - 1; - m_Safety = CollectionHelper.CreateSafetyHandle(allocator); - CollectionHelper.SetStaticSafetyId(ref m_Safety, ref s_staticSafetyId.Data); -#endif - } - - #endregion - - #region Collider Access - - internal ref CircleCollider Circle(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Circle) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up circle collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index); - } - - internal ref FlipperCollider Flipper(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Flipper) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up flipper collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index); - } - - internal ref GateCollider Gate(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Gate) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up gate collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index); - } - - internal ref Line3DCollider Line3D(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Line3D) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line3d collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index); - } - - internal ref LineCollider Line(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Line) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index); - } - - internal ref LineSlingshotCollider LineSlingShot(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.LineSlingShot) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line slingshot collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index); - } - - internal ref LineZCollider LineZ(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.LineZ) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line-z collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index); - } - - internal ref PlaneCollider Plane(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Plane) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up plane collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index); - } - - internal ref PlungerCollider Plunger(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Plunger) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up plunger collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index); - } - - internal ref PointCollider Point(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Point) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up point collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index); - } - - internal ref SpinnerCollider Spinner(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Spinner) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up spinner collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index); - } - - internal ref TriangleCollider Triangle(int colliderId) - { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (lookup.Type != ColliderType.Triangle) { - throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up triangle collider."); - } -#endif - return ref UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index); - } - - #endregion - - #region Collection Access - - public ICollider this[int index] - { - get - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - // If the container is currently not allowed to read from the buffer - // then this will throw an exception. - // This handles all cases, from already disposed containers - // to safe multithreaded access. - AtomicSafetyHandle.CheckReadAndThrow(m_Safety); - - // Perform out of range checks based on - // the NativeContainerSupportsMinMaxWriteRestriction policy - if (index < m_MinIndex || index > m_MaxIndex) - FailOutOfRangeError(index); -#endif - if (index < 0 || index >= m_Length) { - throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); - } - - var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); - switch (lookup.Type) { - case ColliderType.Circle: return UnsafeUtility.ReadArrayElement(m_CircleColliderBuffer, lookup.Index); - case ColliderType.Flipper: return UnsafeUtility.ReadArrayElement(m_FlipperColliderBuffer, lookup.Index); - case ColliderType.Gate: return UnsafeUtility.ReadArrayElement(m_GateColliderBuffer, lookup.Index); - case ColliderType.Line3D: return UnsafeUtility.ReadArrayElement(m_Line3DColliderBuffer, lookup.Index); - case ColliderType.LineSlingShot: return UnsafeUtility.ReadArrayElement(m_LineSlingshotColliderBuffer, lookup.Index); - case ColliderType.Line: return UnsafeUtility.ReadArrayElement(m_LineColliderBuffer, lookup.Index); - case ColliderType.LineZ: return UnsafeUtility.ReadArrayElement(m_LineZColliderBuffer, lookup.Index); - case ColliderType.Plunger: return UnsafeUtility.ReadArrayElement(m_PlungerColliderBuffer, lookup.Index); - case ColliderType.Point: return UnsafeUtility.ReadArrayElement(m_PointColliderBuffer, lookup.Index); - case ColliderType.Spinner: return UnsafeUtility.ReadArrayElement(m_SpinnerColliderBuffer, lookup.Index); - case ColliderType.Triangle: return UnsafeUtility.ReadArrayElement(m_TriangleColliderBuffer, lookup.Index); - case ColliderType.Plane: return UnsafeUtility.ReadArrayElement(m_PlaneColliderBuffer, lookup.Index); - } - throw new ArgumentException($"Unknown lookup type."); - } - - set - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - // If the container is currently not allowed to write to the buffer - // then this will throw an exception. - // This handles all cases, from already disposed containers - // to safe multithreaded access. - AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); - - // Perform out of range checks based on - // the NativeContainerSupportsMinMaxWriteRestriction policy - if (index < m_MinIndex || index > m_MaxIndex) - FailOutOfRangeError(index); -#endif - - if (index < 0 || index >= m_Length) { - throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); - } - - var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); - switch (lookup.Type) { - case ColliderType.Circle: - UnsafeUtility.WriteArrayElement(m_CircleColliderBuffer, lookup.Index, (CircleCollider)value); - break; - case ColliderType.Flipper: - UnsafeUtility.WriteArrayElement(m_FlipperColliderBuffer, lookup.Index, (FlipperCollider)value); - break; - case ColliderType.Gate: - UnsafeUtility.WriteArrayElement(m_GateColliderBuffer, lookup.Index, (GateCollider)value); - break; - case ColliderType.Line: - UnsafeUtility.WriteArrayElement(m_LineColliderBuffer, lookup.Index, (LineCollider)value); - break; - case ColliderType.Line3D: - UnsafeUtility.WriteArrayElement(m_Line3DColliderBuffer, lookup.Index, (Line3DCollider)value); - break; - case ColliderType.LineSlingShot: - UnsafeUtility.WriteArrayElement(m_LineSlingshotColliderBuffer, lookup.Index, (LineSlingshotCollider)value); - break; - case ColliderType.LineZ: - UnsafeUtility.WriteArrayElement(m_LineZColliderBuffer, lookup.Index, (LineZCollider)value); - break; - case ColliderType.Plane: - UnsafeUtility.WriteArrayElement(m_PlaneColliderBuffer, lookup.Index, (PlaneCollider)value); - break; - case ColliderType.Plunger: - UnsafeUtility.WriteArrayElement(m_PlungerColliderBuffer, lookup.Index, (PlungerCollider)value); - break; - case ColliderType.Point: - UnsafeUtility.WriteArrayElement(m_PointColliderBuffer, lookup.Index, (PointCollider)value); - break; - case ColliderType.Spinner: - UnsafeUtility.WriteArrayElement(m_SpinnerColliderBuffer, lookup.Index, (SpinnerCollider)value); - break; - case ColliderType.Triangle: - UnsafeUtility.WriteArrayElement(m_TriangleColliderBuffer, lookup.Index, (TriangleCollider)value); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - } - - #endregion - - #region Disposition - - public void Dispose() - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - CollectionHelper.DisposeSafetyHandle(ref m_Safety); -#endif - - UnsafeUtility.Free(m_LookupBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_CircleColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_FlipperColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_GateColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_Line3DColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_LineSlingshotColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_LineColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_LineZColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_PlungerColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_PointColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_SpinnerColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_TriangleColliderBuffer, m_AllocatorLabel); - UnsafeUtility.Free(m_PlaneColliderBuffer, m_AllocatorLabel); - - m_LookupBuffer = null; - m_CircleColliderBuffer = null; - m_FlipperColliderBuffer = null; - m_GateColliderBuffer = null; - m_Line3DColliderBuffer = null; - m_LineSlingshotColliderBuffer = null; - m_LineColliderBuffer = null; - m_LineZColliderBuffer = null; - m_PlungerColliderBuffer = null; - m_PointColliderBuffer = null; - m_SpinnerColliderBuffer = null; - m_TriangleColliderBuffer = null; - m_PlaneColliderBuffer = null; - m_Length = 0; - } - -#if ENABLE_UNITY_COLLECTIONS_CHECKS - private void FailOutOfRangeError(int index) - { - if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1)) - throw new IndexOutOfRangeException(string.Format( - "Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n" + - "ReadWriteBuffers are restricted to only read & write the element at the job index. " + - "You can use double buffering strategies to avoid race conditions due to " + - "reading & writing in parallel to the same elements from a job.", - index, m_MinIndex, m_MaxIndex)); - - throw new IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length."); - } -#endif - - #endregion - - #region Collider Data - - public Aabb GetAabb(int index) - { - if (index < 0 || index >= m_Length) { - throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); - } - var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); - switch (lookup.Type) { - case ColliderType.Circle: return UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Flipper: return UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Gate: return UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Line3D: return UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.LineSlingShot: return UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Line: return UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.LineZ: return UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Plunger: return UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Point: return UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Spinner: return UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Triangle: return UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index).Bounds.Aabb; - case ColliderType.Plane: return UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index).Bounds.Aabb; - } - throw new ArgumentException($"Unknown lookup type."); - } - - public int GetItemId(int index) => GetHeader(index).ItemId; - - public ItemType GetItemType(int index) => GetHeader(index).ItemType; - - public ref ColliderHeader GetHeader(int index) - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - if (index < 0 || index >= m_Length) { - throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); - } -#endif - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, index); - switch (lookup.Type) { - case ColliderType.Circle: return ref UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index).Header; - case ColliderType.Flipper: return ref UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index).Header; - case ColliderType.Gate: return ref UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index).Header; - case ColliderType.Line3D: return ref UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index).Header; - case ColliderType.LineSlingShot: return ref UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index).Header; - case ColliderType.Line: return ref UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index).Header; - case ColliderType.LineZ: return ref UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index).Header; - case ColliderType.Plunger: return ref UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index).Header; - case ColliderType.Point: return ref UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index).Header; - case ColliderType.Spinner: return ref UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index).Header; - case ColliderType.Triangle: return ref UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index).Header; - case ColliderType.Plane: return ref UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index).Header; - } - throw new ArgumentException($"Unknown lookup type."); - } - - #endregion - - #region Debug - - public ICollider[] ToArray() - { -#if ENABLE_UNITY_COLLECTIONS_CHECKS - AtomicSafetyHandle.CheckReadAndThrow(m_Safety); -#endif - var array = new ICollider[Length]; - for (var i = 0; i < Length; i++) { - ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, i); - switch (lookup.Type) { - case ColliderType.Circle: - array[i] = UnsafeUtility.ReadArrayElement(m_CircleColliderBuffer, lookup.Index); - break; - case ColliderType.Flipper: - array[i] = UnsafeUtility.ReadArrayElement(m_FlipperColliderBuffer, lookup.Index); - break; - case ColliderType.Gate: - array[i] = UnsafeUtility.ReadArrayElement(m_GateColliderBuffer, lookup.Index); - break; - case ColliderType.Line3D: - array[i] = UnsafeUtility.ReadArrayElement(m_Line3DColliderBuffer, lookup.Index); - break; - case ColliderType.LineSlingShot: - array[i] = UnsafeUtility.ReadArrayElement(m_LineSlingshotColliderBuffer, lookup.Index); - break; - case ColliderType.Line: - array[i] = UnsafeUtility.ReadArrayElement(m_LineColliderBuffer, lookup.Index); - break; - case ColliderType.LineZ: - array[i] = UnsafeUtility.ReadArrayElement(m_LineZColliderBuffer, lookup.Index); - break; - case ColliderType.Plunger: - array[i] = UnsafeUtility.ReadArrayElement(m_PlungerColliderBuffer, lookup.Index); - break; - case ColliderType.Point: - array[i] = UnsafeUtility.ReadArrayElement(m_PointColliderBuffer, lookup.Index); - break; - case ColliderType.Spinner: - array[i] = UnsafeUtility.ReadArrayElement(m_SpinnerColliderBuffer, lookup.Index); - break; - case ColliderType.Triangle: - array[i] = UnsafeUtility.ReadArrayElement(m_TriangleColliderBuffer, lookup.Index); - break; - case ColliderType.Plane: - array[i] = UnsafeUtility.ReadArrayElement(m_PlaneColliderBuffer, lookup.Index); - break; - } - } - return array; - } - - #endregion - } - - public readonly struct ColliderLookup - { - public readonly ColliderType Type; - public readonly int Index; - - public ColliderLookup(ColliderType type, int index) - { - Type = type; - Index = index; - } - } - - // Visualizes the colliders in the C# debugger - internal sealed class NativeCollidersDebugView - { - private NativeColliders _nativeColliders; - - public NativeCollidersDebugView(NativeColliders nativeColliders) - { - _nativeColliders = nativeColliders; - } - public ICollider[] Colliders => _nativeColliders.ToArray(); - } -} +// Visual Pinball Engine +// Copyright (C) 2023 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System.Diagnostics; +using System; +using Unity.Burst; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Collections; +using Unity.Profiling; +using VisualPinball.Engine.VPT; + +namespace VisualPinball.Unity +{ + [NativeContainer] + [NativeContainerSupportsMinMaxWriteRestriction] + [DebuggerDisplay("Length = {Length}")] + [DebuggerTypeProxy(typeof(NativeCollidersDebugView))] + public unsafe struct NativeColliders : IDisposable + { + #region Members + + private static readonly ProfilerMarker PerfMarker = new("NativeColliders Allocation"); + + public int Length => m_Length; + + /// + /// An array that links the collider IDs (the key) to the position in the respective collider buffer. + /// + [NativeDisableUnsafePtrRestriction] private void* m_LookupBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_CircleColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_FlipperColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_GateColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_Line3DColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_LineSlingshotColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_LineColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_LineZColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_PlungerColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_PointColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_SpinnerColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_TriangleColliderBuffer; + [NativeDisableUnsafePtrRestriction] private void* m_PlaneColliderBuffer; + + private readonly Allocator m_AllocatorLabel; + + private int m_Length; // must be here, and called like that. + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + internal int m_MinIndex; + internal int m_MaxIndex; + internal AtomicSafetyHandle m_Safety; + internal static readonly SharedStatic s_staticSafetyId = SharedStatic.GetOrCreate(); +#endif + + #endregion + + #region Constructor / Allocation + + public NativeColliders(ref ColliderReference colRef, Allocator allocator) + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + // Native allocation is only valid for Temp, Job and Persistent + if (allocator <= Allocator.None) { + throw new ArgumentException("Allocator must be Temp, TempJob or Persistent", nameof(allocator)); + } +#endif + PerfMarker.Begin(); + + m_Length = colRef.Lookup.Length; + + long size = UnsafeUtility.SizeOf() * colRef.Lookup.Length; + m_LookupBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_LookupBuffer, colRef.Lookup.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.FlipperColliders.Length; + m_FlipperColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_FlipperColliderBuffer, colRef.FlipperColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.CircleColliders.Length; + m_CircleColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_CircleColliderBuffer, colRef.CircleColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.GateColliders.Length; + m_GateColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_GateColliderBuffer, colRef.GateColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.Line3DColliders.Length; + m_Line3DColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_Line3DColliderBuffer, colRef.Line3DColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.LineSlingshotColliders.Length; + m_LineSlingshotColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_LineSlingshotColliderBuffer, colRef.LineSlingshotColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.LineColliders.Length; + m_LineColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_LineColliderBuffer, colRef.LineColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.LineZColliders.Length; + m_LineZColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_LineZColliderBuffer, colRef.LineZColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.PlungerColliders.Length; + m_PlungerColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_PlungerColliderBuffer, colRef.PlungerColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.PointColliders.Length; + m_PointColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_PointColliderBuffer, colRef.PointColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.SpinnerColliders.Length; + m_SpinnerColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_SpinnerColliderBuffer, colRef.SpinnerColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.TriangleColliders.Length; + m_TriangleColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_TriangleColliderBuffer, colRef.TriangleColliders.GetUnsafePtr(), size); + + size = UnsafeUtility.SizeOf() * colRef.PlaneColliders.Length; + m_PlaneColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(m_PlaneColliderBuffer, colRef.PlaneColliders.GetUnsafePtr(), size); + + m_AllocatorLabel = allocator; + + PerfMarker.End(); + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + m_MinIndex = 0; + m_MaxIndex = m_Length - 1; + m_Safety = CollectionHelper.CreateSafetyHandle(allocator); + CollectionHelper.SetStaticSafetyId(ref m_Safety, ref s_staticSafetyId.Data); +#endif + } + + #endregion + + #region Collider Access + + internal ref CircleCollider Circle(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Circle) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up circle collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index); + } + + internal ref FlipperCollider Flipper(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Flipper) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up flipper collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index); + } + + internal ref GateCollider Gate(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Gate) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up gate collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index); + } + + internal ref Line3DCollider Line3D(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Line3D) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line3d collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index); + } + + internal ref LineCollider Line(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Line) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index); + } + + internal ref LineSlingshotCollider LineSlingShot(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.LineSlingShot) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line slingshot collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index); + } + + internal ref LineZCollider LineZ(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.LineZ) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up line-z collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index); + } + + internal ref PlaneCollider Plane(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Plane) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up plane collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index); + } + + internal ref PlungerCollider Plunger(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Plunger) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up plunger collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index); + } + + internal ref PointCollider Point(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Point) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up point collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index); + } + + internal ref SpinnerCollider Spinner(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Spinner) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up spinner collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index); + } + + internal ref TriangleCollider Triangle(int colliderId) + { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, colliderId); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (lookup.Type != ColliderType.Triangle) { + throw new ArgumentException($"Invalid collider type {lookup.Type} when looking up triangle collider."); + } +#endif + return ref UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index); + } + + #endregion + + #region Collection Access + + public ICollider this[int index] + { + get + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + // If the container is currently not allowed to read from the buffer + // then this will throw an exception. + // This handles all cases, from already disposed containers + // to safe multithreaded access. + AtomicSafetyHandle.CheckReadAndThrow(m_Safety); + + // Perform out of range checks based on + // the NativeContainerSupportsMinMaxWriteRestriction policy + if (index < m_MinIndex || index > m_MaxIndex) + FailOutOfRangeError(index); +#endif + if (index < 0 || index >= m_Length) { + throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); + } + + var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); + switch (lookup.Type) { + case ColliderType.Circle: return UnsafeUtility.ReadArrayElement(m_CircleColliderBuffer, lookup.Index); + case ColliderType.Flipper: return UnsafeUtility.ReadArrayElement(m_FlipperColliderBuffer, lookup.Index); + case ColliderType.Gate: return UnsafeUtility.ReadArrayElement(m_GateColliderBuffer, lookup.Index); + case ColliderType.Line3D: return UnsafeUtility.ReadArrayElement(m_Line3DColliderBuffer, lookup.Index); + case ColliderType.LineSlingShot: return UnsafeUtility.ReadArrayElement(m_LineSlingshotColliderBuffer, lookup.Index); + case ColliderType.Line: return UnsafeUtility.ReadArrayElement(m_LineColliderBuffer, lookup.Index); + case ColliderType.LineZ: return UnsafeUtility.ReadArrayElement(m_LineZColliderBuffer, lookup.Index); + case ColliderType.Plunger: return UnsafeUtility.ReadArrayElement(m_PlungerColliderBuffer, lookup.Index); + case ColliderType.Point: return UnsafeUtility.ReadArrayElement(m_PointColliderBuffer, lookup.Index); + case ColliderType.Spinner: return UnsafeUtility.ReadArrayElement(m_SpinnerColliderBuffer, lookup.Index); + case ColliderType.Triangle: return UnsafeUtility.ReadArrayElement(m_TriangleColliderBuffer, lookup.Index); + case ColliderType.Plane: return UnsafeUtility.ReadArrayElement(m_PlaneColliderBuffer, lookup.Index); + } + throw new ArgumentException($"Unknown lookup type."); + } + + set + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + // If the container is currently not allowed to write to the buffer + // then this will throw an exception. + // This handles all cases, from already disposed containers + // to safe multithreaded access. + AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); + + // Perform out of range checks based on + // the NativeContainerSupportsMinMaxWriteRestriction policy + if (index < m_MinIndex || index > m_MaxIndex) + FailOutOfRangeError(index); +#endif + + if (index < 0 || index >= m_Length) { + throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); + } + + var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); + switch (lookup.Type) { + case ColliderType.Circle: + UnsafeUtility.WriteArrayElement(m_CircleColliderBuffer, lookup.Index, (CircleCollider)value); + break; + case ColliderType.Flipper: + UnsafeUtility.WriteArrayElement(m_FlipperColliderBuffer, lookup.Index, (FlipperCollider)value); + break; + case ColliderType.Gate: + UnsafeUtility.WriteArrayElement(m_GateColliderBuffer, lookup.Index, (GateCollider)value); + break; + case ColliderType.Line: + UnsafeUtility.WriteArrayElement(m_LineColliderBuffer, lookup.Index, (LineCollider)value); + break; + case ColliderType.Line3D: + UnsafeUtility.WriteArrayElement(m_Line3DColliderBuffer, lookup.Index, (Line3DCollider)value); + break; + case ColliderType.LineSlingShot: + UnsafeUtility.WriteArrayElement(m_LineSlingshotColliderBuffer, lookup.Index, (LineSlingshotCollider)value); + break; + case ColliderType.LineZ: + UnsafeUtility.WriteArrayElement(m_LineZColliderBuffer, lookup.Index, (LineZCollider)value); + break; + case ColliderType.Plane: + UnsafeUtility.WriteArrayElement(m_PlaneColliderBuffer, lookup.Index, (PlaneCollider)value); + break; + case ColliderType.Plunger: + UnsafeUtility.WriteArrayElement(m_PlungerColliderBuffer, lookup.Index, (PlungerCollider)value); + break; + case ColliderType.Point: + UnsafeUtility.WriteArrayElement(m_PointColliderBuffer, lookup.Index, (PointCollider)value); + break; + case ColliderType.Spinner: + UnsafeUtility.WriteArrayElement(m_SpinnerColliderBuffer, lookup.Index, (SpinnerCollider)value); + break; + case ColliderType.Triangle: + UnsafeUtility.WriteArrayElement(m_TriangleColliderBuffer, lookup.Index, (TriangleCollider)value); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + #endregion + + #region Disposition + + public void Dispose() + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + CollectionHelper.DisposeSafetyHandle(ref m_Safety); +#endif + + UnsafeUtility.Free(m_LookupBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_CircleColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_FlipperColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_GateColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_Line3DColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_LineSlingshotColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_LineColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_LineZColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_PlungerColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_PointColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_SpinnerColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_TriangleColliderBuffer, m_AllocatorLabel); + UnsafeUtility.Free(m_PlaneColliderBuffer, m_AllocatorLabel); + + m_LookupBuffer = null; + m_CircleColliderBuffer = null; + m_FlipperColliderBuffer = null; + m_GateColliderBuffer = null; + m_Line3DColliderBuffer = null; + m_LineSlingshotColliderBuffer = null; + m_LineColliderBuffer = null; + m_LineZColliderBuffer = null; + m_PlungerColliderBuffer = null; + m_PointColliderBuffer = null; + m_SpinnerColliderBuffer = null; + m_TriangleColliderBuffer = null; + m_PlaneColliderBuffer = null; + m_Length = 0; + } + +#if ENABLE_UNITY_COLLECTIONS_CHECKS + private void FailOutOfRangeError(int index) + { + if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1)) + throw new IndexOutOfRangeException(string.Format( + "Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n" + + "ReadWriteBuffers are restricted to only read & write the element at the job index. " + + "You can use double buffering strategies to avoid race conditions due to " + + "reading & writing in parallel to the same elements from a job.", + index, m_MinIndex, m_MaxIndex)); + + throw new IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length."); + } +#endif + + #endregion + + #region Collider Data + + public Aabb GetAabb(int index) + { + if (index < 0 || index >= m_Length) { + throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); + } + var lookup = UnsafeUtility.ReadArrayElement(m_LookupBuffer, index); + switch (lookup.Type) { + case ColliderType.Circle: return UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Flipper: return UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Gate: return UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Line3D: return UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.LineSlingShot: return UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Line: return UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.LineZ: return UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Plunger: return UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Point: return UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Spinner: return UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Triangle: return UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index).Bounds.Aabb; + case ColliderType.Plane: return UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index).Bounds.Aabb; + } + throw new ArgumentException($"Unknown lookup type."); + } + + public int GetItemId(int index) => GetHeader(index).ItemId; + + public ItemType GetItemType(int index) => GetHeader(index).ItemType; + + public ref ColliderHeader GetHeader(int index) + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + if (index < 0 || index >= m_Length) { + throw new IndexOutOfRangeException($"Invalid index {index} when looking up collider."); + } +#endif + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, index); + switch (lookup.Type) { + case ColliderType.Circle: return ref UnsafeUtility.ArrayElementAsRef(m_CircleColliderBuffer, lookup.Index).Header; + case ColliderType.Flipper: return ref UnsafeUtility.ArrayElementAsRef(m_FlipperColliderBuffer, lookup.Index).Header; + case ColliderType.Gate: return ref UnsafeUtility.ArrayElementAsRef(m_GateColliderBuffer, lookup.Index).Header; + case ColliderType.Line3D: return ref UnsafeUtility.ArrayElementAsRef(m_Line3DColliderBuffer, lookup.Index).Header; + case ColliderType.LineSlingShot: return ref UnsafeUtility.ArrayElementAsRef(m_LineSlingshotColliderBuffer, lookup.Index).Header; + case ColliderType.Line: return ref UnsafeUtility.ArrayElementAsRef(m_LineColliderBuffer, lookup.Index).Header; + case ColliderType.LineZ: return ref UnsafeUtility.ArrayElementAsRef(m_LineZColliderBuffer, lookup.Index).Header; + case ColliderType.Plunger: return ref UnsafeUtility.ArrayElementAsRef(m_PlungerColliderBuffer, lookup.Index).Header; + case ColliderType.Point: return ref UnsafeUtility.ArrayElementAsRef(m_PointColliderBuffer, lookup.Index).Header; + case ColliderType.Spinner: return ref UnsafeUtility.ArrayElementAsRef(m_SpinnerColliderBuffer, lookup.Index).Header; + case ColliderType.Triangle: return ref UnsafeUtility.ArrayElementAsRef(m_TriangleColliderBuffer, lookup.Index).Header; + case ColliderType.Plane: return ref UnsafeUtility.ArrayElementAsRef(m_PlaneColliderBuffer, lookup.Index).Header; + } + throw new ArgumentException($"Unknown lookup type."); + } + + #endregion + + #region Debug + + public ICollider[] ToArray() + { +#if ENABLE_UNITY_COLLECTIONS_CHECKS + AtomicSafetyHandle.CheckReadAndThrow(m_Safety); +#endif + var array = new ICollider[Length]; + for (var i = 0; i < Length; i++) { + ref var lookup = ref UnsafeUtility.ArrayElementAsRef(m_LookupBuffer, i); + switch (lookup.Type) { + case ColliderType.Circle: + array[i] = UnsafeUtility.ReadArrayElement(m_CircleColliderBuffer, lookup.Index); + break; + case ColliderType.Flipper: + array[i] = UnsafeUtility.ReadArrayElement(m_FlipperColliderBuffer, lookup.Index); + break; + case ColliderType.Gate: + array[i] = UnsafeUtility.ReadArrayElement(m_GateColliderBuffer, lookup.Index); + break; + case ColliderType.Line3D: + array[i] = UnsafeUtility.ReadArrayElement(m_Line3DColliderBuffer, lookup.Index); + break; + case ColliderType.LineSlingShot: + array[i] = UnsafeUtility.ReadArrayElement(m_LineSlingshotColliderBuffer, lookup.Index); + break; + case ColliderType.Line: + array[i] = UnsafeUtility.ReadArrayElement(m_LineColliderBuffer, lookup.Index); + break; + case ColliderType.LineZ: + array[i] = UnsafeUtility.ReadArrayElement(m_LineZColliderBuffer, lookup.Index); + break; + case ColliderType.Plunger: + array[i] = UnsafeUtility.ReadArrayElement(m_PlungerColliderBuffer, lookup.Index); + break; + case ColliderType.Point: + array[i] = UnsafeUtility.ReadArrayElement(m_PointColliderBuffer, lookup.Index); + break; + case ColliderType.Spinner: + array[i] = UnsafeUtility.ReadArrayElement(m_SpinnerColliderBuffer, lookup.Index); + break; + case ColliderType.Triangle: + array[i] = UnsafeUtility.ReadArrayElement(m_TriangleColliderBuffer, lookup.Index); + break; + case ColliderType.Plane: + array[i] = UnsafeUtility.ReadArrayElement(m_PlaneColliderBuffer, lookup.Index); + break; + } + } + return array; + } + + #endregion + } + + public readonly struct ColliderLookup + { + public readonly ColliderType Type; + public readonly int Index; + + public ColliderLookup(ColliderType type, int index) + { + Type = type; + Index = index; + } + } + + // Visualizes the colliders in the C# debugger + internal sealed class NativeCollidersDebugView + { + private NativeColliders _nativeColliders; + + public NativeCollidersDebugView(NativeColliders nativeColliders) + { + _nativeColliders = nativeColliders; + } + public ICollider[] Colliders => _nativeColliders.ToArray(); + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs.meta similarity index 97% rename from VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs.meta rename to VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs.meta index e941cb236..ef37beb17 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeCollider.cs.meta +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs.meta @@ -1,3 +1,3 @@ -fileFormatVersion: 2 -guid: 264d4febde7b4f19955044bba6cbd6d6 +fileFormatVersion: 2 +guid: 264d4febde7b4f19955044bba6cbd6d6 timeCreated: 1698263847 \ No newline at end of file diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs index 1a3dc9149..f2419b469 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs @@ -72,7 +72,8 @@ void IApiCoil.OnCoil(bool enabled) protected override bool FireHitEvents => ColliderComponent.HitEvent; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var height = MainComponent.PositionZ; colliders.Add(new CircleCollider(MainComponent.Position, MainComponent.Radius, height, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs index 6f6ec848c..9b066f69a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs @@ -41,14 +41,15 @@ protected CollidableApi(GameObject go, Player player, PhysicsEngine physicsEngin protected virtual bool FireHitEvents => false; protected virtual float HitThreshold => 0; - protected abstract void CreateColliders(ref ColliderReference colliders, float margin); + protected abstract void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin); - void IApiColliderGenerator.CreateColliders(ref ColliderReference colliders, float margin) + void IApiColliderGenerator.CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, + float margin) { if (!ColliderComponent) { return; } - CreateColliders(ref colliders, margin); + CreateColliders(ref colliders, ref kinematicColliders, margin); } ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(MainComponent.ItemType); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs index e03a448f0..290aca931 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs @@ -138,7 +138,8 @@ private void OnDrawGizmos() if (generateColliders) { var api = InstantiateColliderApi(player, null); var colliders = new ColliderReference(Allocator.TempJob); - api.CreateColliders(ref colliders, 0.1f); + var kinematicColliders = new ColliderReference(Allocator.TempJob, true); + api.CreateColliders(ref colliders, ref kinematicColliders, 0.1f); if (showColliders) { _colliderMesh = GenerateColliderMesh(ref colliders); @@ -157,7 +158,8 @@ private void OnDrawGizmos() var api = InstantiateColliderApi(player, null); var colliders = new ColliderReference(Allocator.TempJob); - api.CreateColliders(ref colliders, 0.1f); + var kinematicColliders = new ColliderReference(Allocator.TempJob, true); + api.CreateColliders(ref colliders, ref kinematicColliders, 0.1f); var playfieldBounds = GetComponentInChildren().Bounds; var octree = new NativeOctree(playfieldBounds, 32, 10, Allocator.Persistent); @@ -434,10 +436,11 @@ private static void DrawAabb(Aabb aabb, bool isSelected) #endregion - void ICollidableComponent.GetColliders(Player player, ref ColliderReference colliders, float margin) - { - InstantiateColliderApi(player, null).CreateColliders(ref colliders, margin); - } + void ICollidableComponent.GetColliders(Player player, ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) + => InstantiateColliderApi(player, null) + .CreateColliders(ref colliders, ref kinematicColliders, margin); + int ICollidableComponent.ItemId => MainComponent.gameObject.GetInstanceID(); bool ICollidableComponent.IsCollidable => isActiveAndEnabled; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs index 27c95e65a..25cae1a33 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs @@ -221,7 +221,8 @@ void IApiCollidable.OnCollide(int ballId, float hit) #region Collider Generation - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var height = MainComponent.PositionZ; var baseRadius = math.max(MainComponent.BaseRadius, 0.01f); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs index a4f28e686..e5957e884 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs @@ -97,7 +97,8 @@ public void Lift(float speed, float angleDeg) #region Collider Generation - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new GateColliderGenerator(this, MainComponent, ColliderComponent); colliderGenerator.GenerateColliders(MainComponent.PositionZ, ref colliders); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs index 66bc87543..1764216ce 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetApi.cs @@ -102,7 +102,8 @@ private void SetIsDropped(bool isDropped) protected override bool FireHitEvents => true; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new DropTargetColliderGenerator(this, MainComponent, MainComponent); colliderGenerator.GenerateColliders(MainComponent.PlayfieldHeight, ref colliders); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs index ae3818139..65b8c2b21 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs @@ -59,7 +59,8 @@ internal HitTargetApi(GameObject go, Player player, PhysicsEngine physicsEngine) protected override bool FireHitEvents => true; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new HitTargetColliderGenerator(this, MainComponent, MainComponent); colliderGenerator.GenerateColliders(ref colliders); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs index 74f3816ad..9db4834e1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs @@ -41,8 +41,9 @@ public interface IApiColliderGenerator /// Create colliders and add them to the provided list. /// /// List to add colliders to. + /// List to add kinematic colliders to. /// - void CreateColliders(ref ColliderReference colliders, float margin); + void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin); /// /// Computes collider info based on the component data. diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ICollidableComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ICollidableComponent.cs index 3367c18ea..76e47e4fb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ICollidableComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ICollidableComponent.cs @@ -18,7 +18,7 @@ namespace VisualPinball.Unity { public interface ICollidableComponent { - internal void GetColliders(Player player, ref ColliderReference colliders, float margin); + internal void GetColliders(Player player, ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin); internal int ItemId { get; } internal bool IsCollidable { get; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs index 94b41e856..b78b51141 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs @@ -224,7 +224,8 @@ private void KickXYZ(float angle, float speed, float inclination, float x, float #region Collider Generation - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var height = MainComponent.PositionZ; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs index 2a26c3aba..9b04d3b79 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs @@ -43,7 +43,8 @@ internal MetalWireGuideApi(GameObject go, Player player, PhysicsEngine physicsEn protected override bool FireHitEvents => ColliderComponent.HitEvent; protected override float HitThreshold => 2.0f; // hard coded threshold for now - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new MetalWireGuideColliderGenerator(this, new MetalWireGuideMeshGenerator(MainComponent)); colliderGenerator.GenerateColliders(MainComponent.PlayfieldHeight, ColliderComponent.HitHeight, MainComponent.Bendradius, MainComponent.PlayfieldDetailLevel, ref colliders, margin); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldApi.cs index 79121ef15..d5fed05ef 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldApi.cs @@ -29,7 +29,8 @@ internal PlayfieldApi(GameObject go, Player player, PhysicsEngine physicsEngine) #region Collider Generation - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var info = ((IApiColliderGenerator)this).GetColliderInfo(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs index 7ca9c3cd2..328d9f430 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs @@ -142,7 +142,8 @@ private IApiCoil Coil(string deviceItem) #region Collider Generation - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { colliders.Add(new PlungerCollider(MainComponent, ColliderComponent, GetColliderInfo())); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs index af5a106f1..f348a3481 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs @@ -43,10 +43,11 @@ internal PrimitiveApi(GameObject go, Player player, PhysicsEngine physicsEngine) protected override bool FireHitEvents => ColliderComponent.HitEvent; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new PrimitiveColliderGenerator(this, MainComponent, MainComponent); - colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref colliders); + var colls = ColliderComponent.IsKinematic ? kinematicColliders : colliders; + colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref colls); } #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs index d24b10d64..f67120d0c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs @@ -16,7 +16,6 @@ // ReSharper disable InconsistentNaming -using System.Collections.Generic; using UnityEngine; using VisualPinball.Engine.VPT.Primitive; @@ -57,6 +56,9 @@ public class PrimitiveColliderComponent : ColliderComponent GetPhysicsMaterialData(Elasticity, ElasticityFalloff, Friction, Scatter, OverwritePhysics); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs index 66752d069..3e93b9e0f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs @@ -61,7 +61,8 @@ void IApi.OnDestroy() protected override bool FireHitEvents => ColliderComponent.HitEvent; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new RampColliderGenerator(this, MainComponent, ColliderComponent); colliderGenerator.GenerateColliders(MainComponent.PlayfieldHeight, ref colliders, margin); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs index 2d92b9260..b4c0b0d2c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs @@ -43,7 +43,8 @@ internal RubberApi(GameObject go, Player player, PhysicsEngine physicsEngine) : protected override bool FireHitEvents => ColliderComponent.HitEvent; protected override float HitThreshold => 2.0f; // hard coded threshold for now - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new RubberColliderGenerator(this, new RubberMeshGenerator(MainComponent)); colliderGenerator.GenerateColliders(MainComponent.PlayfieldHeight, ColliderComponent.HitHeight, MainComponent.PlayfieldDetailLevel, ref colliders, margin); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs index ccc5f7940..9019cfec0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs @@ -82,7 +82,8 @@ public SpinnerApi(GameObject go, Player player, PhysicsEngine physicsEngine) : b protected override bool FireHitEvents => true; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new SpinnerColliderGenerator(this, MainComponent); colliderGenerator.GenerateColliders(MainComponent.HeightOnPlayfield, ref colliders); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs index 25f804dac..9ad5844a6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs @@ -47,7 +47,8 @@ internal SurfaceApi(GameObject go, Player player, PhysicsEngine physicsEngine) : protected override bool FireHitEvents => true; protected override float HitThreshold => ColliderComponent.Threshold; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { if (MainComponent.DragPoints.Length == 0) { return; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs index 4e053be94..a867681e5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs @@ -63,7 +63,8 @@ internal TriggerApi(GameObject go, Player player, PhysicsEngine physicsEngine) : protected override bool FireHitEvents => true; - protected override void CreateColliders(ref ColliderReference colliders, float margin) + protected override void CreateColliders(ref ColliderReference colliders, + ref ColliderReference kinematicColliders, float margin) { var meshComponent = GameObject.GetComponent(); var colliderGenerator = new TriggerColliderGenerator(this, MainComponent, ColliderComponent, meshComponent); From cd3793e0825b3bc4056913ab9845f4508d9c291a Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 3 Nov 2023 23:04:18 +0100 Subject: [PATCH 02/14] kinematic: Add broad and narrow phase. --- .../VisualPinball.Unity/Game/PhysicsCycle.cs | 17 ++++++- .../VisualPinball.Unity/Game/PhysicsEngine.cs | 8 +++- .../Game/PhysicsKinematicBroadPhase.cs | 41 +++++++++++++++++ .../Game/PhysicsKinematicBroadPhase.cs.meta | 3 ++ .../VisualPinball.Unity/Game/PhysicsState.cs | 46 ++++++++++--------- .../Game/PhysicsStaticNarrowPhase.cs | 12 ++--- .../Game/PhysicsUpdateJob.cs | 4 +- .../Physics/NativeColliderIds.cs | 2 +- 8 files changed, 97 insertions(+), 36 deletions(-) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs index ae89475bf..ca4349eeb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs @@ -45,6 +45,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati // create octree of ball-to-ball collision // it's okay to have this code outside of the inner loop, as the ball hitrects already include the maximum distance they can travel in that timespan var ballOctree = PhysicsDynamicBroadPhase.CreateOctree(ref state.Balls, in playfieldBounds); + var kineticOctree = PhysicsKinematicBroadPhase.CreateOctree(ref state.KinematicColliders, in playfieldBounds); while (dTime > 0) { @@ -63,9 +64,21 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati continue; } - // hit testing + // init contacts and event + ball.CollisionEvent.ClearCollider(hitTime); // search upto current hit time + + // hit testing (overlappingColliders is cleared in broad phase) PhysicsStaticBroadPhase.FindOverlaps(in state.Octree, in ball, ref overlappingColliders); - PhysicsStaticNarrowPhase.FindNextCollision(hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state); + PhysicsStaticNarrowPhase.FindNextCollision(ref state.Colliders, hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state); + + PhysicsStaticBroadPhase.FindOverlaps(in kineticOctree, in ball, ref overlappingColliders); + PhysicsStaticNarrowPhase.FindNextCollision(ref state.KinematicColliders, hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state); + + // no negative time allowed + if (ball.CollisionEvent.HitTime < 0) { + ball.CollisionEvent.ClearCollider(); + } + PhysicsDynamicBroadPhase.FindOverlaps(in ballOctree, in ball, ref overlappingColliders, ref state.Balls); PhysicsDynamicNarrowPhase.FindNextCollision(ref ball, ref overlappingColliders, ref _contacts, ref state); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index d631d527b..3b7d9cb0e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -45,6 +45,8 @@ public class PhysicsEngine : MonoBehaviour [NonSerialized] private InsideOfs _insideOfs; [NonSerialized] private NativeOctree _octree; [NonSerialized] private NativeColliders _colliders; + [NonSerialized] private NativeColliders _kinematicColliders; + [NonSerialized] private NativeColliders _kinematicCollidersAtIdentity; [NonSerialized] private NativeArray _physicsEnv = new(1, Allocator.Persistent); [NonSerialized] private NativeQueue _eventQueue = new(Allocator.Persistent); @@ -188,6 +190,8 @@ private void Start() // allocate colliders _colliders = new NativeColliders(ref colliders, Allocator.Persistent); + _kinematicColliders = new NativeColliders(ref kinematicColliders, Allocator.Persistent); + _kinematicCollidersAtIdentity = new NativeColliders(ref kinematicColliders, Allocator.Persistent); // create octree var elapsedMs = sw.Elapsed.TotalMilliseconds; @@ -221,6 +225,8 @@ private void Update() PhysicsEnv = _physicsEnv, Octree = _octree, Colliders = _colliders, + KinematicColliders = _kinematicColliders, + KinematicCollidersAtIdentity = _kinematicCollidersAtIdentity, InsideOfs = _insideOfs, Events = events, Balls = _ballStates, @@ -240,7 +246,7 @@ private void Update() }; var env = _physicsEnv[0]; - var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref events, ref _insideOfs, ref _ballStates, + var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, ref events, ref _insideOfs, ref _ballStates, ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates, ref _hitTargetStates, ref _kickerStates, ref _plungerStates, ref _spinnerStates, ref _surfaceStates, ref _triggerStates, ref _disabledCollisionItems, ref _swapBallCollisionHandling); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs new file mode 100644 index 000000000..5f07670d8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs @@ -0,0 +1,41 @@ +// Visual Pinball Engine +// Copyright (C) 2023 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using NativeTrees; +using Unity.Collections; +using Unity.Profiling; +using VisualPinball.Unity.Collections; + +namespace VisualPinball.Unity +{ + public static class PhysicsKinematicBroadPhase + { + private static readonly ProfilerMarker PerfMarkerBallOctree = new("CreateKinematicOctree"); + + internal static NativeOctree CreateOctree(ref NativeColliders kinematicColliders, in AABB playfieldBounds) + { + PerfMarkerBallOctree.Begin(); + var octree = new NativeOctree(playfieldBounds, 1024, 10, Allocator.TempJob); + + for (var i = 0; i < kinematicColliders.Length; i++) { + octree.Insert(i, kinematicColliders.GetAabb(i)); + } + + PerfMarkerBallOctree.End(); + return octree; + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs.meta new file mode 100644 index 000000000..522a1e5da --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 04ece8618aa24f0c8bc5a4437ae4a7b9 +timeCreated: 1699026328 \ No newline at end of file diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs index c7a631bb9..bad5ed525 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs @@ -26,6 +26,7 @@ internal struct PhysicsState internal PhysicsEnv Env; internal NativeOctree Octree; internal NativeColliders Colliders; + internal NativeColliders KinematicColliders; internal NativeQueue.ParallelWriter EventQueue; internal InsideOfs InsideOfs; internal NativeParallelHashMap Balls; @@ -42,7 +43,7 @@ internal struct PhysicsState internal NativeParallelHashSet DisabledCollisionItems; internal bool SwapBallCollisionHandling; - public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, + public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, ref NativeColliders kinematicColliders, ref NativeQueue.ParallelWriter eventQueue, ref InsideOfs insideOfs, ref NativeParallelHashMap balls, ref NativeParallelHashMap bumperStates, ref NativeParallelHashMap dropTargetStates, ref NativeParallelHashMap flipperStates, ref NativeParallelHashMap gateStates, @@ -54,6 +55,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native Env = env; Octree = octree; Colliders = colliders; + KinematicColliders = kinematicColliders; EventQueue = eventQueue; InsideOfs = insideOfs; Balls = balls; @@ -74,7 +76,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native internal ref ColliderHeader GetColliderHeader(int colliderId) => ref Colliders.GetHeader(colliderId); internal ColliderType GetColliderType(int colliderId) => Colliders.GetHeader(colliderId).Type; - internal bool IsColliderActive(int colliderId) => !DisabledCollisionItems.Contains(Colliders.GetItemId(colliderId)); + internal bool IsColliderActive(ref NativeColliders colliders, int colliderId) => !DisabledCollisionItems.Contains(colliders.GetItemId(colliderId)); #region States @@ -107,73 +109,73 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native #region Hit Test - internal float HitTest(int colliderId, ref BallState ball, ref CollisionEventData newCollEvent, ref NativeList contacts, ref PhysicsState state) + internal float HitTest(ref NativeColliders colliders, int colliderId, ref BallState ball, ref CollisionEventData newCollEvent, ref NativeList contacts) { - if (IsInactiveDropTarget(colliderId)) { + if (IsInactiveDropTarget(ref colliders, colliderId)) { return -1f; } switch (GetColliderType(colliderId)) { case ColliderType.Bumper: case ColliderType.Circle: - return Colliders.Circle(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Circle(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.Gate: - return Colliders.Gate(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Gate(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.Line: - return Colliders.Line(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Line(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.LineZ: - return Colliders.LineZ(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); + return colliders.LineZ(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); case ColliderType.Line3D: - return Colliders.Line3D(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); + return colliders.Line3D(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); case ColliderType.LineSlingShot: - return Colliders.LineSlingShot(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, in ball, ball.CollisionEvent.HitTime); + return colliders.LineSlingShot(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.Point: - return Colliders.Point(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); + return colliders.Point(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); case ColliderType.Plane: - return Colliders.Plane(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); + return colliders.Plane(colliderId).HitTest(ref newCollEvent, in ball, ball.CollisionEvent.HitTime); case ColliderType.Spinner: - return Colliders.Spinner(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Spinner(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.Triangle: - return Colliders.Triangle(colliderId).HitTest(ref newCollEvent, in state.InsideOfs, in ball, + return colliders.Triangle(colliderId).HitTest(ref newCollEvent, in InsideOfs, in ball, ball.CollisionEvent.HitTime); case ColliderType.KickerCircle: case ColliderType.TriggerCircle: - return Colliders.Circle(colliderId).HitTestBasicRadius(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Circle(colliderId).HitTestBasicRadius(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime, false, false, false); case ColliderType.TriggerLine: - return Colliders.Line(colliderId).HitTestBasic(ref newCollEvent, ref state.InsideOfs, in ball, + return colliders.Line(colliderId).HitTestBasic(ref newCollEvent, ref InsideOfs, in ball, ball.CollisionEvent.HitTime, false, false, false); case ColliderType.Flipper: - ref var flipperState = ref state.GetFlipperState(colliderId); - return Colliders.Flipper(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, ref flipperState.Hit, + ref var flipperState = ref GetFlipperState(colliderId); + return colliders.Flipper(colliderId).HitTest(ref newCollEvent, ref InsideOfs, ref flipperState.Hit, in flipperState.Movement, in flipperState.Tricks, in flipperState.Static, in ball, ball.CollisionEvent.HitTime); case ColliderType.Plunger: - ref var plungerState = ref state.GetPlungerState(colliderId); - return Colliders.Plunger(colliderId).HitTest(ref newCollEvent, ref state.InsideOfs, ref plungerState.Movement, + ref var plungerState = ref GetPlungerState(colliderId); + return colliders.Plunger(colliderId).HitTest(ref newCollEvent, ref InsideOfs, ref plungerState.Movement, in plungerState.Collider, in plungerState.Static, in ball, ball.CollisionEvent.HitTime); } return -1f; } - private bool IsInactiveDropTarget(int colliderId) + private bool IsInactiveDropTarget(ref NativeColliders colliders, int colliderId) { - if (Colliders.GetItemType(colliderId) == ItemType.HitTarget && HasDropTargetState(colliderId)) { + if (colliders.GetItemType(colliderId) == ItemType.HitTarget && HasDropTargetState(colliderId)) { ref var dropTargetState = ref GetDropTargetState(colliderId); if (dropTargetState.Animation.IsDropped || dropTargetState.Animation.MoveAnimation) { // QUICKFIX so that DT is not triggered twice return true; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs index 246dd1f8b..887c8d9e1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs @@ -26,6 +26,7 @@ public static class PhysicsStaticNarrowPhase private static readonly ProfilerMarker PerfMarkerNarrowPhase = new("NarrowPhase"); internal static void FindNextCollision( + ref NativeColliders colliders, float hitTime, ref BallState ball, ref NativeParallelHashSet overlappingColliders, @@ -35,25 +36,18 @@ ref PhysicsState state { PerfMarkerNarrowPhase.Begin(); - // init contacts and event - ball.CollisionEvent.ClearCollider(hitTime); // search upto current hit time - using (var enumerator = overlappingColliders.GetEnumerator()) { while (enumerator.MoveNext()) { var overlappingColliderId = enumerator.Current; - if (!state.IsColliderActive(overlappingColliderId)) { + if (!state.IsColliderActive(ref colliders, overlappingColliderId)) { continue; } var newCollEvent = new CollisionEventData(); - var newTime = state.HitTest(overlappingColliderId, ref ball, ref newCollEvent, ref contacts, ref state); + var newTime = state.HitTest(ref colliders, overlappingColliderId, ref ball, ref newCollEvent, ref contacts); SaveCollisions(ref ball, ref newCollEvent, ref contacts, overlappingColliderId, newTime); } } - // no negative time allowed - if (ball.CollisionEvent.HitTime < 0) { - ball.CollisionEvent.ClearCollider(); - } PerfMarkerNarrowPhase.End(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs index f247a812c..88bcf89b2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs @@ -34,6 +34,8 @@ internal struct PhysicsUpdateJob : IJob public NativeArray PhysicsEnv; public NativeOctree Octree; public NativeColliders Colliders; + public NativeColliders KinematicColliders; + public NativeColliders KinematicCollidersAtIdentity; public InsideOfs InsideOfs; public NativeQueue.ParallelWriter Events; public AABB PlayfieldBounds; @@ -55,7 +57,7 @@ internal struct PhysicsUpdateJob : IJob public void Execute() { var env = PhysicsEnv[0]; - var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref Events, ref InsideOfs, ref Balls, + var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, ref Events, ref InsideOfs, ref Balls, ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates, ref HitTargetStates, ref KickerStates, ref PlungerStates, ref SpinnerStates, ref SurfaceStates, ref TriggerStates, ref DisabledCollisionItems, ref SwapBallCollisionHandling); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs index 9fe5699b1..4f4358244 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs @@ -1,6 +1,6 @@ namespace VisualPinball.Unity { - public enum NativeColliderIds + public struct NativeColliderIds { } From d9d19fffc5a981352ba87a42f8f9e955d7fe9152 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 00:11:04 +0100 Subject: [PATCH 03/14] kinematic: Add interface for kinematic colliders components. --- .../VPT/IKinematicColliderComponent.cs | 27 +++++++++++++++++++ .../VPT/IKinematicColliderComponent.cs.meta | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs new file mode 100644 index 000000000..37b59acef --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs @@ -0,0 +1,27 @@ +// Visual Pinball Engine +// Copyright (C) 2023 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using VisualPinball.Engine.Math; + +namespace VisualPinball.Unity +{ + public interface IKinematicColliderComponent + { + public bool IsKinematic { get; } + public int ItemId { get; } + public Matrix3D GetTransformationMatrix(); + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs.meta new file mode 100644 index 000000000..7fcfa17d4 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 953c3c1b3d4c4aea9d41b5043345c551 +timeCreated: 1699050846 \ No newline at end of file From 20363e5c80ce3228749adaacf16a0ef41189f60a Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 00:11:24 +0100 Subject: [PATCH 04/14] fix: Don't crash when triggers don't have animation or mesh components. --- .../VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs index 315d34357..af1f27461 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs @@ -264,9 +264,9 @@ internal TriggerState CreateState() gameObject.GetInstanceID(), animComponent ? animComponent.gameObject.GetInstanceID() : 0, new TriggerStaticState { - AnimSpeed = animComponent.AnimSpeed, + AnimSpeed = animComponent ? animComponent.AnimSpeed : 0, Radius = collComponent.HitCircleRadius, - Shape = meshComponent.Shape, + Shape = meshComponent ? meshComponent.Shape : 0, TableScaleZ = 1f }, new TriggerMovementState(), From bf428e5e2a429526d9f26c9f23884c2216d77c46 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 00:45:23 +0100 Subject: [PATCH 05/14] kinematic: Add collision and contact. --- .../VisualPinball.Unity/Game/PhysicsCycle.cs | 8 ++-- .../VisualPinball.Unity/Game/PhysicsState.cs | 6 +-- .../Game/PhysicsStaticCollision.cs | 41 +++++++++++-------- .../Game/PhysicsStaticNarrowPhase.cs | 7 ++-- .../Physics/Collider/ColliderReference.cs | 8 ++-- .../Physics/Collision/CollisionEventData.cs | 4 +- .../Physics/Collision/ContactPhysics.cs | 12 ++++-- .../Physics/NativeColliders.cs | 3 ++ .../VPT/Primitive/PrimitiveApi.cs | 2 +- 9 files changed, 54 insertions(+), 37 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs index ca4349eeb..d31805425 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs @@ -45,6 +45,8 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati // create octree of ball-to-ball collision // it's okay to have this code outside of the inner loop, as the ball hitrects already include the maximum distance they can travel in that timespan var ballOctree = PhysicsDynamicBroadPhase.CreateOctree(ref state.Balls, in playfieldBounds); + + // create octree of kinematic-to-ball collision var kineticOctree = PhysicsKinematicBroadPhase.CreateOctree(ref state.KinematicColliders, in playfieldBounds); while (dTime > 0) { @@ -69,10 +71,10 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati // hit testing (overlappingColliders is cleared in broad phase) PhysicsStaticBroadPhase.FindOverlaps(in state.Octree, in ball, ref overlappingColliders); - PhysicsStaticNarrowPhase.FindNextCollision(ref state.Colliders, hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state); + PhysicsStaticNarrowPhase.FindNextCollision(ref state.Colliders, ref ball, ref overlappingColliders, ref _contacts, ref state); PhysicsStaticBroadPhase.FindOverlaps(in kineticOctree, in ball, ref overlappingColliders); - PhysicsStaticNarrowPhase.FindNextCollision(ref state.KinematicColliders, hitTime, ref ball, ref overlappingColliders, ref _contacts, ref state); + PhysicsStaticNarrowPhase.FindNextCollision(ref state.KinematicColliders, ref ball, ref overlappingColliders, ref _contacts, ref state); // no negative time allowed if (ball.CollisionEvent.HitTime < 0) { @@ -141,7 +143,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati // dynamic collision PhysicsDynamicCollision.Collide(hitTime, ref ball, ref state); - // static collision + // static & kinematic collision PhysicsStaticCollision.Collide(hitTime, ref ball, ref state); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs index bad5ed525..02ed3a8c8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs @@ -73,8 +73,8 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native SwapBallCollisionHandling = swapBallCollisionHandling; } - internal ref ColliderHeader GetColliderHeader(int colliderId) => ref Colliders.GetHeader(colliderId); - internal ColliderType GetColliderType(int colliderId) => Colliders.GetHeader(colliderId).Type; + internal ref ColliderHeader GetColliderHeader(ref NativeColliders colliders, int colliderId) => ref colliders.GetHeader(colliderId); + internal ColliderType GetColliderType(ref NativeColliders colliders, int colliderId) => colliders.GetHeader(colliderId).Type; internal bool IsColliderActive(ref NativeColliders colliders, int colliderId) => !DisabledCollisionItems.Contains(colliders.GetItemId(colliderId)); @@ -114,7 +114,7 @@ internal float HitTest(ref NativeColliders colliders, int colliderId, ref BallSt if (IsInactiveDropTarget(ref colliders, colliderId)) { return -1f; } - switch (GetColliderType(colliderId)) { + switch (GetColliderType(ref colliders, colliderId)) { case ColliderType.Bumper: case ColliderType.Circle: return colliders.Circle(colliderId).HitTest(ref newCollEvent, ref InsideOfs, in ball, diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs index b8432e7e5..1ecc41887 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs @@ -25,52 +25,59 @@ internal static class PhysicsStaticCollision { internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState state) { - // find balls with hit objects and minimum time if (ball.CollisionEvent.ColliderId < 0 || ball.CollisionEvent.HitTime > hitTime) { return; } + if (ball.CollisionEvent.IsKinematic) { + Collide(ref state.KinematicColliders, ref ball, ref state); + } else { + Collide(ref state.Colliders, ref ball, ref state); + } + } + + private static void Collide(ref NativeColliders colliders, ref BallState ball, ref PhysicsState state) + { var colliderId = ball.CollisionEvent.ColliderId; - var collHeader = state.GetColliderHeader(colliderId); - if (CollidesWithItem(ref collHeader, ref ball, ref state)) { + var collHeader = state.GetColliderHeader(ref colliders, colliderId); + if (CollidesWithItem(ref colliders, ref collHeader, ref ball, ref state)) { return; } - ref var cols = ref state.Colliders; - switch (state.GetColliderType(colliderId)) { + switch (state.GetColliderType(ref colliders, colliderId)) { case ColliderType.Circle: - ref var circleCollider = ref cols.Circle(colliderId); + ref var circleCollider = ref colliders.Circle(colliderId); circleCollider.Collide(ref ball, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.Plane: - ref var planeCollider = ref cols.Plane(colliderId); + ref var planeCollider = ref colliders.Plane(colliderId); planeCollider.Collide(ref ball, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.Line: - ref var lineCollider = ref cols.Line(colliderId); + ref var lineCollider = ref colliders.Line(colliderId); lineCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.LineZ: - ref var lineZCollider = ref cols.LineZ(colliderId); + ref var lineZCollider = ref colliders.LineZ(colliderId); lineZCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.Triangle: - ref var triangleCollider = ref cols.Triangle(colliderId); + ref var triangleCollider = ref colliders.Triangle(colliderId); triangleCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.Line3D: - ref var line3DCollider = ref cols.Line3D(colliderId); + ref var line3DCollider = ref colliders.Line3D(colliderId); line3DCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random); break; case ColliderType.Point: - ref var pointCollider = ref cols.Point(colliderId); + ref var pointCollider = ref colliders.Point(colliderId); pointCollider.Collide(ref ball, ref state.EventQueue, in ball.CollisionEvent, ref state.Env.Random); break; @@ -82,7 +89,7 @@ internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState case ColliderType.Flipper: ref var flipperState = ref state.GetFlipperState(colliderId); - ref var flipperCollider = ref cols.Flipper(colliderId); + ref var flipperCollider = ref colliders.Flipper(colliderId); flipperCollider.Collide(ref ball, ref ball.CollisionEvent, ref flipperState.Movement, ref state.EventQueue, in ball.Id, in flipperState.Tricks, in flipperState.Static, in flipperState.Velocity, in flipperState.Hit, state.Env.TimeMsec @@ -97,7 +104,7 @@ internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState case ColliderType.LineSlingShot: ref var surfaceState = ref state.GetSurfaceState(colliderId); - ref var surfaceCollider = ref cols.LineSlingShot(colliderId); + ref var surfaceCollider = ref colliders.LineSlingShot(colliderId); surfaceCollider.Collide(ref ball, ref state.EventQueue, in surfaceState.Slingshot, in ball.CollisionEvent, ref state.Env.Random); break; @@ -128,16 +135,14 @@ internal static void Collide(float hitTime, ref BallState ball, ref PhysicsState ball.CollisionEvent.ClearCollider(); } - private static bool CollidesWithItem(ref ColliderHeader collHeader, ref BallState ball, ref PhysicsState state) + private static bool CollidesWithItem(ref NativeColliders colliders, ref ColliderHeader collHeader, ref BallState ball, ref PhysicsState state) { - ref var cols = ref state.Colliders; - // hit target var colliderId = ball.CollisionEvent.ColliderId; if (collHeader.ItemType == ItemType.HitTarget) { var normal = collHeader.Type == ColliderType.Triangle - ? cols.Triangle(colliderId).Normal() + ? colliders.Triangle(colliderId).Normal() : ball.CollisionEvent.HitNormal; if (state.HasDropTargetState(colliderId)) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs index 887c8d9e1..211b16a7d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticNarrowPhase.cs @@ -27,7 +27,6 @@ public static class PhysicsStaticNarrowPhase internal static void FindNextCollision( ref NativeColliders colliders, - float hitTime, ref BallState ball, ref NativeParallelHashSet overlappingColliders, ref NativeList contacts, @@ -44,7 +43,7 @@ ref PhysicsState state } var newCollEvent = new CollisionEventData(); var newTime = state.HitTest(ref colliders, overlappingColliderId, ref ball, ref newCollEvent, ref contacts); - SaveCollisions(ref ball, ref newCollEvent, ref contacts, overlappingColliderId, newTime); + SaveCollisions(ref ball, ref newCollEvent, ref contacts, overlappingColliderId, newTime, colliders.KinematicColliders); } } @@ -52,12 +51,12 @@ ref PhysicsState state } private static void SaveCollisions(ref BallState ball, ref CollisionEventData newCollEvent, - ref NativeList contacts, int colliderId, float newTime) + ref NativeList contacts, int colliderId, float newTime, bool isKinematic) { var validHit = newTime >= 0f && !Math.Sign(newTime) && newTime <= ball.CollisionEvent.HitTime; if (newCollEvent.IsContact || validHit) { // todo why newCollEvent.IsContact? it's not in vpx source - newCollEvent.SetCollider(colliderId); + newCollEvent.SetCollider(colliderId, isKinematic); newCollEvent.HitTime = newTime; if (newCollEvent.IsContact) { // remember all contacts? contacts.Add(new ContactBufferElement(ball.Id, newCollEvent)); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs index f912d613c..7505d6974 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs @@ -37,11 +37,11 @@ public struct ColliderReference : IDisposable public NativeList Lookup; - private bool _trackReferences; + public readonly bool KinematicColliders; private NativeParallelHashMap> _references; - public ColliderReference(Allocator allocator, bool trackReferences = false) + public ColliderReference(Allocator allocator, bool kinematicColliders = false) { CircleColliders = new NativeList(allocator); FlipperColliders = new NativeList(allocator); @@ -57,7 +57,7 @@ public ColliderReference(Allocator allocator, bool trackReferences = false) PlaneColliders = new NativeList(allocator); Lookup = new NativeList(allocator); - _trackReferences = trackReferences; + KinematicColliders = kinematicColliders; _references = new NativeParallelHashMap>(0, allocator); } @@ -115,7 +115,7 @@ private ICollider LookupCollider(int i) private void TrackReference(int itemId, int colliderId) { - if (!_trackReferences) { + if (!KinematicColliders) { return; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/CollisionEventData.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/CollisionEventData.cs index 7e9ad88da..eb332dda6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/CollisionEventData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/CollisionEventData.cs @@ -29,12 +29,14 @@ internal struct CollisionEventData public bool IsContact; public int ColliderId; + public bool IsKinematic; public int BallId; - public void SetCollider(int colliderId) + public void SetCollider(int colliderId, bool isKinematic) { // it's either collider id (for static colliders) or ball id (for dynamic colliders) ColliderId = colliderId; + IsKinematic = isKinematic; BallId = 0; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ContactPhysics.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ContactPhysics.cs index f1523ccac..d43c0d46d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ContactPhysics.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ContactPhysics.cs @@ -22,9 +22,13 @@ internal static void Update(ref ContactBufferElement contact, ref BallState ball { ref var collEvent = ref contact.CollEvent; if (collEvent.ColliderId > -1) { // collide with static collider - var collHeader = state.GetColliderHeader(collEvent.ColliderId); + var collHeader = collEvent.IsKinematic + ? ref state.GetColliderHeader(ref state.KinematicColliders, collEvent.ColliderId) + : ref state.GetColliderHeader(ref state.Colliders, collEvent.ColliderId); if (collHeader.Type == ColliderType.Flipper) { - ref var flipperCollider = ref state.Colliders.Flipper(collEvent.ColliderId); + var flipperCollider = collEvent.IsKinematic + ? ref state.KinematicColliders.Flipper(collEvent.ColliderId) + : ref state.Colliders.Flipper(collEvent.ColliderId); ref var flipperState = ref state.GetFlipperState(collEvent.ColliderId); flipperCollider.Contact(ref ball, ref flipperState.Movement, in collEvent, in flipperState.Static, in flipperState.Velocity, hitTime, in state.Env.Gravity); @@ -32,7 +36,9 @@ internal static void Update(ref ContactBufferElement contact, ref BallState ball Collider.Contact(in collHeader, ref ball, in collEvent, hitTime, in state.Env.Gravity); } } else if (collEvent.BallId != 0) { // collide with ball - ref var collHeader = ref state.GetColliderHeader(contact.CollEvent.ColliderId); + var collHeader = collEvent.IsKinematic + ? ref state.GetColliderHeader(ref state.KinematicColliders, contact.CollEvent.ColliderId) + : ref state.GetColliderHeader(ref state.Colliders, contact.CollEvent.ColliderId); BallCollider.HandleStaticContact(ref ball, in collEvent, collHeader.Material.Friction, hitTime, state.Env.Gravity); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs index bb0cac8d2..28a3b8490 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs @@ -37,6 +37,7 @@ public unsafe struct NativeColliders : IDisposable private static readonly ProfilerMarker PerfMarker = new("NativeColliders Allocation"); public int Length => m_Length; + public bool KinematicColliders => m_KinematicColliders; /// /// An array that links the collider IDs (the key) to the position in the respective collider buffer. @@ -56,6 +57,7 @@ public unsafe struct NativeColliders : IDisposable [NativeDisableUnsafePtrRestriction] private void* m_PlaneColliderBuffer; private readonly Allocator m_AllocatorLabel; + private readonly bool m_KinematicColliders; private int m_Length; // must be here, and called like that. @@ -81,6 +83,7 @@ public NativeColliders(ref ColliderReference colRef, Allocator allocator) PerfMarker.Begin(); m_Length = colRef.Lookup.Length; + m_KinematicColliders = colRef.KinematicColliders; long size = UnsafeUtility.SizeOf() * colRef.Lookup.Length; m_LookupBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs index f348a3481..ece1cca06 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs @@ -46,7 +46,7 @@ internal PrimitiveApi(GameObject go, Player player, PhysicsEngine physicsEngine) protected override void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new PrimitiveColliderGenerator(this, MainComponent, MainComponent); - var colls = ColliderComponent.IsKinematic ? kinematicColliders : colliders; + var colls = ColliderComponent._isKinematic ? kinematicColliders : colliders; colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref colls); } From 8355a9af24066cf297e5a95b8c7f04978e2497ba Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 00:45:47 +0100 Subject: [PATCH 06/14] kinematic: Pass transformation matrices to physics loop. --- .../Primitive/PrimitiveColliderInspector.cs | 2 +- .../VisualPinball.Unity/Game/PhysicsEngine.cs | 31 +++++++++++++++++-- .../VisualPinball.Unity/Game/PhysicsState.cs | 4 +++ .../Game/PhysicsUpdateJob.cs | 4 ++- .../Primitive/PrimitiveColliderComponent.cs | 10 ++++-- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs index 3b58ef8f5..0fa2bccca 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs @@ -51,7 +51,7 @@ protected override void OnEnable() _elasticityFalloffProperty = serializedObject.FindProperty(nameof(PrimitiveColliderComponent.ElasticityFalloff)); _frictionProperty = serializedObject.FindProperty(nameof(PrimitiveColliderComponent.Friction)); _scatterProperty = serializedObject.FindProperty(nameof(PrimitiveColliderComponent.Scatter)); - _isKinematicProperty = serializedObject.FindProperty(nameof(PrimitiveColliderComponent.IsKinematic)); + _isKinematicProperty = serializedObject.FindProperty(nameof(PrimitiveColliderComponent._isKinematic)); } public override void OnInspectorGUI() diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index 3b7d9cb0e..e12d25d4e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -64,7 +64,6 @@ public class PhysicsEngine : MonoBehaviour [NonSerialized] private NativeParallelHashSet _disabledCollisionItems = new(0, Allocator.Persistent); [NonSerialized] private bool _swapBallCollisionHandling; - [NonSerialized] private NativeParallelHashMap _itemTransforms = new(0, Allocator.Persistent); [NonSerialized] private NativeParallelHashMap _colliderLookup = new(0, Allocator.Persistent); #endregion @@ -72,6 +71,8 @@ public class PhysicsEngine : MonoBehaviour #region Transforms [NonSerialized] private readonly Dictionary _transforms = new(); + [NonSerialized] private NativeParallelHashMap _kinematicTransforms = new(0, Allocator.Persistent); + [NonSerialized] private NativeParallelHashMap _updatedKinematicTransforms = new(0, Allocator.Persistent); [NonSerialized] private readonly Dictionary _skinnedMeshRenderers = new(); #endregion @@ -80,6 +81,8 @@ public class PhysicsEngine : MonoBehaviour [NonSerialized] private readonly List _scheduledActions = new(); [NonSerialized] private Player _player; + [NonSerialized] private IKinematicColliderComponent[] _kinematicColliderComponents; + private static ulong NowUsec => (ulong)(Time.timeAsDouble * 1000000); @@ -171,6 +174,7 @@ private void Awake() _player = GetComponentInParent(); _insideOfs = new InsideOfs(Allocator.Persistent); _physicsEnv[0] = new PhysicsEnv(NowUsec, GetComponentInChildren(), GravityStrength); + _kinematicColliderComponents = GetComponentsInChildren(); } private void Start() @@ -213,10 +217,28 @@ private void Start() foreach (var ball in balls) { Register(ball); } + + // get kinetic collider matrices + foreach (var coll in _kinematicColliderComponents) { + _kinematicTransforms[coll.ItemId] = coll.GetTransformationMatrix().ToUnityMatrix(); + } } private void Update() { + // check for updated kinematic transforms + _updatedKinematicTransforms.Clear(); + foreach (var coll in _kinematicColliderComponents) { + if (!coll.IsKinematic) { + continue; + } + var lastTransformationMatrix = _kinematicTransforms[coll.ItemId]; + var currTransformationMatrix = (float4x4)coll.GetTransformationMatrix().ToUnityMatrix(); + if (!lastTransformationMatrix.Equals(currTransformationMatrix)) { + _updatedKinematicTransforms.Add(coll.ItemId, currTransformationMatrix); + } + } + // prepare job var events = _eventQueue.AsParallelWriter(); var updatePhysics = new PhysicsUpdateJob { @@ -227,6 +249,7 @@ private void Update() Colliders = _colliders, KinematicColliders = _kinematicColliders, KinematicCollidersAtIdentity = _kinematicCollidersAtIdentity, + UpdatedKinematicTransforms = _updatedKinematicTransforms, InsideOfs = _insideOfs, Events = events, Balls = _ballStates, @@ -246,7 +269,8 @@ private void Update() }; var env = _physicsEnv[0]; - var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, ref events, ref _insideOfs, ref _ballStates, + var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, ref _updatedKinematicTransforms, + ref events, ref _insideOfs, ref _ballStates, ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates, ref _hitTargetStates, ref _kickerStates, ref _plungerStates, ref _spinnerStates, ref _surfaceStates, ref _triggerStates, ref _disabledCollisionItems, ref _swapBallCollisionHandling); @@ -412,6 +436,9 @@ private void OnDestroy() } _triggerStates.Dispose(); _disabledCollisionItems.Dispose(); + _kinematicTransforms.Dispose(); + _updatedKinematicTransforms.Dispose(); + _colliderLookup.Dispose(); } #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs index 02ed3a8c8..ca849df4f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs @@ -16,6 +16,7 @@ using NativeTrees; using Unity.Collections; +using Unity.Mathematics; using VisualPinball.Engine.VPT; using VisualPinball.Unity.Collections; @@ -27,6 +28,7 @@ internal struct PhysicsState internal NativeOctree Octree; internal NativeColliders Colliders; internal NativeColliders KinematicColliders; + internal NativeParallelHashMap UpdatedKinematicTransforms; internal NativeQueue.ParallelWriter EventQueue; internal InsideOfs InsideOfs; internal NativeParallelHashMap Balls; @@ -44,6 +46,7 @@ internal struct PhysicsState internal bool SwapBallCollisionHandling; public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, ref NativeColliders kinematicColliders, + ref NativeParallelHashMap updatedKinematicTransforms, ref NativeQueue.ParallelWriter eventQueue, ref InsideOfs insideOfs, ref NativeParallelHashMap balls, ref NativeParallelHashMap bumperStates, ref NativeParallelHashMap dropTargetStates, ref NativeParallelHashMap flipperStates, ref NativeParallelHashMap gateStates, @@ -56,6 +59,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native Octree = octree; Colliders = colliders; KinematicColliders = kinematicColliders; + UpdatedKinematicTransforms = updatedKinematicTransforms; EventQueue = eventQueue; InsideOfs = insideOfs; Balls = balls; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs index 88bcf89b2..cd35d7e6a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs @@ -17,6 +17,7 @@ using Unity.Burst; using Unity.Collections; using Unity.Jobs; +using Unity.Mathematics; using VisualPinball.Engine.Common; namespace VisualPinball.Unity @@ -36,6 +37,7 @@ internal struct PhysicsUpdateJob : IJob public NativeColliders Colliders; public NativeColliders KinematicColliders; public NativeColliders KinematicCollidersAtIdentity; + public NativeParallelHashMap UpdatedKinematicTransforms; public InsideOfs InsideOfs; public NativeQueue.ParallelWriter Events; public AABB PlayfieldBounds; @@ -57,7 +59,7 @@ internal struct PhysicsUpdateJob : IJob public void Execute() { var env = PhysicsEnv[0]; - var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, ref Events, ref InsideOfs, ref Balls, + var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, ref UpdatedKinematicTransforms, ref Events, ref InsideOfs, ref Balls, ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates, ref HitTargetStates, ref KickerStates, ref PlungerStates, ref SpinnerStates, ref SurfaceStates, ref TriggerStates, ref DisabledCollisionItems, ref SwapBallCollisionHandling); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs index f67120d0c..e261f7f54 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs @@ -17,12 +17,14 @@ // ReSharper disable InconsistentNaming using UnityEngine; +using UnityEngine.Serialization; +using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT.Primitive; namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Collision/Primitive Collider")] - public class PrimitiveColliderComponent : ColliderComponent + public class PrimitiveColliderComponent : ColliderComponent, IKinematicColliderComponent { #region Data @@ -57,7 +59,11 @@ public class PrimitiveColliderComponent : ColliderComponent _isKinematic; + public int ItemId => MainComponent.gameObject.GetInstanceID(); + public Matrix3D GetTransformationMatrix() => MainComponent.GetTransformationMatrix(); #endregion From 2e2b74a078aec2de9e428951032750fa97b102ff Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 00:58:23 +0100 Subject: [PATCH 07/14] kinematic: Pass kinematic colliders at identity to physics loop. --- .../VisualPinball.Unity/Game/PhysicsEngine.cs | 7 ++++--- .../VisualPinball.Unity/Game/PhysicsState.cs | 9 ++++++--- .../VisualPinball.Unity/Game/PhysicsUpdateJob.cs | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index e12d25d4e..f7b512332 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -195,6 +195,7 @@ private void Start() // allocate colliders _colliders = new NativeColliders(ref colliders, Allocator.Persistent); _kinematicColliders = new NativeColliders(ref kinematicColliders, Allocator.Persistent); + // todo make them actually at identity by reverse-applying their matrices _kinematicCollidersAtIdentity = new NativeColliders(ref kinematicColliders, Allocator.Persistent); // create octree @@ -229,7 +230,7 @@ private void Update() // check for updated kinematic transforms _updatedKinematicTransforms.Clear(); foreach (var coll in _kinematicColliderComponents) { - if (!coll.IsKinematic) { + if (!coll.IsKinematic) { // kinematic enabled? continue; } var lastTransformationMatrix = _kinematicTransforms[coll.ItemId]; @@ -269,8 +270,8 @@ private void Update() }; var env = _physicsEnv[0]; - var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, ref _updatedKinematicTransforms, - ref events, ref _insideOfs, ref _ballStates, + var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, + ref _kinematicCollidersAtIdentity, ref _updatedKinematicTransforms, ref events, ref _insideOfs, ref _ballStates, ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates, ref _hitTargetStates, ref _kickerStates, ref _plungerStates, ref _spinnerStates, ref _surfaceStates, ref _triggerStates, ref _disabledCollisionItems, ref _swapBallCollisionHandling); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs index ca849df4f..dbd6bfcc2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs @@ -28,6 +28,7 @@ internal struct PhysicsState internal NativeOctree Octree; internal NativeColliders Colliders; internal NativeColliders KinematicColliders; + internal NativeColliders KinematicCollidersAtIdentity; internal NativeParallelHashMap UpdatedKinematicTransforms; internal NativeQueue.ParallelWriter EventQueue; internal InsideOfs InsideOfs; @@ -45,9 +46,10 @@ internal struct PhysicsState internal NativeParallelHashSet DisabledCollisionItems; internal bool SwapBallCollisionHandling; - public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, ref NativeColliders kinematicColliders, - ref NativeParallelHashMap updatedKinematicTransforms, - ref NativeQueue.ParallelWriter eventQueue, ref InsideOfs insideOfs, ref NativeParallelHashMap balls, + public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, + ref NativeColliders kinematicColliders, ref NativeColliders kinematicCollidersAtIdentity, + ref NativeParallelHashMap updatedKinematicTransforms, ref NativeQueue.ParallelWriter eventQueue, + ref InsideOfs insideOfs, ref NativeParallelHashMap balls, ref NativeParallelHashMap bumperStates, ref NativeParallelHashMap dropTargetStates, ref NativeParallelHashMap flipperStates, ref NativeParallelHashMap gateStates, ref NativeParallelHashMap hitTargetStates, ref NativeParallelHashMap kickerStates, @@ -59,6 +61,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native Octree = octree; Colliders = colliders; KinematicColliders = kinematicColliders; + KinematicCollidersAtIdentity = kinematicCollidersAtIdentity; UpdatedKinematicTransforms = updatedKinematicTransforms; EventQueue = eventQueue; InsideOfs = insideOfs; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs index cd35d7e6a..5a0c7e850 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs @@ -59,7 +59,8 @@ internal struct PhysicsUpdateJob : IJob public void Execute() { var env = PhysicsEnv[0]; - var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, ref UpdatedKinematicTransforms, ref Events, ref InsideOfs, ref Balls, + var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, + ref KinematicCollidersAtIdentity, ref UpdatedKinematicTransforms, ref Events, ref InsideOfs, ref Balls, ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates, ref HitTargetStates, ref KickerStates, ref PlungerStates, ref SpinnerStates, ref SurfaceStates, ref TriggerStates, ref DisabledCollisionItems, ref SwapBallCollisionHandling); From e12dc924dba928647eee7416f9910d8261548216 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 15:56:24 +0100 Subject: [PATCH 08/14] kinematic: Pass kinematic transformation matrices to physics loop. --- .../VisualPinball.Unity/Game/PhysicsCycle.cs | 1 + .../VisualPinball.Unity/Game/PhysicsEngine.cs | 17 +++++--- .../Game/PhysicsKinematicBroadPhase.cs | 14 +++++++ .../VisualPinball.Unity/Game/PhysicsState.cs | 26 ++++++++++++- .../Game/PhysicsUpdateJob.cs | 5 ++- .../Physics/Collider/ColliderReference.cs | 10 +++++ .../Physics/Collider/Line3DCollider.cs | 4 ++ .../Physics/Collider/PointCollider.cs | 5 +++ .../Physics/Collider/TriangleCollider.cs | 13 +++++-- .../Physics/NativeColliderIds.cs | 39 +++++++++++++++++-- 10 files changed, 119 insertions(+), 15 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs index d31805425..af2e1f61c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs @@ -47,6 +47,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati var ballOctree = PhysicsDynamicBroadPhase.CreateOctree(ref state.Balls, in playfieldBounds); // create octree of kinematic-to-ball collision + PhysicsKinematicBroadPhase.TransformColliders(ref state); var kineticOctree = PhysicsKinematicBroadPhase.CreateOctree(ref state.KinematicColliders, in playfieldBounds); while (dTime > 0) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index f7b512332..67fc12896 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -47,6 +47,7 @@ public class PhysicsEngine : MonoBehaviour [NonSerialized] private NativeColliders _colliders; [NonSerialized] private NativeColliders _kinematicColliders; [NonSerialized] private NativeColliders _kinematicCollidersAtIdentity; + [NonSerialized] private NativeParallelHashMap _kinematicColliderLookups; [NonSerialized] private NativeArray _physicsEnv = new(1, Allocator.Persistent); [NonSerialized] private NativeQueue _eventQueue = new(Allocator.Persistent); @@ -64,8 +65,6 @@ public class PhysicsEngine : MonoBehaviour [NonSerialized] private NativeParallelHashSet _disabledCollisionItems = new(0, Allocator.Persistent); [NonSerialized] private bool _swapBallCollisionHandling; - [NonSerialized] private NativeParallelHashMap _colliderLookup = new(0, Allocator.Persistent); - #endregion #region Transforms @@ -197,6 +196,7 @@ private void Start() _kinematicColliders = new NativeColliders(ref kinematicColliders, Allocator.Persistent); // todo make them actually at identity by reverse-applying their matrices _kinematicCollidersAtIdentity = new NativeColliders(ref kinematicColliders, Allocator.Persistent); + _kinematicColliderLookups = kinematicColliders.CreateLookup(Allocator.Persistent); // create octree var elapsedMs = sw.Elapsed.TotalMilliseconds; @@ -250,6 +250,7 @@ private void Update() Colliders = _colliders, KinematicColliders = _kinematicColliders, KinematicCollidersAtIdentity = _kinematicCollidersAtIdentity, + KinematicColliderLookups = _kinematicColliderLookups, UpdatedKinematicTransforms = _updatedKinematicTransforms, InsideOfs = _insideOfs, Events = events, @@ -271,8 +272,8 @@ private void Update() var env = _physicsEnv[0]; var state = new PhysicsState(ref env, ref _octree, ref _colliders, ref _kinematicColliders, - ref _kinematicCollidersAtIdentity, ref _updatedKinematicTransforms, ref events, ref _insideOfs, ref _ballStates, - ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates, + ref _kinematicCollidersAtIdentity, ref _updatedKinematicTransforms, ref _kinematicColliderLookups, ref events, + ref _insideOfs, ref _ballStates, ref _bumperStates, ref _dropTargetStates, ref _flipperStates, ref _gateStates, ref _hitTargetStates, ref _kickerStates, ref _plungerStates, ref _spinnerStates, ref _surfaceStates, ref _triggerStates, ref _disabledCollisionItems, ref _swapBallCollisionHandling); @@ -439,7 +440,13 @@ private void OnDestroy() _disabledCollisionItems.Dispose(); _kinematicTransforms.Dispose(); _updatedKinematicTransforms.Dispose(); - _colliderLookup.Dispose(); + using (var enumerator = _kinematicColliderLookups.GetEnumerator()) { + while (enumerator.MoveNext()) { + enumerator.Current.Value.Dispose(); + } + } + _kinematicColliderLookups.Dispose(); + } #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs index 5f07670d8..04b30ead8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsKinematicBroadPhase.cs @@ -25,6 +25,20 @@ public static class PhysicsKinematicBroadPhase { private static readonly ProfilerMarker PerfMarkerBallOctree = new("CreateKinematicOctree"); + internal static void TransformColliders(ref PhysicsState state) + { + using var enumerator = state.UpdatedKinematicTransforms.GetEnumerator(); + while (enumerator.MoveNext()) { + ref var matrix = ref enumerator.Current.Value; + var itemId = enumerator.Current.Key; + + ref var colliderLookups = ref state.KinematicColliderLookups.GetValueByRef(itemId); + for (var i = 0; i < colliderLookups.Length; i++) { + state.Transform(colliderLookups[i], matrix); + } + } + } + internal static NativeOctree CreateOctree(ref NativeColliders kinematicColliders, in AABB playfieldBounds) { PerfMarkerBallOctree.Begin(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs index dbd6bfcc2..ce53f2ca2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsState.cs @@ -30,6 +30,8 @@ internal struct PhysicsState internal NativeColliders KinematicColliders; internal NativeColliders KinematicCollidersAtIdentity; internal NativeParallelHashMap UpdatedKinematicTransforms; + internal NativeParallelHashMap KinematicColliderLookups; + internal NativeQueue.ParallelWriter EventQueue; internal InsideOfs InsideOfs; internal NativeParallelHashMap Balls; @@ -48,7 +50,8 @@ internal struct PhysicsState public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref NativeColliders colliders, ref NativeColliders kinematicColliders, ref NativeColliders kinematicCollidersAtIdentity, - ref NativeParallelHashMap updatedKinematicTransforms, ref NativeQueue.ParallelWriter eventQueue, + ref NativeParallelHashMap updatedKinematicTransforms, + ref NativeParallelHashMap kinematicColliderLookups, ref NativeQueue.ParallelWriter eventQueue, ref InsideOfs insideOfs, ref NativeParallelHashMap balls, ref NativeParallelHashMap bumperStates, ref NativeParallelHashMap dropTargetStates, ref NativeParallelHashMap flipperStates, ref NativeParallelHashMap gateStates, @@ -63,6 +66,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native KinematicColliders = kinematicColliders; KinematicCollidersAtIdentity = kinematicCollidersAtIdentity; UpdatedKinematicTransforms = updatedKinematicTransforms; + KinematicColliderLookups = kinematicColliderLookups; EventQueue = eventQueue; InsideOfs = insideOfs; Balls = balls; @@ -114,6 +118,26 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native #endregion + #region Transform + + internal void Transform(int colliderId, float4x4 matrix) + { + switch (GetColliderType(ref KinematicColliders, colliderId)) + { + case ColliderType.Point: + KinematicColliders.Point(colliderId).Transform(KinematicCollidersAtIdentity.Point(colliderId), matrix); + break; + case ColliderType.Line3D: + KinematicColliders.Line3D(colliderId).Transform(KinematicCollidersAtIdentity.Line3D(colliderId), matrix); + break; + case ColliderType.Triangle: + KinematicColliders.Triangle(colliderId).Transform(KinematicCollidersAtIdentity.Triangle(colliderId), matrix); + break; + } + } + + #endregion + #region Hit Test internal float HitTest(ref NativeColliders colliders, int colliderId, ref BallState ball, ref CollisionEventData newCollEvent, ref NativeList contacts) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs index 5a0c7e850..105c10b91 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsUpdateJob.cs @@ -38,6 +38,7 @@ internal struct PhysicsUpdateJob : IJob public NativeColliders KinematicColliders; public NativeColliders KinematicCollidersAtIdentity; public NativeParallelHashMap UpdatedKinematicTransforms; + public NativeParallelHashMap KinematicColliderLookups; public InsideOfs InsideOfs; public NativeQueue.ParallelWriter Events; public AABB PlayfieldBounds; @@ -60,8 +61,8 @@ public void Execute() { var env = PhysicsEnv[0]; var state = new PhysicsState(ref env, ref Octree, ref Colliders, ref KinematicColliders, - ref KinematicCollidersAtIdentity, ref UpdatedKinematicTransforms, ref Events, ref InsideOfs, ref Balls, - ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates, + ref KinematicCollidersAtIdentity, ref UpdatedKinematicTransforms, ref KinematicColliderLookups, ref Events, + ref InsideOfs, ref Balls, ref BumperStates, ref DropTargetStates, ref FlipperStates, ref GateStates, ref HitTargetStates, ref KickerStates, ref PlungerStates, ref SpinnerStates, ref SurfaceStates, ref TriggerStates, ref DisabledCollisionItems, ref SwapBallCollisionHandling); var cycle = new PhysicsCycle(Allocator.Temp); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs index 7505d6974..0ed2cabb9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs @@ -281,5 +281,15 @@ public ICollider[] ToArray() } return array; } + + public NativeParallelHashMap CreateLookup(Allocator allocator) + { + var lookup = new NativeParallelHashMap(_references.Count(), allocator); + using var enumerator = _references.GetEnumerator(); + while (enumerator.MoveNext()) { + lookup.Add(enumerator.Current.Key, new NativeColliderIds(enumerator.Current.Value, allocator)); + } + return lookup; + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs index ebbf1ec4a..9f54cfc1e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs @@ -132,5 +132,9 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrite } public override string ToString() => $"Line3DCollider[{Header.ItemId}] ({_xy.x}/{_xy.y} | {_zLow} -> {_zHigh})"; + + public void Transform(Line3DCollider line3D, float4x4 matrix) + { + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs index 94f6b3956..871f1cb04 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs @@ -139,5 +139,10 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrit #endregion public override string ToString() => $"PointCollider[{Header.ItemId}] ({P.x}/{P.y}/{P.z})"; + + public void Transform(PointCollider point, float4x4 matrix) + { + + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs index 0959028ea..0eb5acc1b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs @@ -31,10 +31,10 @@ public int Id public ColliderHeader Header; - public readonly float3 Rgv0; - public readonly float3 Rgv1; - public readonly float3 Rgv2; - private readonly float3 _normal; + public float3 Rgv0; + public float3 Rgv1; + public float3 Rgv2; + private float3 _normal; public float3 Normal() => _normal; @@ -182,5 +182,10 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrite } #endregion + + public void Transform(TriangleCollider triangle, float4x4 matrix) + { + //Rgv0 = math.mul(matrix, triangle.Rgv0); + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs index 4f4358244..ca84fd051 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs @@ -1,7 +1,40 @@ -namespace VisualPinball.Unity +using System; +using System.Linq; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace VisualPinball.Unity { - public struct NativeColliderIds + public unsafe struct NativeColliderIds : IDisposable { - + public readonly int Length; + private void* _buffer; + + private readonly Allocator _allocator; + + public NativeColliderIds(NativeList colliderIds, Allocator allocator) + { + _allocator = allocator; + Length = colliderIds.Length; + long size = UnsafeUtility.SizeOf() * Length; + _buffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); + UnsafeUtility.MemCpy(_buffer, colliderIds.GetUnsafePtr(), size); + } + + public int this[int index] + { + get { + if (index < 0 || index >= Length) { + throw new IndexOutOfRangeException(); + } + return UnsafeUtility.ReadArrayElement(_buffer, index); + } + } + + public void Dispose() + { + UnsafeUtility.Free(_buffer, _allocator); + _buffer = null; + } } } From c2edb1a88c4f61ad9c2b85464f6f28fc5c293ca2 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 17:02:55 +0100 Subject: [PATCH 09/14] kinematic: Save colliders at identity matrix. --- .../VisualPinball.Unity/Game/PhysicsEngine.cs | 16 +-- .../Physics/Collider/ColliderReference.cs | 113 +++++++++++------- .../Physics/Collider/Line3DCollider.cs | 26 ++-- .../Physics/Collider/PointCollider.cs | 4 +- .../Physics/Collider/TriangleCollider.cs | 5 +- .../Physics/NativeColliders.cs | 6 +- 6 files changed, 107 insertions(+), 63 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index 67fc12896..9fdbeee7f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -194,10 +194,17 @@ private void Start() // allocate colliders _colliders = new NativeColliders(ref colliders, Allocator.Persistent); _kinematicColliders = new NativeColliders(ref kinematicColliders, Allocator.Persistent); - // todo make them actually at identity by reverse-applying their matrices - _kinematicCollidersAtIdentity = new NativeColliders(ref kinematicColliders, Allocator.Persistent); + + // get kinetic collider matrices + foreach (var coll in _kinematicColliderComponents) { + _kinematicTransforms[coll.ItemId] = coll.GetTransformationMatrix().ToUnityMatrix(); + } _kinematicColliderLookups = kinematicColliders.CreateLookup(Allocator.Persistent); + // create identity kinematic colliders + kinematicColliders.TransformToIdentity(_kinematicTransforms); + _kinematicCollidersAtIdentity = new NativeColliders(ref kinematicColliders, Allocator.Persistent); + // create octree var elapsedMs = sw.Elapsed.TotalMilliseconds; var playfieldBounds = GetComponentInChildren().Bounds; @@ -218,11 +225,6 @@ private void Start() foreach (var ball in balls) { Register(ball); } - - // get kinetic collider matrices - foreach (var coll in _kinematicColliderComponents) { - _kinematicTransforms[coll.ItemId] = coll.GetTransformationMatrix().ToUnityMatrix(); - } } private void Update() diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs index 0ed2cabb9..17ba64e34 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs @@ -16,6 +16,7 @@ using System; using Unity.Collections; +using Unity.Mathematics; using VisualPinball.Unity.Collections; namespace VisualPinball.Unity @@ -35,11 +36,10 @@ public struct ColliderReference : IDisposable internal NativeList TriangleColliders; internal NativeList PlaneColliders; - public NativeList Lookup; - - public readonly bool KinematicColliders; - private NativeParallelHashMap> _references; + public NativeList Lookups; // collider id -> collider type + index within collider type list + public readonly bool KinematicColliders; // if set, populate _itemIdToColliderIds + private NativeParallelHashMap> _itemIdToColliderIds; public ColliderReference(Allocator allocator, bool kinematicColliders = false) { @@ -55,10 +55,10 @@ public ColliderReference(Allocator allocator, bool kinematicColliders = false) SpinnerColliders = new NativeList(allocator); TriangleColliders = new NativeList(allocator); PlaneColliders = new NativeList(allocator); - Lookup = new NativeList(allocator); + Lookups = new NativeList(allocator); KinematicColliders = kinematicColliders; - _references = new NativeParallelHashMap>(0, allocator); + _itemIdToColliderIds = new NativeParallelHashMap>(0, allocator); } public void Dispose() @@ -75,25 +75,52 @@ public void Dispose() SpinnerColliders.Dispose(); TriangleColliders.Dispose(); PlaneColliders.Dispose(); - using (var enumerator = _references.GetEnumerator()) { + using (var enumerator = _itemIdToColliderIds.GetEnumerator()) { while (enumerator.MoveNext()) { enumerator.Current.Value.Dispose(); } } - _references.Dispose(); + _itemIdToColliderIds.Dispose(); } - public int Count => Lookup.Length; + public int Count => Lookups.Length; public ICollider this[int i] => LookupCollider(i); + public void TransformToIdentity(NativeParallelHashMap itemIdToTransformationMatrix) + { + using var enumerator = _itemIdToColliderIds.GetEnumerator(); + while (enumerator.MoveNext()) { + var itemId = enumerator.Current.Key; + ref var colliderIds = ref enumerator.Current.Value; + foreach (var colliderId in colliderIds) { + var matrix = itemIdToTransformationMatrix[itemId]; + var lookup = Lookups[colliderId]; + switch (lookup.Type) { + case ColliderType.Point: + ref var pointCollider = ref PointColliders.GetElementAsRef(lookup.Index); + pointCollider.Transform(PointColliders[lookup.Index], math.inverse(matrix)); + break; + case ColliderType.Line3D: + ref var line3DCollider = ref Line3DColliders.GetElementAsRef(lookup.Index); + line3DCollider.Transform(Line3DColliders[lookup.Index], math.inverse(matrix)); + break; + case ColliderType.Triangle: + ref var triangleCollider = ref TriangleColliders.GetElementAsRef(lookup.Index); + triangleCollider.Transform(TriangleColliders[lookup.Index], math.inverse(matrix)); + break; + } + } + } + } + private ICollider LookupCollider(int i) { - if (i < 0 || i >= Lookup.Length) { + if (i < 0 || i >= Lookups.Length) { throw new IndexOutOfRangeException($"Invalid index {i} when looking up collider."); } - ref var lookup = ref Lookup.GetElementAsRef(i); + ref var lookup = ref Lookups.GetElementAsRef(i); switch (lookup.Type) { case ColliderType.Circle: return CircleColliders.GetElementAsRef(lookup.Index); case ColliderType.Flipper: return FlipperColliders.GetElementAsRef(lookup.Index); @@ -119,116 +146,116 @@ private void TrackReference(int itemId, int colliderId) return; } - if (!_references.ContainsKey(itemId)) { - _references[itemId] = new NativeList(Allocator.Temp); + if (!_itemIdToColliderIds.ContainsKey(itemId)) { + _itemIdToColliderIds[itemId] = new NativeList(Allocator.Temp); } - _references[itemId].Add(colliderId); + _itemIdToColliderIds[itemId].Add(colliderId); } internal int Add(CircleCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Circle, CircleColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Circle, CircleColliders.Length)); CircleColliders.Add(collider); return collider.Id; } internal int Add(FlipperCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Flipper, FlipperColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Flipper, FlipperColliders.Length)); FlipperColliders.Add(collider); return collider.Id; } internal int Add(GateCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Gate, GateColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Gate, GateColliders.Length)); GateColliders.Add(collider); return collider.Id; } internal int Add(Line3DCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Line3D, Line3DColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Line3D, Line3DColliders.Length)); Line3DColliders.Add(collider); return collider.Id; } internal int Add(LineSlingshotCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.LineSlingShot, LineSlingshotColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.LineSlingShot, LineSlingshotColliders.Length)); LineSlingshotColliders.Add(collider); return collider.Id; } internal int Add(LineCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Line, LineColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Line, LineColliders.Length)); LineColliders.Add(collider); return collider.Id; } internal int Add(LineZCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.LineZ, LineZColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.LineZ, LineZColliders.Length)); LineZColliders.Add(collider); return collider.Id; } internal int Add(PlungerCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Plunger, PlungerColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Plunger, PlungerColliders.Length)); PlungerColliders.Add(collider); return collider.Id; } internal int Add(PointCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Point, PointColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Point, PointColliders.Length)); PointColliders.Add(collider); return collider.Id; } internal int Add(SpinnerCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Spinner, SpinnerColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Spinner, SpinnerColliders.Length)); SpinnerColliders.Add(collider); return collider.Id; } internal int Add(TriangleCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Triangle, TriangleColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Triangle, TriangleColliders.Length)); TriangleColliders.Add(collider); return collider.Id; } internal int Add(PlaneCollider collider) { - collider.Id = Lookup.Length; + collider.Id = Lookups.Length; TrackReference(collider.Header.ItemId, collider.Header.Id); - Lookup.Add(new ColliderLookup(ColliderType.Plane, PlaneColliders.Length)); + Lookups.Add(new ColliderLookup(ColliderType.Plane, PlaneColliders.Length)); PlaneColliders.Add(collider); return collider.Id; } @@ -237,9 +264,9 @@ internal int Add(PlaneCollider collider) public ICollider[] ToArray() { - var array = new ICollider[Lookup.Length]; - for (var i = 0; i < Lookup.Length; i++) { - var lookup = Lookup[i]; + var array = new ICollider[Lookups.Length]; + for (var i = 0; i < Lookups.Length; i++) { + var lookup = Lookups[i]; switch (lookup.Type) { case ColliderType.Circle: array[i] = CircleColliders[lookup.Index]; @@ -284,8 +311,8 @@ public ICollider[] ToArray() public NativeParallelHashMap CreateLookup(Allocator allocator) { - var lookup = new NativeParallelHashMap(_references.Count(), allocator); - using var enumerator = _references.GetEnumerator(); + var lookup = new NativeParallelHashMap(_itemIdToColliderIds.Count(), allocator); + using var enumerator = _itemIdToColliderIds.GetEnumerator(); while (enumerator.MoveNext()) { lookup.Add(enumerator.Current.Key, new NativeColliderIds(enumerator.Current.Value, allocator)); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs index 9f54cfc1e..77745a7f6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/Line3DCollider.cs @@ -37,20 +37,25 @@ public int Id // these are all used when casting this to LineZCollider, // so the order is important too. - // ReSharper disable once NotAccessedField.Local - private readonly float2 _xy; - // ReSharper disable once NotAccessedField.Local - private readonly float _zLow; - // ReSharper disable once NotAccessedField.Local - private readonly float _zHigh; - private readonly float3x3 _matrix; + private float2 _xy; + private float _zLow; + private float _zHigh; + private float3x3 _matrix; + + // these are just so we can recompute the matrix when the collider is transformed. + private float3 _v1; + private float3 _v2; public ColliderBounds Bounds { get; private set; } public Line3DCollider(float3 v1, float3 v2, ColliderInfo info) : this() { Header.Init(info, ColliderType.Line3D); + SetByVectors(v1, v2); + } + private void SetByVectors(float3 v1, float3 v2) + { var vLine = math.normalize(v2 - v1); // Axis of rotation to make 3D cylinder a cylinder along the z-axis @@ -89,6 +94,9 @@ public Line3DCollider(float3 v1, float3 v2, ColliderInfo info) : this() math.min(v1.z, v2.z), math.max(v1.z, v2.z) )); + + _v1 = v1; + _v2 = v2; } #region Narrowphase @@ -135,6 +143,10 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrite public void Transform(Line3DCollider line3D, float4x4 matrix) { + SetByVectors( + math.mul(matrix, new float4(line3D._v1, 1f)).xyz, + math.mul(matrix, new float4(line3D._v2, 1f)).xyz + ); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs index 871f1cb04..2110c4be7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/PointCollider.cs @@ -30,7 +30,7 @@ public int Id public ColliderHeader Header; - public readonly float3 P; + public float3 P; public ColliderBounds Bounds => new ColliderBounds(Header.ItemId, Header.Id, new Aabb( P.x, @@ -142,7 +142,7 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrit public void Transform(PointCollider point, float4x4 matrix) { - + P = math.mul(matrix, new float4(point.P, 1f)).xyz; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs index 0eb5acc1b..7a9d2ecbf 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/TriangleCollider.cs @@ -185,7 +185,10 @@ public void Collide(ref BallState ball, ref NativeQueue.ParallelWrite public void Transform(TriangleCollider triangle, float4x4 matrix) { - //Rgv0 = math.mul(matrix, triangle.Rgv0); + Rgv0 = math.mul(matrix, new float4(triangle.Rgv0, 1f)).xyz; + Rgv1 = math.mul(matrix, new float4(triangle.Rgv1, 1f)).xyz; + Rgv2 = math.mul(matrix, new float4(triangle.Rgv2, 1f)).xyz; + _normal = math.normalizesafe(math.cross(Rgv2 - Rgv0, Rgv1 - Rgv0)); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs index 28a3b8490..c221c73ae 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliders.cs @@ -82,12 +82,12 @@ public NativeColliders(ref ColliderReference colRef, Allocator allocator) #endif PerfMarker.Begin(); - m_Length = colRef.Lookup.Length; + m_Length = colRef.Lookups.Length; m_KinematicColliders = colRef.KinematicColliders; - long size = UnsafeUtility.SizeOf() * colRef.Lookup.Length; + long size = UnsafeUtility.SizeOf() * colRef.Lookups.Length; m_LookupBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); - UnsafeUtility.MemCpy(m_LookupBuffer, colRef.Lookup.GetUnsafePtr(), size); + UnsafeUtility.MemCpy(m_LookupBuffer, colRef.Lookups.GetUnsafePtr(), size); size = UnsafeUtility.SizeOf() * colRef.FlipperColliders.Length; m_FlipperColliderBuffer = UnsafeUtility.Malloc(size, UnsafeUtility.AlignOf(), allocator); From b6cbb1cd7d3295e2d69d65e997f0777bc36b5a50 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 19:23:56 +0100 Subject: [PATCH 10/14] editor: Fix collider gizmo for colliders. --- .../VisualPinball.Unity/VPT/ColliderComponent.cs | 4 +++- .../VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs index 290aca931..4a6d868c8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs @@ -142,7 +142,9 @@ private void OnDrawGizmos() api.CreateColliders(ref colliders, ref kinematicColliders, 0.1f); if (showColliders) { - _colliderMesh = GenerateColliderMesh(ref colliders); + _colliderMesh = this is IKinematicColliderComponent { IsKinematic: true } + ? GenerateColliderMesh(ref kinematicColliders) + : GenerateColliderMesh(ref colliders); _collidersDirty = false; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs index ece1cca06..ecea5bf90 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs @@ -46,8 +46,11 @@ internal PrimitiveApi(GameObject go, Player player, PhysicsEngine physicsEngine) protected override void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin) { var colliderGenerator = new PrimitiveColliderGenerator(this, MainComponent, MainComponent); - var colls = ColliderComponent._isKinematic ? kinematicColliders : colliders; - colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref colls); + if (ColliderComponent._isKinematic) { + colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref kinematicColliders); + } else { + colliderGenerator.GenerateColliders(ColliderComponent.CollisionReductionFactor, ref colliders); + } } #endregion From c16045a54f8a11bf82f47ca0419930a047bbe358 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 4 Nov 2023 23:34:33 +0100 Subject: [PATCH 11/14] kinematic: Generate transformation matrix without garbage. --- .../VisualPinball.Unity/Game/PhysicsEngine.cs | 4 ++-- .../VisualPinball.Unity/VPT/CollidableApi.cs | 3 +-- .../VPT/IKinematicColliderComponent.cs | 4 ++-- .../VPT/Primitive/PrimitiveColliderComponent.cs | 9 ++++++--- .../VPT/Primitive/PrimitiveComponent.cs | 16 ++++++++++++++++ 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs index 9fdbeee7f..696c0361e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsEngine.cs @@ -197,7 +197,7 @@ private void Start() // get kinetic collider matrices foreach (var coll in _kinematicColliderComponents) { - _kinematicTransforms[coll.ItemId] = coll.GetTransformationMatrix().ToUnityMatrix(); + _kinematicTransforms[coll.ItemId] = coll.TransformationMatrix; } _kinematicColliderLookups = kinematicColliders.CreateLookup(Allocator.Persistent); @@ -236,7 +236,7 @@ private void Update() continue; } var lastTransformationMatrix = _kinematicTransforms[coll.ItemId]; - var currTransformationMatrix = (float4x4)coll.GetTransformationMatrix().ToUnityMatrix(); + var currTransformationMatrix = coll.TransformationMatrix; if (!lastTransformationMatrix.Equals(currTransformationMatrix)) { _updatedKinematicTransforms.Add(coll.ItemId, currTransformationMatrix); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs index 9b066f69a..fcbfa695c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs @@ -43,8 +43,7 @@ protected CollidableApi(GameObject go, Player player, PhysicsEngine physicsEngin protected abstract void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin); - void IApiColliderGenerator.CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, - float margin) + void IApiColliderGenerator.CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin) { if (!ColliderComponent) { return; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs index 37b59acef..203149523 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IKinematicColliderComponent.cs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using VisualPinball.Engine.Math; +using Unity.Mathematics; namespace VisualPinball.Unity { @@ -22,6 +22,6 @@ public interface IKinematicColliderComponent { public bool IsKinematic { get; } public int ItemId { get; } - public Matrix3D GetTransformationMatrix(); + public float4x4 TransformationMatrix { get; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs index e261f7f54..b30d404d4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs @@ -16,9 +16,8 @@ // ReSharper disable InconsistentNaming +using Unity.Mathematics; using UnityEngine; -using UnityEngine.Serialization; -using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT.Primitive; namespace VisualPinball.Unity @@ -61,9 +60,13 @@ public class PrimitiveColliderComponent : ColliderComponent _isKinematic; public int ItemId => MainComponent.gameObject.GetInstanceID(); - public Matrix3D GetTransformationMatrix() => MainComponent.GetTransformationMatrix(); + public float4x4 TransformationMatrix => MainComponent.TransformationMatrix; #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs index 90a555e0f..85ad3bd4a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs @@ -95,6 +95,22 @@ public float2 RotatedPosition { } } + public float4x4 TransformationMatrix { + get { + var scaleMatrix = float4x4.Scale(Size); + var transMatrix = float4x4.Translate(new float3(Position.x, Position.y, Position.z + PlayfieldHeight)); + var rotTransMatrix = math.mul( + float4x4.EulerZYX(math.radians(Rotation)), + float4x4.Translate(Translation) + ); + rotTransMatrix = math.mul( + float4x4.EulerZYX(math.radians(ObjectRotation)), + rotTransMatrix + ); + return math.mul(transMatrix, math.mul(rotTransMatrix, scaleMatrix)); + } + } + #endregion #region Conversion From 95e5b263d5b5740694ced0631ec05bfed80c68d0 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 5 Nov 2023 00:59:59 +0100 Subject: [PATCH 12/14] editor: For kinematic colliders, show the original, transformed colliders if game is running. --- .../Physics/NativeColliderIds.cs | 1 - .../VPT/ColliderComponent.cs | 120 +++++++++++++++--- 2 files changed, 104 insertions(+), 17 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs index ca84fd051..fbc8c9570 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/NativeColliderIds.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs index 4a6d868c8..7b2f3f0fb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ColliderComponent.cs @@ -26,6 +26,7 @@ using UnityEditor; using UnityEngine; using UnityEngine.Profiling; +using UnityEngine.UIElements; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Flipper; using Mesh = UnityEngine.Mesh; @@ -70,6 +71,8 @@ public abstract class ColliderComponent : SubComponent this is IKinematicColliderComponent { IsKinematic: true }; + private void OnDrawGizmos() { Profiler.BeginSample("ItemColliderComponent.OnDrawGizmosSelected"); @@ -136,25 +142,41 @@ private void OnDrawGizmos() var generateColliders = ShowAabbs || showColliders && !HasCachedColliders; if (generateColliders) { - var api = InstantiateColliderApi(player, null); - var colliders = new ColliderReference(Allocator.TempJob); - var kinematicColliders = new ColliderReference(Allocator.TempJob, true); - api.CreateColliders(ref colliders, ref kinematicColliders, 0.1f); - if (showColliders) { - _colliderMesh = this is IKinematicColliderComponent { IsKinematic: true } - ? GenerateColliderMesh(ref kinematicColliders) - : GenerateColliderMesh(ref colliders); - _collidersDirty = false; - } + if (Application.isPlaying && IsKinematic) { + + if (!_physicsEngine) { + _physicsEngine = GetComponentInParent(); + } + + var colliders = _physicsEngine.GetKinematicColliders(MainComponent.gameObject.GetInstanceID()); + if (showColliders) { + _colliderMesh = GenerateColliderMesh(colliders); + _collidersDirty = false; + } - if (ShowAabbs) { - for (var i = 0; i < colliders.Count; i++) { - var col = colliders[i]; - DrawAabb(col.Bounds.Aabb, i == SelectedCollider); + } else { + var api = InstantiateColliderApi(player, null); + var colliders = new ColliderReference(Allocator.TempJob); + var kinematicColliders = new ColliderReference(Allocator.TempJob, true); + api.CreateColliders(ref colliders, ref kinematicColliders, 0.1f); + + if (showColliders) { + _colliderMesh = IsKinematic + ? GenerateColliderMesh(ref kinematicColliders) + : GenerateColliderMesh(ref colliders); + _collidersDirty = false; } + + if (ShowAabbs) { + for (var i = 0; i < colliders.Count; i++) { + var col = colliders[i]; + DrawAabb(col.Bounds.Aabb, i == SelectedCollider); + } + } + colliders.Dispose(); + } - colliders.Dispose(); } if (ShowColliderOctree) { @@ -178,7 +200,9 @@ private void OnDrawGizmos() if (showColliders) { - var color = Color.green; + var color = Application.isPlaying && IsKinematic + ? Color.magenta + : IsKinematic ? new Color(0, 1, 1) : Color.green; Handles.color = color; color.a = 0.3f; Gizmos.color = color; @@ -248,6 +272,70 @@ private Mesh GenerateColliderMesh(ref ColliderReference colliders) }; } + private Mesh GenerateColliderMesh(IEnumerable colliders) + { + var color = Color.magenta; + Handles.color = color; + color.a = 0.3f; + Gizmos.color = color; + var vertices = new List(); + var normals = new List(); + var indices = new List(); + _nonMeshColliders.Clear(); + + foreach (var coll in colliders) { + + if (coll is CircleCollider circleCollider) { + AddCollider(circleCollider, vertices, normals, indices); + } + + if (coll is FlipperCollider) { + AddFlipperCollider(vertices, normals, indices); + } + + if (coll is GateCollider gateCollider) { + AddCollider(gateCollider.LineSeg0, vertices, normals, indices); + AddCollider(gateCollider.LineSeg1, vertices, normals, indices); + } + + if (coll is LineCollider lineCollider) { + AddCollider(lineCollider, vertices, normals, indices); + } + + if (coll is LineSlingshotCollider lineSlingshotCollider) { + AddCollider(lineSlingshotCollider, vertices, normals, indices); + } + + if (coll is LineZCollider lineZCollider) { + _nonMeshColliders.Add(lineZCollider); + } + + if (coll is PlungerCollider plungerCollider) { + AddCollider(plungerCollider.LineSegBase, vertices, normals, indices); + AddCollider(plungerCollider.JointBase0, vertices, normals, indices); + AddCollider(plungerCollider.JointBase1, vertices, normals, indices); + } + + if (coll is SpinnerCollider spinnerCollider) { + AddCollider(spinnerCollider.LineSeg0, vertices, normals, indices); + AddCollider(spinnerCollider.LineSeg1, vertices, normals, indices); + } + + if (coll is TriangleCollider triangleCollider) { + AddCollider(triangleCollider, vertices, normals, indices); + } + } + + // todo Line3DCollider + + return new Mesh { + name = $"{name} (debug collider)", + vertices = vertices.ToArray(), + triangles = indices.ToArray(), + normals = normals.ToArray() + }; + } + private void DrawNonMeshColliders() { foreach (var col in _nonMeshColliders) { From d8b1699e10d51c1bad3530c1981a9734d6bbcf6e Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 5 Nov 2023 01:22:24 +0100 Subject: [PATCH 13/14] kinematic: Add support for bumpers. --- .../VPT/Bumper/BumperColliderInspector.cs | 3 +++ .../Extensions/MathExtensions.cs | 9 +++++++++ .../VisualPinball.Unity/Game/PhysicsEngine.cs | 17 +++++++++++++++-- .../VisualPinball.Unity/Game/PhysicsState.cs | 7 +++++-- .../Game/PhysicsStaticCollision.cs | 2 +- .../Physics/Collider/CircleCollider.cs | 11 +++++++++-- .../Physics/Collider/ColliderReference.cs | 5 +++++ .../VisualPinball.Unity/VPT/Bumper/BumperApi.cs | 10 +++++++--- .../VPT/Bumper/BumperCollider.cs | 3 --- .../VPT/Bumper/BumperColliderComponent.cs | 14 +++++++++++++- .../VPT/Bumper/BumperComponent.cs | 12 +++++++++++- 11 files changed, 78 insertions(+), 15 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperColliderInspector.cs index bcc483637..6168e070e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperColliderInspector.cs @@ -28,6 +28,7 @@ public class BumperColliderInspector : ColliderInspector octree, ref Native internal ref KickerState GetKickerState(int colliderId) => ref KickerStates.GetValueByRef(Colliders.GetItemId(colliderId)); - internal bool HasDropTargetState(int colliderId) => DropTargetStates.ContainsKey(Colliders.GetItemId(colliderId)); internal bool HasHitTargetState(int colliderId) => HitTargetStates.ContainsKey(Colliders.GetItemId(colliderId)); @@ -110,7 +109,7 @@ public PhysicsState(ref PhysicsEnv env, ref NativeOctree octree, ref Native internal ref HitTargetState GetHitTargetState(int colliderId) => ref HitTargetStates.GetValueByRef(Colliders.GetItemId(colliderId)); - internal ref BumperState GetBumperState(int colliderId) => ref BumperStates.GetValueByRef(Colliders.GetItemId(colliderId)); + internal ref BumperState GetBumperState(int colliderId, ref NativeColliders col) => ref BumperStates.GetValueByRef(col.GetItemId(colliderId)); internal ref GateState GetGateState(int colliderId) => ref GateStates.GetValueByRef(Colliders.GetItemId(colliderId)); @@ -124,6 +123,10 @@ internal void Transform(int colliderId, float4x4 matrix) { switch (GetColliderType(ref KinematicColliders, colliderId)) { + case ColliderType.Bumper: + case ColliderType.Circle: + KinematicColliders.Circle(colliderId).Transform(KinematicCollidersAtIdentity.Circle(colliderId), matrix); + break; case ColliderType.Point: KinematicColliders.Point(colliderId).Transform(KinematicCollidersAtIdentity.Point(colliderId), matrix); break; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs index 1ecc41887..082f6ccb0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs @@ -82,7 +82,7 @@ private static void Collide(ref NativeColliders colliders, ref BallState ball, r break; case ColliderType.Bumper: - ref var bumperState = ref state.GetBumperState(colliderId); + ref var bumperState = ref state.GetBumperState(colliderId, ref colliders); BumperCollider.Collide(ref ball, ref state.EventQueue, ref ball.CollisionEvent, ref bumperState.RingAnimation, ref bumperState.SkirtAnimation, in collHeader, in bumperState.Static, ref state.Env.Random); break; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/CircleCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/CircleCollider.cs index bd18a8a48..85e8743c9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/CircleCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/CircleCollider.cs @@ -30,8 +30,8 @@ public int Id public ColliderHeader Header; - public readonly float2 Center; - public readonly float Radius; + public float2 Center; + public float Radius; private readonly float _zHigh; private readonly float _zLow; @@ -221,5 +221,12 @@ public void Collide(ref BallState ball, in CollisionEventData collEvent, ref Ran { BallCollider.Collide3DWall(ref ball, in Header.Material, in collEvent, in collEvent.HitNormal, ref random); } + + public void Transform(CircleCollider circle, float4x4 matrix) + { + var size = matrix.GetScale(); + Center = math.mul(matrix, new float4(circle.Center, 0f, 1f)).xy; + Radius = size.x / 2 * BumperComponent.DataMeshScale; + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs index 17ba64e34..5ca5b4aa2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collider/ColliderReference.cs @@ -97,6 +97,11 @@ public void TransformToIdentity(NativeParallelHashMap itemIdToTra var matrix = itemIdToTransformationMatrix[itemId]; var lookup = Lookups[colliderId]; switch (lookup.Type) { + case ColliderType.Bumper: + case ColliderType.Circle: + ref var circleCollider = ref CircleColliders.GetElementAsRef(lookup.Index); + circleCollider.Transform(CircleColliders[lookup.Index], math.inverse(matrix)); + break; case ColliderType.Point: ref var pointCollider = ref PointColliders.GetElementAsRef(lookup.Index); pointCollider.Transform(PointColliders[lookup.Index], math.inverse(matrix)); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs index f2419b469..9b2bca9c6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs @@ -15,7 +15,6 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using UnityEngine; using VisualPinball.Engine.VPT.Bumper; @@ -76,8 +75,13 @@ protected override void CreateColliders(ref ColliderReference colliders, ref ColliderReference kinematicColliders, float margin) { var height = MainComponent.PositionZ; - colliders.Add(new CircleCollider(MainComponent.Position, MainComponent.Radius, height, - height + MainComponent.HeightScale, GetColliderInfo(), ColliderType.Bumper)); + if (ColliderComponent.IsKinematic) { + kinematicColliders.Add(new CircleCollider(MainComponent.Position, MainComponent.Radius, height, + height + MainComponent.HeightScale, GetColliderInfo(), ColliderType.Bumper)); + } else { + colliders.Add(new CircleCollider(MainComponent.Position, MainComponent.Radius, height, + height + MainComponent.HeightScale, GetColliderInfo(), ColliderType.Bumper)); + } } #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs index 25847bf6e..3f81e2774 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs @@ -26,9 +26,6 @@ public static void Collide(ref BallState ball, ref NativeQueue.Parall ref CollisionEventData collEvent, ref BumperRingAnimationState ringState, ref BumperSkirtAnimationState skirtState, in ColliderHeader collHeader, in BumperStaticState state, ref Random random) { - // todo - // if (!m_enabled) return; - var dot = math.dot(collEvent.HitNormal, ball.Velocity); // needs to be computed before Collide3DWall()! var material = collHeader.Material; BallCollider.Collide3DWall(ref ball, in material, in collEvent, in collEvent.HitNormal, ref random); // reflect ball from wall diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperColliderComponent.cs index a3f19df37..34b60b586 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperColliderComponent.cs @@ -16,13 +16,14 @@ // ReSharper disable InconsistentNaming +using Unity.Mathematics; using UnityEngine; using VisualPinball.Engine.VPT.Bumper; namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Collision/Bumper Collider")] - public class BumperColliderComponent : ColliderComponent + public class BumperColliderComponent : ColliderComponent, IKinematicColliderComponent { #region Data @@ -41,6 +42,17 @@ public class BumperColliderComponent : ColliderComponent _isKinematic; + public int ItemId => MainComponent.gameObject.GetInstanceID(); + public float4x4 TransformationMatrix => MainComponent.TransformationMatrix; + #endregion protected override IApiColliderGenerator InstantiateColliderApi(Player player, PhysicsEngine physicsEngine) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs index c71ece42a..5548381a1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs @@ -77,7 +77,8 @@ public class BumperComponent : MainRenderableComponent, private const string BaseMeshName = "bumper.base"; private const string CapMeshName = "bumper.cap"; private const string RingMeshName = "bumper.ring"; - private const float DataMeshScale = 100f; + + public const float DataMeshScale = 100f; public const string SocketSwitchItem = "socket_switch"; @@ -146,6 +147,15 @@ public override void UpdateTransforms() t.localEulerAngles = new Vector3(0, Orientation, 0); } + public float4x4 TransformationMatrix { + get { + var scaleMatrix = float4x4.Scale(new float3(Radius * 2f, Radius * 2f, HeightScale) / DataMeshScale); + var transMatrix = float4x4.Translate(new float3(Position.x, Position.y, PositionZ)); + var rotMatrix = float4x4.RotateZ(math.radians(Orientation)); + return math.mul(transMatrix, math.mul(rotMatrix, scaleMatrix)); + } + } + #endregion #region Conversion From d5f60403d25ad71696d291fb925e181451cc9336 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 5 Nov 2023 12:49:42 +0100 Subject: [PATCH 14/14] chore(cleanup): Remove unneeded ItemId from states. --- .../VisualPinball.Unity/Game/PhysicsCycle.cs | 8 ++++---- .../VisualPinball.Unity/VPT/Bumper/BumperComponent.cs | 1 - .../VisualPinball.Unity/VPT/Bumper/BumperState.cs | 4 +--- .../VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs | 1 - .../VisualPinball.Unity/VPT/Flipper/FlipperState.cs | 4 +--- .../VisualPinball.Unity/VPT/Gate/GateComponent.cs | 1 - .../VisualPinball.Unity/VPT/Gate/GateState.cs | 4 +--- .../VPT/HitTarget/DropTargetComponent.cs | 1 - .../VisualPinball.Unity/VPT/HitTarget/DropTargetState.cs | 4 +--- .../VPT/HitTarget/HitTargetComponent.cs | 1 - .../VisualPinball.Unity/VPT/HitTarget/HitTargetState.cs | 4 +--- .../VisualPinball.Unity/VPT/Kicker/KickerComponent.cs | 1 - .../VisualPinball.Unity/VPT/Kicker/KickerState.cs | 4 +--- .../VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs | 1 - .../VisualPinball.Unity/VPT/Plunger/PlungerState.cs | 4 +--- .../VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs | 1 - .../VisualPinball.Unity/VPT/Spinner/SpinnerState.cs | 4 +--- .../VisualPinball.Unity/VPT/Surface/SurfaceComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Surface/SurfaceState.cs | 4 +--- .../VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs | 2 -- .../VisualPinball.Unity/VPT/Trigger/TriggerState.cs | 7 ++----- 21 files changed, 16 insertions(+), 47 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs index af2e1f61c..357e3de36 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsCycle.cs @@ -103,7 +103,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati using (var enumerator = state.FlipperStates.GetEnumerator()) { while (enumerator.MoveNext()) { ref var flipperState = ref enumerator.Current.Value; - FlipperDisplacementPhysics.UpdateDisplacement(flipperState.ItemId, ref flipperState.Movement, + FlipperDisplacementPhysics.UpdateDisplacement(enumerator.Current.Key, ref flipperState.Movement, ref flipperState.Tricks, in flipperState.Static, hitTime, ref state.EventQueue); } } @@ -111,7 +111,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati using (var enumerator = state.GateStates.GetEnumerator()) { while (enumerator.MoveNext()) { ref var gateState = ref enumerator.Current.Value; - GateDisplacementPhysics.UpdateDisplacement(gateState.ItemId, ref gateState.Movement, in gateState.Static, + GateDisplacementPhysics.UpdateDisplacement(enumerator.Current.Key, ref gateState.Movement, in gateState.Static, hitTime, ref state.EventQueue); } } @@ -119,7 +119,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati using (var enumerator = state.PlungerStates.GetEnumerator()) { while (enumerator.MoveNext()) { ref var plungerState = ref enumerator.Current.Value; - PlungerDisplacementPhysics.UpdateDisplacement(plungerState.ItemId, ref plungerState.Movement, ref plungerState.Collider, + PlungerDisplacementPhysics.UpdateDisplacement(enumerator.Current.Key, ref plungerState.Movement, ref plungerState.Collider, in plungerState.Static, hitTime, ref state.EventQueue); } } @@ -127,7 +127,7 @@ internal void Simulate(ref PhysicsState state, in AABB playfieldBounds, ref Nati using (var enumerator = state.SpinnerStates.GetEnumerator()) { while (enumerator.MoveNext()) { ref var spinnerState = ref enumerator.Current.Value; - SpinnerDisplacementPhysics.UpdateDisplacement(spinnerState.ItemId, ref spinnerState.Movement, in spinnerState.Static, + SpinnerDisplacementPhysics.UpdateDisplacement(enumerator.Current.Key, ref spinnerState.Movement, in spinnerState.Static, hitTime, ref state.EventQueue); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs index 5548381a1..ccc1de0d2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs @@ -358,7 +358,6 @@ internal BumperState CreateState() } : default; return new BumperState( - collComponent ? gameObject.GetInstanceID() : 0, skirtAnimComponent ? skirtAnimComponent.gameObject.GetInstanceID() : 0, ringAnimComponent ? ringAnimComponent.gameObject.GetInstanceID() : 0, staticData, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs index 1e2de8b9f..0013b549c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs @@ -18,17 +18,15 @@ namespace VisualPinball.Unity { internal struct BumperState { - internal readonly int ItemId; internal readonly int SkirtItemId; internal int RingItemId; internal BumperStaticState Static; internal BumperRingAnimationState RingAnimation; internal BumperSkirtAnimationState SkirtAnimation; - public BumperState(int itemId, int skirtItemId, int ringItemId, BumperStaticState @static, + public BumperState(int skirtItemId, int ringItemId, BumperStaticState @static, BumperRingAnimationState ringAnimation, BumperSkirtAnimationState skirtAnimation) { - ItemId = itemId; SkirtItemId = skirtItemId; RingItemId = ringItemId; Static = @static; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs index 83bfc2756..3ee02ad77 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs @@ -506,7 +506,6 @@ internal FlipperState CreateState() // vpx physics var d = GetMaterialData(colliderComponent); var state = new FlipperState( - gameObject.GetInstanceID(), d, GetMovementData(d), GetVelocityData(d), diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperState.cs index eab2654d0..adc9e6ae3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperState.cs @@ -18,7 +18,6 @@ namespace VisualPinball.Unity { internal struct FlipperState { - internal readonly int ItemId; internal FlipperStaticData Static; internal FlipperMovementState Movement; internal FlipperVelocityData Velocity; @@ -26,11 +25,10 @@ internal struct FlipperState internal FlipperTricksData Tricks; internal SolenoidState Solenoid; - public FlipperState(int itemId, FlipperStaticData @static, FlipperMovementState movement, + public FlipperState(FlipperStaticData @static, FlipperMovementState movement, FlipperVelocityData velocity, FlipperHitData hit, FlipperTricksData tricks, SolenoidState solenoid) { - ItemId = itemId; Static = @static; Movement = movement; Velocity = velocity; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs index 53d9e21b7..5cb9ec8f6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs @@ -312,7 +312,6 @@ internal GateState CreateState() } : default; return new GateState( - collComponent ? gameObject.GetInstanceID() : 0, wireComponent ? wireComponent.gameObject.GetInstanceID() : 0, staticData, movementData diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateState.cs index 4e017f528..7242111e7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateState.cs @@ -18,14 +18,12 @@ namespace VisualPinball.Unity { internal struct GateState { - internal readonly int ItemId; internal readonly int WireItemId; internal GateStaticState Static; internal GateMovementState Movement; - public GateState(int itemId, int wireItemId, GateStaticState @static, GateMovementState movement) + public GateState(int wireItemId, GateStaticState @static, GateMovementState movement) { - ItemId = itemId; WireItemId = wireItemId; Static = @static; Movement = movement; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetComponent.cs index 03ac170e3..39d88c32e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetComponent.cs @@ -168,7 +168,6 @@ internal DropTargetState CreateState() } : default; return new DropTargetState( - colliderComponent && animationComponent ? gameObject.GetInstanceID() : 0, animationComponent ? animationComponent.gameObject.GetInstanceID() : 0, staticData, animationData diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetState.cs index b5434468e..96cd8a424 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/DropTargetState.cs @@ -18,14 +18,12 @@ namespace VisualPinball.Unity { internal struct DropTargetState { - internal readonly int ItemId; internal readonly int AnimatedItemId; internal DropTargetStaticState Static; internal DropTargetAnimationState Animation; - public DropTargetState(int itemId, int animatedItemId, DropTargetStaticState @static, DropTargetAnimationState animation) + public DropTargetState(int animatedItemId, DropTargetStaticState @static, DropTargetAnimationState animation) { - ItemId = itemId; AnimatedItemId = animatedItemId; Static = @static; Animation = animation; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetComponent.cs index 2034b65a4..9f98de683 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetComponent.cs @@ -144,7 +144,6 @@ internal HitTargetState CreateState() } : default; return new HitTargetState( - hitTargetColliderComponent && hitTargetAnimationComponent ? gameObject.GetInstanceID() : 0, hitTargetAnimationComponent ? hitTargetAnimationComponent.gameObject.GetInstanceID() : 0, staticData, animationData diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetState.cs index 5938e876f..72f5f1897 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetState.cs @@ -18,14 +18,12 @@ namespace VisualPinball.Unity { internal struct HitTargetState { - internal readonly int ItemId; internal readonly int AnimatedItemId; internal HitTargetStaticData Static; internal HitTargetAnimationData Animation; - public HitTargetState(int itemId, int animatedItemId, HitTargetStaticData @static, HitTargetAnimationData animation) + public HitTargetState(int animatedItemId, HitTargetStaticData @static, HitTargetAnimationData animation) { - ItemId = itemId; AnimatedItemId = animatedItemId; Static = @static; Animation = animation; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs index 8d2cd03b7..872819dde 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs @@ -280,7 +280,6 @@ internal KickerState CreateState() : new ColliderMeshData(KickerHitMesh.Vertices, Radius, new float3(Center.x, Center.y, height), Allocator.Persistent); return new KickerState( - colliderComponent ? colliderComponent.gameObject.GetInstanceID() : 0, staticData, new KickerCollisionState(), meshData diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerState.cs index c18df1806..d4ffabf60 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerState.cs @@ -20,14 +20,12 @@ namespace VisualPinball.Unity { internal struct KickerState : IDisposable { - internal readonly int ItemId; internal KickerStaticState Static; internal KickerCollisionState Collision; internal ColliderMeshData CollisionMesh; - public KickerState(int itemId, KickerStaticState @static, KickerCollisionState collision, ColliderMeshData collisionMesh) + public KickerState(KickerStaticState @static, KickerCollisionState collision, ColliderMeshData collisionMesh) { - ItemId = itemId; Static = @static; Collision = collision; CollisionMesh = collisionMesh; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs index b7d9867b3..6bee71fe9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs @@ -303,7 +303,6 @@ internal PlungerState CreateState() }; return new PlungerState( - gameObject.GetInstanceID(), new PlungerStaticState { MomentumXfer = collComponent.MomentumXfer, ScatterVelocity = collComponent.ScatterVelocity, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerState.cs index 66acf2347..2d7a4b008 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerState.cs @@ -18,16 +18,14 @@ namespace VisualPinball.Unity { internal struct PlungerState { - internal readonly int ItemId; internal PlungerStaticState Static; internal PlungerColliderState Collider; internal PlungerMovementState Movement; internal PlungerVelocityState Velocity; internal PlungerAnimationState Animation; - public PlungerState(int itemId, PlungerStaticState @static, PlungerColliderState collider, PlungerMovementState movement, PlungerVelocityState velocity, PlungerAnimationState animation) + public PlungerState(PlungerStaticState @static, PlungerColliderState collider, PlungerMovementState movement, PlungerVelocityState velocity, PlungerAnimationState animation) { - ItemId = itemId; Static = @static; Collider = collider; Movement = movement; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs index d7fe56f65..f3e3718df 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs @@ -273,7 +273,6 @@ internal SpinnerState CreateState() } : default; return new SpinnerState( - collComponent ? gameObject.GetInstanceID() : 0, animComponent ? animComponent.gameObject.GetInstanceID() : 0, staticData, movementData diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerState.cs index 4fed8ca9d..4ce440e9e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerState.cs @@ -18,14 +18,12 @@ namespace VisualPinball.Unity { internal struct SpinnerState { - internal readonly int ItemId; internal readonly int AnimationItemId; internal SpinnerStaticState Static; internal SpinnerMovementState Movement; - public SpinnerState(int itemId, int animationItemId, SpinnerStaticState @static, SpinnerMovementState movement) + public SpinnerState(int animationItemId, SpinnerStaticState @static, SpinnerMovementState movement) { - ItemId = itemId; AnimationItemId = animationItemId; Static = @static; Movement = movement; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceComponent.cs index ee7dde8f3..f1f7d031a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceComponent.cs @@ -219,7 +219,7 @@ internal SurfaceState CreateState() return default; } - return new SurfaceState(gameObject.GetInstanceID(), new LineSlingshotState { + return new SurfaceState(new LineSlingshotState { IsDisabled = false, Threshold = collComponent.SlingshotThreshold, }); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceState.cs index 4213e4550..7d7c497b9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceState.cs @@ -18,12 +18,10 @@ namespace VisualPinball.Unity { internal struct SurfaceState { - internal readonly int ItemId; internal LineSlingshotState Slingshot; - public SurfaceState(int itemId, LineSlingshotState slingshot) + public SurfaceState(LineSlingshotState slingshot) { - ItemId = itemId; Slingshot = slingshot; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs index af1f27461..2205b7d63 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs @@ -261,7 +261,6 @@ internal TriggerState CreateState() if (collComponent.ForFlipper == null) { return new TriggerState( - gameObject.GetInstanceID(), animComponent ? animComponent.gameObject.GetInstanceID() : 0, new TriggerStaticState { AnimSpeed = animComponent ? animComponent.AnimSpeed : 0, @@ -275,7 +274,6 @@ internal TriggerState CreateState() } return new TriggerState( - gameObject.GetInstanceID(), new TriggerStaticState { AnimSpeed = 0, Radius = collComponent.HitCircleRadius, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerState.cs index ef9acff93..afeddbf20 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerState.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerState.cs @@ -20,7 +20,6 @@ namespace VisualPinball.Unity { internal struct TriggerState : IDisposable { - internal readonly int ItemId; internal readonly int AnimatedItemId; internal TriggerStaticState Static; internal TriggerMovementState Movement; @@ -30,9 +29,8 @@ internal struct TriggerState : IDisposable /// /// Default trigger usage. /// - public TriggerState(int itemId, int animatedItemId, TriggerStaticState @static, TriggerMovementState movement, TriggerAnimationState animation) + public TriggerState(int animatedItemId, TriggerStaticState @static, TriggerMovementState movement, TriggerAnimationState animation) { - ItemId = itemId; AnimatedItemId = animatedItemId; Static = @static; Movement = movement; @@ -43,9 +41,8 @@ public TriggerState(int itemId, int animatedItemId, TriggerStaticState @static, /// /// Flipper correction usage. /// - public TriggerState(int itemId, TriggerStaticState @static, FlipperCorrectionState flipperCorrection) + public TriggerState(TriggerStaticState @static, FlipperCorrectionState flipperCorrection) { - ItemId = itemId; AnimatedItemId = 0; Static = @static; Movement = default;