Slope handling

Player movement is now smooth on slopes.
Clamped debug camera vertical rotation.
This commit is contained in:
Banane_Rotative
2025-03-06 15:52:22 +01:00
parent 736f1ed646
commit 8acbd5c9e5
2 changed files with 128 additions and 30 deletions

View File

@@ -119,6 +119,39 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &90518571
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 90518572}
m_Layer: 0
m_Name: Terrain
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &90518572
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 90518571}
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: 272243396}
- {fileID: 1192843592}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &99782791
GameObject:
m_ObjectHideFlags: 0
@@ -229,9 +262,7 @@ Transform:
m_LocalScale: {x: 1, y: 0.9, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1561010223}
- {fileID: 493760350}
- {fileID: 330585546}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &99782796
@@ -250,6 +281,7 @@ MonoBehaviour:
speed: 15
sensitivity: 70
maxSpeed: 10
maxSlopeAngle: 30
--- !u!54 &99782797
Rigidbody:
m_ObjectHideFlags: 0
@@ -379,12 +411,12 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 272243392}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 5, y: 5, z: 5}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_Father: {fileID: 90518572}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &330585543
GameObject:
@@ -463,13 +495,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
serializedVersion: 2
m_LocalRotation: {x: 0.08715578, y: 0, z: 0, w: 0.9961947}
m_LocalPosition: {x: 0, y: 2, z: -3.31}
m_LocalScale: {x: 1, y: 1.1111112, z: 1}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1.1111114, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 99782795}
m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0}
m_Father: {fileID: 493760350}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &330585547
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -667,6 +699,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 990919147}
- {fileID: 330585546}
m_Father: {fileID: 99782795}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!81 &493760351
@@ -689,6 +722,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5a895e8a798ee0b4a9a5ea33d6b07f4b, type: 3}
m_Name:
m_EditorClassIdentifier:
minRotation: -90
maxRotation: 90
--- !u!1 &990919146
GameObject:
m_ObjectHideFlags: 0
@@ -720,7 +755,7 @@ Transform:
m_Children: []
m_Father: {fileID: 493760350}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1561010222
--- !u!1 &1192843591
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -728,38 +763,61 @@ GameObject:
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1561010223}
- component: {fileID: 1561010225}
- component: {fileID: 1561010224}
- component: {fileID: 1192843592}
- component: {fileID: 1192843595}
- component: {fileID: 1192843594}
- component: {fileID: 1192843593}
m_Layer: 0
m_Name: Noze
m_Name: Slope
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1561010223
--- !u!4 &1192843592
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1561010222}
m_GameObject: {fileID: 1192843591}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0.2, z: 0.5}
m_LocalScale: {x: 0.3, y: 0.3, z: 0.3}
m_LocalRotation: {x: 0, y: 0, z: -0.24784453, w: 0.9687998}
m_LocalPosition: {x: -5.5, y: 1.13, z: -6.62}
m_LocalScale: {x: 0.5, y: 1, z: 0.5}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 99782795}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!23 &1561010224
m_Father: {fileID: 90518572}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: -28.7}
--- !u!64 &1192843593
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1192843591}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 5
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1192843594
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1561010222}
m_GameObject: {fileID: 1192843591}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
@@ -798,14 +856,14 @@ MeshRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &1561010225
--- !u!33 &1192843595
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1561010222}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
m_GameObject: {fileID: 1192843591}
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
--- !u!1 &1697224667
GameObject:
m_ObjectHideFlags: 0
@@ -1126,6 +1184,6 @@ SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 410087041}
- {fileID: 272243396}
- {fileID: 99782795}
- {fileID: 1697224671}
- {fileID: 90518572}

View File

@@ -1,22 +1,35 @@
using UnityEngine;
using UnityEngine.EventSystems;
// Handles everything related to player movement
public class PlayerController : MonoBehaviour
{
[SerializeField] private EarsController ears = null;
[Header("Vertical rotation")]
[SerializeField] float minRotation = -90f;
[SerializeField] float maxRotation = 90f;
[Header("Player speed")]
[SerializeField] private float speed = 15;
[SerializeField] private float sensitivity = 50;
[SerializeField] private float maxSpeed = 10;
[Header("Slope handling")]
[SerializeField] private float maxSlopeAngle = 20f;
private RaycastHit slopeHit;
private float playerHeight = 2f;
private PlayerControlsMap playerControls;
private Rigidbody rb;
private Vector3 currentRotation = Vector3.zero;
// Awake is always called before Start. Often used to initialize variables
void Awake()
{
playerHeight = 2f * transform.localScale.y;
playerControls = new PlayerControlsMap();
rb = GetComponent<Rigidbody>();
@@ -50,23 +63,27 @@ public class PlayerController : MonoBehaviour
}
// Rotate player according to input
void RotatePlayer() {
// Update player direction. Very basic
// First, rotate player on y axis
Vector2 lookInput = playerControls.Player.Look.ReadValue<Vector2>();
lookInput *= sensitivity * Time.deltaTime;
currentRotation += new Vector3(Mathf.Clamp(-lookInput.y, -90, 90), lookInput.x, 0);
currentRotation += new Vector3(-lookInput.y, lookInput.x, 0);
currentRotation.x = Mathf.Clamp(currentRotation.x, minRotation, maxRotation);
transform.localEulerAngles = new Vector3(0, currentRotation.y, 0);
// Then, rotate player's ears on both x and z axes (only available with certain controllers such as AR/VR)
ears.RotateHead(new Vector3(currentRotation.x, 0, currentRotation.z));
}
// Move player according to input
void MovePlayer() {
// Update player acceleration, using a force
Vector2 mvtInput = playerControls.Player.Move.ReadValue<Vector2>();
mvtInput *= speed * Time.deltaTime;
rb.AddForce(transform.rotation * new Vector3(mvtInput.x, 0, mvtInput.y), ForceMode.VelocityChange);
Vector3 moveDirection = GetMoveDirection(transform.rotation*new Vector3(mvtInput.x, 0, mvtInput.y));
rb.AddForce(moveDirection * speed * Time.deltaTime, ForceMode.VelocityChange);
// Limit max speed.
// maxSpeed affects only max speed, while rigidbody's linear damping affects both max speed and deceleration
@@ -74,4 +91,27 @@ public class PlayerController : MonoBehaviour
rb.linearVelocity = rb.linearVelocity.normalized * maxSpeed;
}
}
// Check if player is on a slope
bool OnSlope() {
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.2f)) {
float angle = Vector3.Angle(Vector3.up, slopeHit.normal);
return angle < maxSlopeAngle && angle != 0;
}
return false;
}
// Get move direction, whether there is a slope or not
private Vector3 GetMoveDirection(Vector3 mvtInput) {
if (OnSlope()) {
Vector3 mvtDir = Vector3.ProjectOnPlane(mvtInput, slopeHit.normal);
// Limit norm of direction to 1, while allowing lower
if (mvtDir.magnitude > 1) {
return mvtDir.normalized;
}
return mvtDir;
}
return mvtInput;
}
}