Compare commits

...

No commits in common. "movement-physics" and "movement-surface-contact" have entirely different histories.

22 changed files with 97819 additions and 13796 deletions

1353
Assets/Scenes/Crevasse.unity Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 66d1ece53cdf641d7841b31236ea16b7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

1898
Assets/Scenes/Jump.unity Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

9641
Assets/Scenes/Parkour.unity Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 439764a2772394f03a6b9eb5e23b81fe
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
guid: 9fafc2503da6749cea6a1f8795a226df
DefaultImporter:
externalObjects: {}
userData:

12695
Assets/Scenes/Slopes.unity Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 87a03ddbc23374fbea4106bbd87484b9
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

59860
Assets/Scenes/Stairs.unity Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 89a7be54d6cc744f88bd699a3c912610
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

10014
Assets/Scenes/Steps.unity Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d9aa08533cdb74c099bb81f69d1cc0a7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a9666310024fc4682be7d0ec8aa47081
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -15,23 +15,41 @@ public class MovingSphere : MonoBehaviour
private int maxAirJumps = 0;
[SerializeField, Range(0f, 90f)]
private float maxGroundAngle = 25f;
private float maxGroundAngle = 25f, maxStairsAngle = 50f;
[SerializeField, Range(0f, 100f)]
float maxSnapSpeed = 100f;
[SerializeField, Min(0f)]
float probeDistance = 1f;
[SerializeField]
LayerMask probeMask = -1, stairsMask = -1;
private Rigidbody body;
private Vector3 desiredVelocity = new Vector3(0f, 0f, 0f);
private bool desiredJump = false;
private int groundContactCount;
private bool onGround => groundContactCount > 0;
private int jumpPhase;
private Vector3 velocity;
private Vector3 contactNormal;
private float minGroundDotProduct;
private Vector3 contactNormal, steepNormal;
private int groundContactCount, steepContactCount;
private float minGroundDotProduct, minStairsDotProduct;
private int stepsSinceLastGrounded, stepsSinceLastJump;
private bool onGround => groundContactCount > 0;
private bool onSteep => steepContactCount > 0;
private float GetMinDot(int layer)
{
return (stairsMask & (1 << layer)) == 0 ?
minGroundDotProduct : minStairsDotProduct;
}
private void OnValidate()
{
minGroundDotProduct = Mathf.Cos(maxGroundAngle * Mathf.Deg2Rad);
minStairsDotProduct = Mathf.Cos(maxStairsAngle * Mathf.Deg2Rad);
}
private void Awake()
@ -49,6 +67,10 @@ public class MovingSphere : MonoBehaviour
desiredVelocity = new Vector3(playerInput.x, 0f, playerInput.y) * maxSpeed;
desiredJump |= Input.GetButtonDown("Jump");
GetComponent<MeshRenderer>().material.SetColor(
"_BaseColor", onGround ? Color.black : Color.white
);
}
private void FixedUpdate()
@ -70,10 +92,16 @@ public class MovingSphere : MonoBehaviour
private void UpdateState()
{
stepsSinceLastGrounded++;
stepsSinceLastJump++;
velocity = body.velocity;
if (onGround)
if (onGround || SnapToGround() || CheckSteepContacts())
{
stepsSinceLastGrounded = 0;
if (stepsSinceLastJump > 1)
{
jumpPhase = 0;
}
if (groundContactCount > 1)
{
contactNormal.Normalize();
@ -97,30 +125,60 @@ public class MovingSphere : MonoBehaviour
private void EvaluateCollision(Collision collision)
{
float minDot = GetMinDot(collision.gameObject.layer);
for (int i = 0; i < collision.contactCount; i++)
{
var normal = collision.GetContact(i).normal;
if (normal.y >= minGroundDotProduct)
if (normal.y >= minDot)
{
groundContactCount += 1;
contactNormal += normal;
}
else if (normal.y > -0.01f)
{
steepContactCount += 1;
steepNormal += normal;
}
}
}
private void Jump()
{
if (onGround || jumpPhase < maxAirJumps)
Vector3 jumpDirection;
if (onGround)
{
jumpDirection = contactNormal;
}
else if (onSteep)
{
jumpDirection = steepNormal;
jumpPhase = 0;
}
else if (maxAirJumps > 0 && jumpPhase <= maxAirJumps)
{
if (jumpPhase == 0)
{
jumpPhase = 1;
}
jumpDirection = contactNormal;
}
else
{
return;
}
stepsSinceLastJump = 0;
jumpPhase++;
float jumpSpeed = Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight);
float alignedSpeed = Vector3.Dot(velocity, contactNormal);
jumpDirection = (jumpDirection + Vector3.up).normalized;
float alignedSpeed = Vector3.Dot(velocity, jumpDirection);
if (alignedSpeed > 0f)
{
jumpSpeed = Mathf.Max(jumpSpeed - alignedSpeed, 0f);
}
velocity += contactNormal * jumpSpeed;
}
velocity += jumpDirection * jumpSpeed;
}
private void AdjustVelocity()
@ -147,9 +205,54 @@ public class MovingSphere : MonoBehaviour
return vector - contactNormal * Vector3.Dot(vector, contactNormal);
}
void ClearState()
private void ClearState()
{
groundContactCount = 0;
contactNormal = Vector3.zero;
groundContactCount = steepContactCount = 0;
contactNormal = steepNormal = Vector3.zero;
}
private bool SnapToGround()
{
if (stepsSinceLastGrounded > 1 || stepsSinceLastJump <= 2)
{
return false;
}
float speed = velocity.magnitude;
if (speed > maxSnapSpeed)
{
return false;
}
if (!Physics.Raycast(body.position, Vector3.down, out RaycastHit hit, probeDistance, probeMask))
{
return false;
}
if (hit.normal.y < GetMinDot(hit.collider.gameObject.layer))
{
return false;
}
groundContactCount = 1;
contactNormal = hit.normal;
float dot = Vector3.Dot(velocity, hit.normal);
if (dot > 0f)
{
velocity = (velocity - hit.normal * dot).normalized * speed;
}
return true;
}
bool CheckSteepContacts()
{
if (steepContactCount > 1)
{
steepNormal.Normalize();
if (steepNormal.y >= minGroundDotProduct)
{
groundContactCount = 1;
contactNormal = steepNormal;
return true;
}
}
return false;
}
}

