From d5ea686f2c71e8077e2964013f3df7a90bcc8c56 Mon Sep 17 00:00:00 2001 From: Nilton Constantino Date: Fri, 12 Jun 2026 17:16:33 +0100 Subject: [PATCH] moving platform --- .../# Prototype/Scripts/TestGroundMorion.cs | 158 +++++++ .../Scripts/TestGroundMorion.cs.meta | 3 + .../Windows/world-overlay.window.enter.asset | 2 +- Assets/Scenes/5. Gameplay.unity | 390 +++++++++++++++++- .../Core/Entities/EntityMotorTopDown.cs | 188 +++++++-- .../Core/Grounding/GroundProfileMotion.cs | 7 +- .../Intrepid/Core/Grounding/GroundProfiles.cs | 15 +- .../Entities/Player/Sentinel/SentinelBrain.cs | 1 + .../Player/Sentinel/SentinelEntity.cs | 2 + 9 files changed, 711 insertions(+), 55 deletions(-) create mode 100644 Assets/# Prototype/Scripts/TestGroundMorion.cs create mode 100644 Assets/# Prototype/Scripts/TestGroundMorion.cs.meta diff --git a/Assets/# Prototype/Scripts/TestGroundMorion.cs b/Assets/# Prototype/Scripts/TestGroundMorion.cs new file mode 100644 index 0000000..67bff33 --- /dev/null +++ b/Assets/# Prototype/Scripts/TestGroundMorion.cs @@ -0,0 +1,158 @@ +using Intrepid.Core.Grounding; +using Intrepid.Utilities; +using Sirenix.OdinInspector; +using UnityEngine; + +namespace __Prototype.Scripts +{ + public class TestGroundMorion : GroundProfileMotion + { + [GroupConfigurations, SerializeField] private Vector3 localDirection = Vector3.right; + [GroupConfigurations, SerializeField] private float speed = 2f; + [GroupConfigurations, SerializeField] private float maxDistance = 4f; + [GroupConfigurations, SerializeField] private bool pingPong = true; + [GroupConfigurations, SerializeField] private bool moveOnStart; + + public override Vector3 Velocity { get; protected set; } + public override Vector3 DeltaPosition { get; protected set; } + public override bool IsMoving { get; protected set; } + public override bool IsStatic { get; protected set; } = false; + + private Vector3 _startPosition; + private Vector3 _lastPosition; + private int _directionSign = 1; + private bool _initialized; + + private void Awake() + { + Snap(); + + if (moveOnStart) + { + Move(); + } + } + + private void FixedUpdate() + { + if (!IsMoving) + { + ClearFrameMotion(); + return; + } + + var current = transform.position; + + var worldDirection = transform.TransformDirection(localDirection.normalized); + var next = current + worldDirection * (_directionSign * speed * Time.fixedDeltaTime); + + if (maxDistance > 0f) + { + var distanceFromStart = Vector3.Dot( + next - _startPosition, + worldDirection + ); + + if (Mathf.Abs(distanceFromStart) >= maxDistance) + { + if (pingPong) + { + _directionSign *= -1; + + var clampedDistance = Mathf.Clamp( + distanceFromStart, + -maxDistance, + maxDistance + ); + + next = _startPosition + worldDirection * clampedDistance; + } + else + { + next = _startPosition + worldDirection * Mathf.Sign(distanceFromStart) * maxDistance; + Stop(); + } + } + } + + transform.position = next; + + DeltaPosition = transform.position - _lastPosition; + Velocity = DeltaPosition / Time.fixedDeltaTime; + + _lastPosition = transform.position; + } + + [GroupDebug, Button(ButtonSizes.Medium)] + private void Move() + { + if (!_initialized) + { + Snap(); + } + + IsMoving = true; + } + + [GroupDebug, Button(ButtonSizes.Medium)] + private void Stop() + { + IsMoving = false; + ClearFrameMotion(); + } + + [GroupDebug, Button(ButtonSizes.Medium)] + private void Reverse() + { + _directionSign *= -1; + } + + [GroupDebug, Button(ButtonSizes.Medium)] + private void Snap() + { + _startPosition = transform.position; + _lastPosition = transform.position; + _directionSign = 1; + ClearFrameMotion(); + _initialized = true; + } + + [GroupDebug, Button(ButtonSizes.Medium)] + private void ResetToStart() + { + transform.position = _startPosition; + _lastPosition = transform.position; + _directionSign = 1; + ClearFrameMotion(); + } + + private void ClearFrameMotion() + { + DeltaPosition = Vector3.zero; + Velocity = Vector3.zero; + } + +#if UNITY_EDITOR + private void OnDrawGizmosSelected() + { + var origin = _initialized ? _startPosition : transform.position; + var worldDirection = transform.TransformDirection(localDirection.normalized); + + Gizmos.color = Color.green; + Gizmos.DrawLine( + origin - worldDirection * maxDistance, + origin + worldDirection * maxDistance + ); + + Gizmos.DrawSphere(origin - worldDirection * maxDistance, 0.08f); + Gizmos.DrawSphere(origin + worldDirection * maxDistance, 0.08f); + + Gizmos.color = Color.cyan; + Gizmos.DrawLine( + transform.position, + transform.position + Velocity + ); + } +#endif + } +} \ No newline at end of file diff --git a/Assets/# Prototype/Scripts/TestGroundMorion.cs.meta b/Assets/# Prototype/Scripts/TestGroundMorion.cs.meta new file mode 100644 index 0000000..cc42725 --- /dev/null +++ b/Assets/# Prototype/Scripts/TestGroundMorion.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52f9a25d1be7481baf4085a7b34ef8bb +timeCreated: 1781278946 \ No newline at end of file diff --git a/Assets/Resources/Tags/Windows/world-overlay.window.enter.asset b/Assets/Resources/Tags/Windows/world-overlay.window.enter.asset index 74734da..9e88f76 100644 --- a/Assets/Resources/Tags/Windows/world-overlay.window.enter.asset +++ b/Assets/Resources/Tags/Windows/world-overlay.window.enter.asset @@ -12,7 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6f2337b04d5e44dba892ac6b72ae7e44, type: 3} m_Name: world-overlay.window.enter m_EditorClassIdentifier: Intrepid General Utilities::Intrepid.Window.Data.WindowAnimationData - mode: 2 + mode: 3 direction: 0 soundEffect: {fileID: 0} animationSpeed: 2 diff --git a/Assets/Scenes/5. Gameplay.unity b/Assets/Scenes/5. Gameplay.unity index 4ca3cfa..5041c55 100644 --- a/Assets/Scenes/5. Gameplay.unity +++ b/Assets/Scenes/5. Gameplay.unity @@ -1270,6 +1270,11 @@ Transform: - {fileID: 1383643367} m_Father: {fileID: 1187971236} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &67093088 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 6524376507900539265, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + m_PrefabInstance: {fileID: 1977728341} + m_PrefabAsset: {fileID: 0} --- !u!1 &115233784 GameObject: m_ObjectHideFlags: 0 @@ -1751,7 +1756,7 @@ PrefabInstance: objectReference: {fileID: 23906060} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 331 + value: 337 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -2161,7 +2166,7 @@ PrefabInstance: objectReference: {fileID: 1485618350} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 276 + value: 282 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -2666,8 +2671,41 @@ Transform: - {fileID: 1629937738} - {fileID: 1501201613} - {fileID: 651339733} + - {fileID: 332227168} m_Father: {fileID: 1187971236} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &332227167 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 332227168} + m_Layer: 0 + m_Name: Platforms + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &332227168 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 332227167} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1977728342} + m_Father: {fileID: 320298439} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &347886466 GameObject: m_ObjectHideFlags: 0 @@ -3041,7 +3079,7 @@ PrefabInstance: objectReference: {fileID: 7028820} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 309 + value: 315 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -4481,7 +4519,7 @@ PrefabInstance: objectReference: {fileID: 48094519} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 331 + value: 337 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -5171,7 +5209,7 @@ Camera: near clip plane: 0.1 far clip plane: 5000 field of view: 40 - orthographic: 1 + orthographic: 0 orthographic size: 7 m_Depth: 0 m_CullingMask: @@ -5655,7 +5693,7 @@ PrefabInstance: objectReference: {fileID: 1367132531} - target: {fileID: 4461476242845816847, guid: d5f09e3d9ca134424b1900c7865fca19, type: 3} propertyPath: m_VersionIndex - value: 503 + value: 509 objectReference: {fileID: 0} - target: {fileID: 4461476242845816847, guid: d5f09e3d9ca134424b1900c7865fca19, type: 3} propertyPath: m_Faces.Array.size @@ -6797,7 +6835,7 @@ PrefabInstance: objectReference: {fileID: 929953728} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 276 + value: 282 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -7166,7 +7204,7 @@ PrefabInstance: objectReference: {fileID: 487086061} - target: {fileID: 4461476242845816847, guid: d5f09e3d9ca134424b1900c7865fca19, type: 3} propertyPath: m_VersionIndex - value: 423 + value: 429 objectReference: {fileID: 0} - target: {fileID: 4461476242845816847, guid: d5f09e3d9ca134424b1900c7865fca19, type: 3} propertyPath: m_Faces.Array.size @@ -12538,7 +12576,7 @@ PrefabInstance: objectReference: {fileID: 1769321392} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 276 + value: 282 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -22041,6 +22079,7 @@ MonoBehaviour: KnockoutTimeMultiplier: 0.1 knockdownTime: 0.1 recoverTime: 0.5 + maxKnockdown: 15 --- !u!1 &1450430340 GameObject: m_ObjectHideFlags: 0 @@ -22312,6 +22351,10 @@ MonoBehaviour: groundMask: serializedVersion: 2 m_Bits: 2147483648 + inheritGroundMotionY: 0 + preserveGroundVelocityWhenUngrounded: 1 + inheritedGroundVelocityDuration: 0.18 + inheritedGroundVelocityDecay: 30 groundCheckHeight: 1 groundCheckDistance: 3 groundOffset: 0 @@ -24102,6 +24145,184 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Entities.Sentinel.StateMachine.SentinelStateMachine currentState: 0 lastState: 0 +--- !u!43 &1854535944 +Mesh: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: pb_Mesh-57142 + serializedVersion: 12 + m_SubMeshes: + - serializedVersion: 2 + firstByte: 0 + indexCount: 36 + topology: 0 + baseVertex: 0 + firstVertex: 0 + vertexCount: 24 + localAABB: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 4, y: 0.25, z: 4} + m_Shapes: + vertices: [] + shapes: [] + channels: [] + fullWeights: [] + m_BindPose: [] + m_BoneNameHashes: + m_RootBoneNameHash: 0 + m_BonesAABB: [] + m_VariableBoneCountWeights: + m_Data: + m_MeshCompression: 0 + m_IsReadable: 1 + m_KeepVertices: 1 + m_KeepIndices: 1 + m_IndexFormat: 0 + m_IndexBuffer: 000001000200010003000200040005000600050007000600080009000a0009000b000a000c000d000e000d000f000e00100011001200110013001200140015001600150017001600 + m_VertexData: + serializedVersion: 3 + m_VertexCount: 24 + m_Channels: + - stream: 0 + offset: 0 + format: 0 + dimension: 3 + - stream: 0 + offset: 12 + format: 0 + dimension: 3 + - stream: 0 + offset: 24 + format: 0 + dimension: 4 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 40 + format: 0 + dimension: 2 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + - stream: 0 + offset: 0 + format: 0 + dimension: 0 + m_DataSize: 1152 + _typelessdata: 000080c0000080be0000804000000000000000000000803f000080bf0000000000000000000080bf000000410000003f00008040000080be0000804000000000000000000000803f000080bf0000000000000000000080bf000000000000003f000080c00000803e0000804000000000000000000000803f000080bf0000000000000000000080bf000000410000803f000080400000803e0000804000000000000000000000803f000080bf0000000000000000000080bf000000000000803f00008040000080be000080400000803f000000000000000000000000000000000000803f000080bf000000410000003f00008040000080be000080c00000803f000000000000000000000000000000000000803f000080bf000000000000003f000080400000803e000080400000803f000000000000000000000000000000000000803f000080bf000000410000803f000080400000803e000080c00000803f000000000000000000000000000000000000803f000080bf000000000000803f00008040000080be000080c00000000000000000000080bf0000803f0000000000000000000080bf000000410000003f000080c0000080be000080c00000000000000000000080bf0000803f0000000000000000000080bf000000000000003f000080400000803e000080c00000000000000000000080bf0000803f0000000000000000000080bf000000410000803f000080c00000803e000080c00000000000000000000080bf0000803f0000000000000000000080bf000000000000803f000080c0000080be000080c0000080bf00000000000000000000000000000000000080bf000080bf000000410000003f000080c0000080be00008040000080bf00000000000000000000000000000000000080bf000080bf000000000000003f000080c00000803e000080c0000080bf00000000000000000000000000000000000080bf000080bf000000410000803f000080c00000803e00008040000080bf00000000000000000000000000000000000080bf000080bf000000000000803f000080c00000803e00008040000000000000803f000000000000803f0000000000000000000080bf000000000000803f000080400000803e00008040000000000000803f000000000000803f0000000000000000000080bf000000410000803f000080c00000803e000080c0000000000000803f000000000000803f0000000000000000000080bf000000000000e0c0000080400000803e000080c0000000000000803f000000000000803f0000000000000000000080bf000000410000e0c0000080c0000080be000080c000000000000080bf00000000000080bf0000000000000000000080bf000000410000e0c000008040000080be000080c000000000000080bf00000000000080bf0000000000000000000080bf000000000000e0c0000080c0000080be0000804000000000000080bf00000000000080bf0000000000000000000080bf000000410000803f00008040000080be0000804000000000000080bf00000000000080bf0000000000000000000080bf000000000000803f + m_CompressedMesh: + m_Vertices: + m_NumItems: 0 + m_Range: 0 + m_Start: 0 + m_Data: + m_BitSize: 0 + m_UV: + m_NumItems: 0 + m_Range: 0 + m_Start: 0 + m_Data: + m_BitSize: 0 + m_Normals: + m_NumItems: 0 + m_Range: 0 + m_Start: 0 + m_Data: + m_BitSize: 0 + m_Tangents: + m_NumItems: 0 + m_Range: 0 + m_Start: 0 + m_Data: + m_BitSize: 0 + m_Weights: + m_NumItems: 0 + m_Data: + m_BitSize: 0 + m_NormalSigns: + m_NumItems: 0 + m_Data: + m_BitSize: 0 + m_TangentSigns: + m_NumItems: 0 + m_Data: + m_BitSize: 0 + m_FloatColors: + m_NumItems: 0 + m_Range: 0 + m_Start: 0 + m_Data: + m_BitSize: 0 + m_BoneIndices: + m_NumItems: 0 + m_Data: + m_BitSize: 0 + m_Triangles: + m_NumItems: 0 + m_Data: + m_BitSize: 0 + m_UVInfo: 0 + m_LocalAABB: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 4, y: 0.25, z: 4} + m_MeshUsageFlags: 0 + m_CookingOptions: 30 + m_BakedConvexCollisionMesh: + m_BakedTriangleCollisionMesh: + 'm_MeshMetrics[0]': 1 + 'm_MeshMetrics[1]': 1 + m_MeshOptimizationFlags: 1 + m_StreamData: + serializedVersion: 2 + offset: 0 + size: 0 + path: + m_MeshLodInfo: + serializedVersion: 2 + m_LodSelectionCurve: + serializedVersion: 1 + m_LodSlope: 0 + m_LodBias: 0 + m_NumLevels: 1 + m_SubMeshes: + - serializedVersion: 2 + m_Levels: + - serializedVersion: 1 + m_IndexStart: 0 + m_IndexCount: 0 --- !u!1 &1869388369 GameObject: m_ObjectHideFlags: 0 @@ -24369,7 +24590,7 @@ PrefabInstance: objectReference: {fileID: 571221644} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 320 + value: 326 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size @@ -24794,6 +25015,153 @@ CanvasGroup: m_Interactable: 1 m_BlocksRaycasts: 1 m_IgnoreParentGroups: 0 +--- !u!1001 &1977728341 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 332227168} + m_Modifications: + - target: {fileID: 101776470001583037, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: groundProfileMotion + value: + objectReference: {fileID: 1977728344} + - target: {fileID: 1597087542051609407, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: sizeX + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 1597087542051609407, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: sizeZ + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalPosition.z + value: -27.5 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 1854535944} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_VersionIndex + value: 265 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Tangents.Array.size + value: 24 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Textures0.Array.size + value: 24 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[0].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[1].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[2].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[3].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[4].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Faces.Array.data[5].m_Uv.m_Anchor + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6392326082573612157, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Size.x + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 6392326082573612157, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Size.z + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 6524376507900539265, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Name + value: Ground_Slab_Prototype + objectReference: {fileID: 0} + - target: {fileID: 7186094041257591047, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 1854535944} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 6524376507900539265, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + insertIndex: -1 + addedObject: {fileID: 1977728344} + m_SourcePrefab: {fileID: 100100000, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} +--- !u!4 &1977728342 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2109134711161568785, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} + m_PrefabInstance: {fileID: 1977728341} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1977728344 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 67093088} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 52f9a25d1be7481baf4085a7b34ef8bb, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::__Prototype.Scripts.TestGroundMorion + id: 72244c182c1b4b7f8026c837d732ae79 + localDirection: {x: 1, y: 0, z: 0} + speed: 2 + maxDistance: 16 + pingPong: 1 + moveOnStart: 1 --- !u!1001 &1981541173 PrefabInstance: m_ObjectHideFlags: 0 @@ -25094,7 +25462,7 @@ PrefabInstance: objectReference: {fileID: 36345656} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_VersionIndex - value: 331 + value: 337 objectReference: {fileID: 0} - target: {fileID: 2212457409070270700, guid: 28468bc4d76574c58b20f1a932bdaf62, type: 3} propertyPath: m_Tangents.Array.size diff --git a/Assets/Scripts/Intrepid/Core/Entities/EntityMotorTopDown.cs b/Assets/Scripts/Intrepid/Core/Entities/EntityMotorTopDown.cs index f27775c..287ef43 100644 --- a/Assets/Scripts/Intrepid/Core/Entities/EntityMotorTopDown.cs +++ b/Assets/Scripts/Intrepid/Core/Entities/EntityMotorTopDown.cs @@ -15,6 +15,9 @@ namespace Intrepid.Core.Entities [GroupConfigurations, SerializeField] private LayerMask groundMask; [GroupConfigurations, SerializeField] private bool inheritGroundMotionY; + [GroupConfigurations, SerializeField] private bool preserveGroundVelocityWhenUngrounded = true; + [GroupConfigurations, SerializeField] private float inheritedGroundVelocityDuration = 0.18f; + [GroupConfigurations, SerializeField] private float inheritedGroundVelocityDecay = 30f; [GroupConfigurations, SerializeField] private float groundCheckHeight = 1.0f; [GroupConfigurations, SerializeField] private float groundCheckDistance = 3.0f; [GroupConfigurations, SerializeField] private float groundOffset; @@ -25,32 +28,44 @@ namespace Intrepid.Core.Entities [GroupConfigurations, SerializeField] private float minFallHeight = 0.25f; [GroupConfigurations, SerializeField] private float fallAcceleration = 35f; [GroupConfigurations, SerializeField] private float maxFallSpeed = 18f; - + private Vector3 Origin { get; set; } private Vector3 End { get; set; } private bool HasHit { get; set; } - private GroundProfiles _currentGroundProfiles = GroundProfiles.None; + private Vector3 _inheritedGroundVelocity; private float _fallVerticalSpeed; private RaycastHit _groundHit; private float GroundProbeRadius => IsFalling || IsFallingToAbyss ? groundProbeRadiusFalling : groundProbeRadiusGrounded; - + + public GroundProfiles CurrentGroundProfiles { get; private set; } = GroundProfiles.None; public float MaxSlopeAngle => maxSlopeAngle; - [GroupDebug, ShowInInspector, ReadOnly] public Vector3 LastSafeGroundPosition { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] + public Vector3 LastSafeGroundPosition { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] public bool HasStableGroundNormal { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] public Vector3 StableGroundNormal { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] public bool IsFalling { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] public bool IsFallingToAbyss { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] public bool IsGrounded { get; private set; } + [GroupDebug, ShowInInspector, ReadOnly] + public Vector3 InheritedGroundVelocity => _inheritedGroundVelocity; + [GroupDebug, ShowInInspector, ReadOnly] + public float InheritedGroundVelocityTimer { get; private set; } public void ResetFallingToAbyss() { IsFalling = false; IsFallingToAbyss = false; - _currentGroundProfiles = GroundProfiles.None; + CurrentGroundProfiles = GroundProfiles.None; + ClearInheritedGroundVelocity(); } - + public void Move( Rigidbody body, Vector3 velocity, @@ -72,7 +87,7 @@ namespace Intrepid.Core.Entities } var movementVelocity = ResolveMovementVelocity(velocity); - var groundMotionDelta = ResolveGroundMotionDelta(); + var groundMotionDelta = ResolveGroundMotionDelta(deltaTime); var next = current + groundMotionDelta @@ -83,25 +98,20 @@ namespace Intrepid.Core.Entities IsGrounded = true; IsFallingToAbyss = false; - _currentGroundProfiles = groundProfiles; + CurrentGroundProfiles = groundProfiles; RegisterStableGroundNormal(nextNormal); + RefreshInheritedGroundVelocityFrom(groundProfiles); next.y = _groundHit.point.y + groundOffset; - LastSafeGroundPosition = new Vector3( - next.x, - next.y, - next.z - ); - - if (IsFalling) + if (CurrentGroundProfiles.IsSafe) { - IsFalling = false; - Proxy.Instance.EventBus.Raise(new EntityRecoverStableGroundEvent - { - EntityId = entity.Id, - }); + LastSafeGroundPosition = new Vector3( + next.x, + next.y, + next.z + ); } } else if (options.KeepHeightWhenNoGround) @@ -109,7 +119,11 @@ namespace Intrepid.Core.Entities IsGrounded = false; IsFalling = false; IsFallingToAbyss = false; - _currentGroundProfiles = GroundProfiles.None; + + // Important: + // We are no longer grounded, so the current ground profile must be cleared. + // But inherited ground velocity is intentionally preserved for game feel. + CurrentGroundProfiles = GroundProfiles.None; } else if (TryAnyGroundSurfaceBelowAt(next, out var fallHit, out _, out _) && IsGroundMeaningfullyBelow(current, fallHit)) @@ -125,15 +139,52 @@ namespace Intrepid.Core.Entities ApplyMove(body, next); } - - private Vector3 ResolveGroundMotionDelta() + + private Vector3 ResolveGroundMotionDelta(float deltaTime) { - if (!IsGrounded || !_currentGroundProfiles.TryGetGroundProfileMotion(out var motion)) + if (IsGrounded && CurrentGroundProfiles.TryGetGroundProfileMotion(out var motion)) + { + var delta = motion.DeltaPosition; + + CaptureInheritedGroundVelocity(motion.Velocity); + + if (inheritGroundMotionY) + { + return delta; + } + + return new Vector3(delta.x, 0f, delta.z); + } + + return ResolveInheritedGroundMotionDelta(deltaTime); + } + + private Vector3 ResolveInheritedGroundMotionDelta(float deltaTime) + { + if (!preserveGroundVelocityWhenUngrounded) { return Vector3.zero; } - var delta = motion.DeltaPosition; + if (InheritedGroundVelocityTimer <= 0f + || _inheritedGroundVelocity.sqrMagnitude <= GonConstants.CommonZeroSqrt) + { + ClearInheritedGroundVelocity(); + return Vector3.zero; + } + + var delta = _inheritedGroundVelocity * deltaTime; + + InheritedGroundVelocityTimer = Mathf.Max( + 0f, + InheritedGroundVelocityTimer - deltaTime + ); + + _inheritedGroundVelocity = Vector3.MoveTowards( + _inheritedGroundVelocity, + Vector3.zero, + inheritedGroundVelocityDecay * deltaTime + ); if (inheritGroundMotionY) { @@ -142,27 +193,63 @@ namespace Intrepid.Core.Entities return new Vector3(delta.x, 0f, delta.z); } - + + private void CaptureInheritedGroundVelocity(Vector3 velocity) + { + if (!preserveGroundVelocityWhenUngrounded) + { + return; + } + + if (!inheritGroundMotionY) + { + velocity.y = 0f; + } + + _inheritedGroundVelocity = velocity; + InheritedGroundVelocityTimer = inheritedGroundVelocityDuration; + } + + private void RefreshInheritedGroundVelocityFrom(GroundProfiles groundProfiles) + { + if (groundProfiles.TryGetGroundProfileMotion(out var motion)) + { + CaptureInheritedGroundVelocity(motion.Velocity); + return; + } + + ClearInheritedGroundVelocity(); + } + + private void ClearInheritedGroundVelocity() + { + _inheritedGroundVelocity = Vector3.zero; + InheritedGroundVelocityTimer = 0f; + } + private Vector3 ResolveFallingPosition(Vector3 current, float deltaTime) { IsGrounded = false; IsFallingToAbyss = false; + var inheritedMotionDelta = ResolveInheritedGroundMotionDelta(deltaTime); + _fallVerticalSpeed = Mathf.Min( _fallVerticalSpeed + fallAcceleration * deltaTime, maxFallSpeed ); - var next = current; + var next = current + inheritedMotionDelta; next.y -= _fallVerticalSpeed * deltaTime; - if (!TryAnyGroundSurfaceBelowAt(next, + if (!TryAnyGroundSurfaceBelowAt( + next, out var fallHit, out var fallNormal, out var fallProfiles)) { BeginFallToAbyss(); - return current; // or next? + return current; } var targetY = fallHit.point.y + groundOffset; @@ -180,8 +267,19 @@ namespace Intrepid.Core.Entities IsFalling = false; IsFallingToAbyss = false; _fallVerticalSpeed = 0f; - _currentGroundProfiles = fallProfiles; - + + CurrentGroundProfiles = fallProfiles; + RefreshInheritedGroundVelocityFrom(fallProfiles); + + if (CurrentGroundProfiles.IsSafe) + { + LastSafeGroundPosition = new Vector3( + next.x, + next.y, + next.z + ); + } + Proxy.Instance.EventBus.Raise(new EntityRecoverStableGroundEvent { EntityId = entity.Id, @@ -189,7 +287,7 @@ namespace Intrepid.Core.Entities return next; } - + private void BeginFall() { if (IsFalling) @@ -201,8 +299,11 @@ namespace Intrepid.Core.Entities IsFalling = true; IsFallingToAbyss = false; _fallVerticalSpeed = 0f; - _currentGroundProfiles = GroundProfiles.None; - + + // We clear the contact, but not the inherited velocity. + // This gives a short carry from the moving platform after leaving it. + CurrentGroundProfiles = GroundProfiles.None; + Proxy.Instance.EventBus.Raise(new EntityLeaveStableGroundEvent { EntityId = entity.Id, @@ -215,15 +316,17 @@ namespace Intrepid.Core.Entities { return; } - + DLogger.LogDebug("Real abyss fall"); - + IsGrounded = false; IsFalling = false; IsFallingToAbyss = true; _fallVerticalSpeed = 0f; - _currentGroundProfiles = GroundProfiles.None; - + + CurrentGroundProfiles = GroundProfiles.None; + ClearInheritedGroundVelocity(); + Proxy.Instance.EventBus.Raise(new EntityFaillingToAbyssEvent { EntityId = entity.Id, @@ -463,6 +566,15 @@ namespace Intrepid.Core.Entities transform.position + StableGroundNormal * 1.25f ); } + + if (_inheritedGroundVelocity.sqrMagnitude > GonConstants.CommonZeroSqrt) + { + Gizmos.color = Color.green; + Gizmos.DrawLine( + transform.position, + transform.position + _inheritedGroundVelocity.normalized * 1.5f + ); + } } #endif } diff --git a/Assets/Scripts/Intrepid/Core/Grounding/GroundProfileMotion.cs b/Assets/Scripts/Intrepid/Core/Grounding/GroundProfileMotion.cs index a744055..d094872 100644 --- a/Assets/Scripts/Intrepid/Core/Grounding/GroundProfileMotion.cs +++ b/Assets/Scripts/Intrepid/Core/Grounding/GroundProfileMotion.cs @@ -4,8 +4,9 @@ namespace Intrepid.Core.Grounding { public abstract class GroundProfileMotion : GroundProfile { - public abstract Vector3 Velocity { get; } - public abstract Vector3 DeltaPosition { get; } - public abstract bool IsMoving { get; } + public abstract Vector3 Velocity { get; protected set; } + public abstract Vector3 DeltaPosition { get; protected set; } + public abstract bool IsMoving { get; protected set; } + public abstract bool IsStatic { get; protected set; } } } \ No newline at end of file diff --git a/Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs b/Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs index eef4ec0..4210848 100644 --- a/Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs +++ b/Assets/Scripts/Intrepid/Core/Grounding/GroundProfiles.cs @@ -6,14 +6,25 @@ namespace Intrepid.Core.Grounding { public static readonly GroundProfiles None = new(false); - public bool IsSafe { get; } + private readonly bool _isSafe; private GroundProfileMotion GroundProfileMotion { get; } + public bool IsSafe => CheckIfThisProfileIsSafe(); public GroundProfiles(bool isSafe, GroundProfileMotion groundProfileMotion = null) { - IsSafe = isSafe; + _isSafe = isSafe; GroundProfileMotion = groundProfileMotion; } + + private bool CheckIfThisProfileIsSafe() + { + if (GroundProfileMotion.IsNull()) + { + return _isSafe; + } + + return GroundProfileMotion.IsStatic; + } private bool TryGet(T value, out T profile) where T: GroundProfile { diff --git a/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelBrain.cs b/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelBrain.cs index d4b446b..500dae0 100644 --- a/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelBrain.cs +++ b/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelBrain.cs @@ -4,6 +4,7 @@ using Intrepid.Core; using Intrepid.Core.Camera; using Intrepid.Core.Entities; using Intrepid.Core.Entities.Messages; +using Intrepid.Core.Grounding; using Intrepid.Core.TimeControl; using Intrepid.Gameplay.Entities.Player.ActionBelt; using Intrepid.Gameplay.Entities.Player.Sentinel; diff --git a/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelEntity.cs b/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelEntity.cs index a0a8223..a5a2c60 100644 --- a/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelEntity.cs +++ b/Assets/Scripts/Intrepid/Gameplay/Entities/Player/Sentinel/SentinelEntity.cs @@ -1,4 +1,5 @@ using Intrepid.Core.Entities; +using Intrepid.Core.Grounding; using Intrepid.GameManagers; using Intrepid.Gameplay.Messages.Events; using Intrepid.Utilities; @@ -30,6 +31,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel public Vector3 LinearVelocity { get; private set; } public Vector2 Forward => new Vector2(_desiredForward.x, _desiredForward.z).normalized; public bool IsGrounded => MotorTopDown.IsGrounded; + public GroundProfiles CurrentGroundProfiles => MotorTopDown.CurrentGroundProfiles; public override void DeployEntity(Vector2 position) {