161 lines
6.2 KiB
C#
161 lines
6.2 KiB
C#
using UnityEngine;
|
||
|
||
public class BallController : MonoBehaviour
|
||
{
|
||
[Header("Настройки Движения")]
|
||
[SerializeField] private float maxSpeed = 15f; // Максимальная скорость на земле
|
||
[SerializeField] private float accelerationRate = 200f; // Как быстро шарик разгоняется
|
||
[SerializeField] private float airControlSpeed = 5f; // Скорость управления в прыжке
|
||
[SerializeField] private float jumpForce = 7f; // Сила прыжка
|
||
[SerializeField] private float trampolineBounceForce = 1.5f; // Множитель для отскока от батута
|
||
|
||
[Header("Настройки Контроля")]
|
||
[Tooltip("Как быстро шарик останавливается (сила торможения). Должна быть высокой.")]
|
||
[SerializeField] private float decelerationRate = 200f; // Сила торможения
|
||
|
||
private Rigidbody rb;
|
||
private bool isGrounded;
|
||
|
||
void Start()
|
||
{
|
||
rb = GetComponent<Rigidbody>();
|
||
|
||
// УБЕДИСЬ, ЧТО ЭТА СТРОКА ЗАКОММЕНТИРОВАНА ИЛИ УДАЛЕНА!
|
||
// rb.freezeRotation = true;
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
HandleJumpInput();
|
||
}
|
||
|
||
void FixedUpdate()
|
||
{
|
||
isGrounded = false;
|
||
HandleMovement();
|
||
}
|
||
|
||
// --- Логика Управления Движением ---
|
||
|
||
private void HandleMovement()
|
||
{
|
||
// Используем GetAxisRaw для мгновенного отклика (1, 0, -1)
|
||
float moveX = Input.GetAxisRaw("Horizontal");
|
||
float moveZ = Input.GetAxisRaw("Vertical");
|
||
|
||
if (isGrounded)
|
||
{
|
||
Vector3 currentVel = rb.linearVelocity;
|
||
Vector3 currentAngularVel = rb.angularVelocity;
|
||
|
||
// --- Управление Осью X (A/D) ---
|
||
if (Mathf.Abs(moveX) > 0.01f)
|
||
{
|
||
// 1. Ускорение по X
|
||
if (Mathf.Abs(currentVel.x) < maxSpeed)
|
||
{
|
||
rb.AddForce(new Vector3(moveX, 0, 0) * accelerationRate, ForceMode.Acceleration);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 2. Торможение по X (Линейное)
|
||
// Применяем силу против текущей скорости X
|
||
float brakeForceX = -currentVel.x;
|
||
rb.AddForce(new Vector3(brakeForceX, 0, 0) * decelerationRate, ForceMode.Acceleration);
|
||
|
||
// 2. Торможение по X (Угловое - качение по X = вращение по Z)
|
||
// Применяем крутящий момент против вращения по Z
|
||
float brakeTorqueZ = -currentAngularVel.z;
|
||
rb.AddTorque(new Vector3(0, 0, brakeTorqueZ) * decelerationRate, ForceMode.Acceleration);
|
||
}
|
||
|
||
// --- Управление Осью Z (W/S) ---
|
||
if (Mathf.Abs(moveZ) > 0.01f)
|
||
{
|
||
// 1. Ускорение по Z
|
||
if (Mathf.Abs(currentVel.z) < maxSpeed)
|
||
{
|
||
rb.AddForce(new Vector3(0, 0, moveZ) * accelerationRate, ForceMode.Acceleration);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 2. Торможение по Z (Линейное)
|
||
// Применяем силу против текущей скорости Z
|
||
float brakeForceZ = -currentVel.z;
|
||
rb.AddForce(new Vector3(0, 0, brakeForceZ) * decelerationRate, ForceMode.Acceleration);
|
||
|
||
// 2. Торможение по Z (Угловое - качение по Z = вращение по X)
|
||
// Применяем крутящий момент против вращения по X
|
||
float brakeTorqueX = -currentAngularVel.x;
|
||
rb.AddTorque(new Vector3(brakeTorqueX, 0, 0) * decelerationRate, ForceMode.Acceleration);
|
||
}
|
||
|
||
// Ограничение максимальной скорости
|
||
Vector3 horizontalVel = new Vector3(rb.linearVelocity.x, 0, rb.linearVelocity.z);
|
||
if (horizontalVel.sqrMagnitude > maxSpeed * maxSpeed)
|
||
{
|
||
Vector3 clampedVel = horizontalVel.normalized * maxSpeed;
|
||
rb.linearVelocity = new Vector3(clampedVel.x, rb.linearVelocity.y, clampedVel.z);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Управление в воздухе
|
||
Vector3 movement = new Vector3(moveX, 0.0f, moveZ).normalized;
|
||
rb.AddForce(movement * airControlSpeed, ForceMode.Acceleration);
|
||
}
|
||
}
|
||
|
||
private void HandleJumpInput()
|
||
{
|
||
if (Input.GetButtonDown("Jump") && isGrounded)
|
||
{
|
||
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
|
||
isGrounded = false;
|
||
}
|
||
}
|
||
|
||
// --- Логика Взаимодействия и Тегирования ---
|
||
|
||
private void OnCollisionEnter(Collision collision)
|
||
{
|
||
if (collision.gameObject.CompareTag("Trampoline"))
|
||
{
|
||
HandleTrampolineBounce(collision);
|
||
return;
|
||
}
|
||
CheckIfGrounded(collision);
|
||
}
|
||
|
||
private void OnCollisionStay(Collision collision)
|
||
{
|
||
CheckIfGrounded(collision);
|
||
}
|
||
|
||
private void HandleTrampolineBounce(Collision collision)
|
||
{
|
||
Vector3 surfaceNormal = Vector3.up;
|
||
if (collision.contacts.Length > 0)
|
||
{
|
||
surfaceNormal = collision.contacts[0].normal;
|
||
}
|
||
rb.linearVelocity = Vector3.zero;
|
||
rb.AddForce(surfaceNormal * jumpForce * trampolineBounceForce, ForceMode.Impulse);
|
||
}
|
||
|
||
private void CheckIfGrounded(Collision collision)
|
||
{
|
||
if (isGrounded) return;
|
||
|
||
if (collision.contacts.Length > 0)
|
||
{
|
||
Vector3 normal = collision.contacts[0].normal;
|
||
if (normal.y > 0.7f) // ~45 градусов
|
||
{
|
||
isGrounded = true;
|
||
}
|
||
}
|
||
}
|
||
} |