Untitled
using UnityEngine; public class SonicController : MonoBehaviour { [Header("Movement Variables")] public float acceleration; // How fast Sonic accelerates on the ground public float deceleration; // How fast Sonic slows down when no input is given public float topSpeed; // Maximum speed Sonic can reach while on the ground public float maxSpeed; // Absolute maxiumum speed Sonic can reach [Header("Air Movement Variables")] public float airAcceleration; // How fast Sonic accelerates while in the air public float airDeceleration; // How fast Sonic slows down in the air public float airTopSpeed; // Maximum speed Sonic can reach while in the air [Header("Jumping Variables")] public float jumpForce; // Initial force applied when Sonic jumps public float minJumpHeight; // Minimum height Sonic can reach when jump button is released early public float maxJumpHeight; // Maximum height Sonic can reach if the jump button is held [Header("Ground Detection Variables")] public float groundCheckDistance; // Distance to check below Sonic to determine if grounded public LayerMask groundLayer; // Layers considered as ground for detection [Header("Slope Physics Variables")] public float slopeAssistance = 5f; // Multiplier for increasing speed when moving downhill public float slopeDrag = 5f; // Multiplier for decreasing speed when moving uphill public float wallStickSpeedThreshold = 2f; // Speed threshold below which Sonic will stick to walls on steep slopes private Rigidbody rb; // Reference to Sonic's Rigidbody component private bool isGrounded; // Boolean to check if Sonic is currently on the ground private float currentSpeed; // Sonic's current movement speed private Vector3 groundNormal; // The normal of the surface Sonic is currently on void Start() { rb = GetComponent<Rigidbody>(); // Initialize the Rigidbody reference } void Update() { CheckGrounded(); // Check if Sonic is grounded HandleMovement(); // Handle Sonic's movement HandleJump(); // Handle Sonic's jumping } void HandleMovement() { float horizontalInput = Input.GetAxis("Horizontal"); // Get horizontal input (left/right movement) float verticalInput = Input.GetAxis("Vertical"); // Get vertical input (forward/backward movement) Vector3 inputDirection = new Vector3(horizontalInput, 0f, verticalInput).normalized; // Combine inputs into a direction vector bool isBoosting = Input.GetKey(KeyCode.RightShift); // Check if the boost key is pressed if (isGrounded) { AlignWithGround(); // Align Sonic with the ground's slope float slopeRotation = Vector3.Dot(inputDirection, groundNormal); // Calculate rotation based on slope if (isBoosting) { currentSpeed = maxSpeed; // Set speed to max if boosting } else { if (inputDirection.magnitude > 0) { currentSpeed += acceleration * Time.deltaTime; // Increase speed based on acceleration currentSpeed = Mathf.Clamp(currentSpeed, 0, topSpeed); // Clamp speed to topSpeed if (slopeRotation > 0) // Moving downhill { currentSpeed += slopeRotation * slopeAssistance * Time.deltaTime; // Increase speed downhill } else if (slopeRotation < 0) // Moving uphill { currentSpeed += slopeRotation * slopeDrag * Time.deltaTime; // Decrease speed uphill } } else { currentSpeed -= deceleration * Time.deltaTime; // Decrease speed when no input if (currentSpeed < 0) currentSpeed = 0; // Prevent speed from going negative } } if (inputDirection.magnitude > 0) { Quaternion targetRotation = Quaternion.LookRotation(inputDirection); // Rotate to face movement direction transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 10f); // Smooth rotation } } else { if (inputDirection.magnitude > 0) { currentSpeed += airAcceleration * Time.deltaTime; // Increase speed in the air currentSpeed = Mathf.Clamp(currentSpeed, 0, airTopSpeed); // Clamp speed to airTopSpeed } } Vector3 moveDirection = transform.forward * currentSpeed; // Calculate movement direction rb.velocity = new Vector3(moveDirection.x, rb.velocity.y, moveDirection.z); // Apply velocity to Rigidbody } void HandleJump() { if (Input.GetButtonDown("Jump") && isGrounded) { Vector3 jumpDirection = groundNormal * jumpForce; // Calculate jump force based on ground normal float slopeJumpForce = rb.velocity.y * currentSpeed; // Apply slope-based jump force rb.velocity = new Vector3(rb.velocity.x, jumpDirection.y + slopeJumpForce, rb.velocity.z); // Apply jump velocity } if (Input.GetButtonUp("Jump") && rb.velocity.y > minJumpHeight) { rb.velocity = new Vector3(rb.velocity.x, minJumpHeight, rb.velocity.z); // Limit jump height when button is released } } void CheckGrounded() { RaycastHit hit; isGrounded = Physics.Raycast(transform.position, Vector3.down, out hit, groundCheckDistance, groundLayer); // Check if grounded if (isGrounded) { groundNormal = hit.normal; // Store the ground normal if (Vector3.Angle(Vector3.up, groundNormal) >= 90f && currentSpeed < wallStickSpeedThreshold) { isGrounded = false; // Disable grounding on steep slopes if speed is low } } } void AlignWithGround() { Quaternion slopeRotation = Quaternion.FromToRotation(transform.up, groundNormal) * transform.rotation; // Align rotation with ground transform.rotation = Quaternion.Slerp(transform.rotation, slopeRotation, Time.deltaTime * 10f); // Smooth rotation alignment } private void OnDrawGizmosSelected() { Gizmos.color = Color.red; // Set Gizmo color Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundCheckDistance); // Draw ground check line } }
Leave a Comment