232 lines
8.3 KiB
C#
232 lines
8.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace BulletHellTemplate
|
|
{
|
|
/// <summary>
|
|
/// Handles advanced character movement, including walking, jumping, and being pushed.
|
|
/// Requires a CharacterController component to function correctly.
|
|
/// </summary>
|
|
[RequireComponent(typeof(CharacterController))]
|
|
public class AdvancedCharacterController : MonoBehaviour
|
|
{
|
|
public float moveSpeed = 5f; // Speed at which the character moves
|
|
public float pushForce = 10f; // Force applied when being pushed
|
|
public float rotationSpeed = 720f; // Speed of character rotation
|
|
public float jumpHeight = 2f; // Height the character can jump
|
|
public float gravity = 9.81f; // Gravity applied to the character
|
|
public float maxFallVelocity = 40f; // Maximum velocity when falling
|
|
|
|
private CharacterController characterController; // The CharacterController component
|
|
private Vector3 moveDirection = Vector3.zero; // Current direction of movement
|
|
private Vector3 pushDirection = Vector3.zero; // Direction of any applied push force
|
|
private float verticalVelocity; // Vertical velocity for gravity and jumping
|
|
private bool isJumping = false; // Indicates if the character is currently jumping
|
|
private bool isMovementStopped = false;
|
|
[HideInInspector]public bool CanRotateWhileStopped { get; private set; } = false;
|
|
void Start()
|
|
{
|
|
// Initialize the CharacterController component
|
|
characterController = GetComponent<CharacterController>();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
// Apply gravity and move the character each frame
|
|
ApplyGravity();
|
|
MoveCharacter();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves the character in a specified direction.
|
|
/// </summary>
|
|
/// <param name="direction">Direction vector for movement.</param>
|
|
public void Move(Vector3 direction)
|
|
{
|
|
if (GameplayManager.Singleton.IsPaused())
|
|
{
|
|
moveDirection = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
if (isMovementStopped)
|
|
{
|
|
if (CanRotateWhileStopped && direction.magnitude > 0)
|
|
{
|
|
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
|
|
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref rotationSpeed, 0.1f);
|
|
transform.rotation = Quaternion.Euler(0, angle, 0);
|
|
}
|
|
moveDirection = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
if (direction.magnitude > 0)
|
|
{
|
|
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
|
|
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref rotationSpeed, 0.1f);
|
|
transform.rotation = Quaternion.Euler(0, angle, 0);
|
|
|
|
moveDirection = direction.normalized * moveSpeed;
|
|
}
|
|
else
|
|
{
|
|
moveDirection = Vector3.zero;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the character jump if grounded.
|
|
/// </summary>
|
|
public void Jump()
|
|
{
|
|
if (characterController.isGrounded)
|
|
{
|
|
isJumping = true;
|
|
verticalVelocity = Mathf.Sqrt(2 * jumpHeight * gravity);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies a force to push the character.
|
|
/// </summary>
|
|
/// <param name="force">The force to apply.</param>
|
|
public void Push(Vector3 force)
|
|
{
|
|
pushDirection = force;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Alters the character's movement speed.
|
|
/// </summary>
|
|
/// <param name="newSpeed">The new speed value.</param>
|
|
public void AlterSpeed(float newSpeed)
|
|
{
|
|
moveSpeed = newSpeed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current speed of the character.
|
|
/// </summary>
|
|
/// <returns>The magnitude of the character's movement velocity.</returns>
|
|
public float GetCurrentSpeed()
|
|
{
|
|
Vector3 horizontalVelocity = new Vector3(moveDirection.x + pushDirection.x, 0, moveDirection.z + pushDirection.z);
|
|
return horizontalVelocity.magnitude;
|
|
}
|
|
|
|
|
|
private void ApplyGravity()
|
|
{
|
|
if (characterController.isGrounded)
|
|
{
|
|
if (!isJumping)
|
|
{
|
|
verticalVelocity = -gravity * Time.deltaTime;
|
|
}
|
|
else
|
|
{
|
|
verticalVelocity -= gravity * Time.deltaTime;
|
|
isJumping = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
verticalVelocity -= gravity * Time.deltaTime;
|
|
if (verticalVelocity < -maxFallVelocity)
|
|
{
|
|
verticalVelocity = -maxFallVelocity;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MoveCharacter()
|
|
{
|
|
if (isMovementStopped)
|
|
{
|
|
characterController.Move(Vector3.zero);
|
|
return;
|
|
}
|
|
|
|
Vector3 velocity = moveDirection + pushDirection;
|
|
velocity.y = verticalVelocity;
|
|
|
|
if (GameplayManager.Singleton.IsPaused())
|
|
{
|
|
characterController.Move(Vector3.zero);
|
|
}
|
|
else
|
|
{
|
|
characterController.Move(velocity * Time.deltaTime);
|
|
}
|
|
|
|
// Gradually reduce push force over time
|
|
pushDirection = Vector3.Lerp(pushDirection, Vector3.zero, Time.deltaTime * pushForce);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops the movement of the character temporarily, allowing optional rotation.
|
|
/// </summary>
|
|
/// <param name="allowRotation">Whether rotation is allowed while movement is stopped.</param>
|
|
public void StopMovement(bool allowRotation = false)
|
|
{
|
|
isMovementStopped = true;
|
|
CanRotateWhileStopped = allowRotation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resumes the movement of the character.
|
|
/// </summary>
|
|
public void ResumeMovement()
|
|
{
|
|
isMovementStopped = false;
|
|
CanRotateWhileStopped = false;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Performs a dash in the specified direction while ensuring that the character does not pass through walls.
|
|
/// The dash increases the movement speed temporarily, locks the movement direction, and ensures the character faces the dash direction.
|
|
/// </summary>
|
|
/// <param name="dashSpeed">The speed to dash at.</param>
|
|
/// <param name="dashDuration">The duration of the dash in seconds.</param>
|
|
/// <param name="direction">The direction vector in which to dash, typically coming from the joystick input.</param>
|
|
public IEnumerator Dash(Vector3 direction, float dashSpeed, float dashDuration)
|
|
{
|
|
// Normalize the dash direction
|
|
Vector3 dashDirection = direction.normalized;
|
|
|
|
// Rotate character to face dash direction
|
|
if (dashDirection.magnitude > 0)
|
|
{
|
|
float targetAngle = Mathf.Atan2(dashDirection.x, dashDirection.z) * Mathf.Rad2Deg;
|
|
transform.rotation = Quaternion.Euler(0, targetAngle, 0); // Instantly rotate to dash direction
|
|
}
|
|
|
|
// Store the original speed and temporarily disable normal movement
|
|
float originalSpeed = moveSpeed;
|
|
moveSpeed = 0f;
|
|
|
|
float elapsedTime = 0f;
|
|
|
|
// Perform the dash by temporarily setting the dash speed
|
|
while (elapsedTime < dashDuration)
|
|
{
|
|
// Apply dash movement in the locked dash direction using CharacterController
|
|
Vector3 dashMovement = dashDirection * dashSpeed * Time.deltaTime;
|
|
characterController.Move(dashMovement);
|
|
|
|
// Increase the elapsed time
|
|
elapsedTime += Time.deltaTime;
|
|
yield return null;
|
|
}
|
|
|
|
// After the dash, return to the original movement speed
|
|
moveSpeed = originalSpeed;
|
|
}
|
|
|
|
|
|
}
|
|
}
|