238
Assets/Sphere.prefab Normal file
View File

@ -0,0 +1,238 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6426552592410720839
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6426552592410720835}
- component: {fileID: 6426552592410720836}
- component: {fileID: 6426552592410720837}
- component: {fileID: 6426552592410720838}
- component: {fileID: 6426552592410720834}
- component: {fileID: 6426552592410720833}
- component: {fileID: 6426552592410720832}
m_Layer: 8
m_Name: Sphere
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6426552592410720835
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 22.5, y: 0.5, z: -9}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &6426552592410720836
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &6426552592410720837
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 728a9eb6ba9b95f4d918698f253a4553, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!135 &6426552592410720838
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_Material: {fileID: 13400000, guid: 3e12b1f04be465e48b61b3ad0978e7ef, type: 2}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}
--- !u!96 &6426552592410720834
TrailRenderer:
serializedVersion: 2
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 0
m_LightProbeUsage: 0
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 3483ecac0b7ab3f4c9cd0989279e6070, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_Time: 5
m_Parameters:
serializedVersion: 3
widthMultiplier: 0.1
widthCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
colorGradient:
serializedVersion: 2
key0: {r: 1, g: 1, b: 1, a: 1}
key1: {r: 1, g: 1, b: 1, a: 1}
key2: {r: 0, g: 0, b: 0, a: 0}
key3: {r: 0, g: 0, b: 0, a: 0}
key4: {r: 0, g: 0, b: 0, a: 0}
key5: {r: 0, g: 0, b: 0, a: 0}
key6: {r: 0, g: 0, b: 0, a: 0}
key7: {r: 0, g: 0, b: 0, a: 0}
ctime0: 0
ctime1: 65535
ctime2: 0
ctime3: 0
ctime4: 0
ctime5: 0
ctime6: 0
ctime7: 0
atime0: 0
atime1: 65535
atime2: 0
atime3: 0
atime4: 0
atime5: 0
atime6: 0
atime7: 0
m_Mode: 0
m_NumColorKeys: 2
m_NumAlphaKeys: 2
numCornerVertices: 0
numCapVertices: 0
alignment: 0
textureMode: 0
shadowBias: 0.5
generateLightingData: 0
m_MinVertexDistance: 0.1
m_Autodestruct: 0
m_Emitting: 1
--- !u!114 &6426552592410720833
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 50beb4685c906ba49b7db3438cc30dfc, type: 3}
m_Name:
m_EditorClassIdentifier:
maxSpeed: 10
maxAcceleration: 10
maxAirAcceleration: 1
jumpHeight: 2
maxAirJumps: 1
maxGroundAngle: 25
maxStairsAngle: 50
maxSnapSpeed: 100
probeDistance: 1
probeMask:
serializedVersion: 2
m_Bits: 1075
stairsMask:
serializedVersion: 2
m_Bits: 1024
--- !u!54 &6426552592410720832
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426552592410720839}
serializedVersion: 2
m_Mass: 1
m_Drag: 0
m_AngularDrag: 0.05
m_UseGravity: 1
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 112
m_CollisionDetection: 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3dd5393965472a4438e901f90d336e67
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,7 +3,7 @@
--- !u!55 &1
PhysicsManager:
m_ObjectHideFlags: 0
serializedVersion: 11
serializedVersion: 13
m_Gravity: {x: 0, y: -9.81, z: 0}
m_DefaultMaterial: {fileID: 0}
m_BounceThreshold: 2
@ -17,11 +17,12 @@ PhysicsManager:
m_ClothInterCollisionDistance: 0
m_ClothInterCollisionStiffness: 0
m_ContactsGeneration: 1
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_LayerCollisionMatrix: fffbfffffffbfffffffbfffffffffffffffbfffffffbfffffffffffffffffffffffdfffffffaffffc8f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_AutoSimulation: 1
m_AutoSyncTransforms: 0
m_ReuseCollisionCallbacks: 1
m_ClothInterCollisionSettingsToggle: 0
m_ClothGravity: {x: 0, y: -9.81, z: 0}
m_ContactPairsMode: 0
m_BroadphaseType: 0
m_WorldBounds:
@ -31,4 +32,5 @@ PhysicsManager:
m_FrictionType: 0
m_EnableEnhancedDeterminism: 0
m_EnableUnifiedHeightmaps: 1
m_DefaultMaxAngluarSpeed: 7
m_SolverType: 0
m_DefaultMaxAngularSpeed: 7

View File

@ -1,2 +1,2 @@
m_EditorVersion: 2019.4.18f1c1
m_EditorVersionWithRevision: 2019.4.18f1c1 (6ddd89a99571)
m_EditorVersion: 2019.4.19f1c1
m_EditorVersionWithRevision: 2019.4.19f1c1 (e27b4ba3cbee)

View File

@ -13,9 +13,9 @@ TagManager:
- UI
-
-
-
-
-
- Agent
- Detailed
- Stairs
-
-
-