-Донастроенный трейл -Текстура шарика -Шарик при отсутствии сил замедляется -сиськи письки
177 lines
6.2 KiB
C#
177 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 = 5f; // Сила, замедляющая шарик (трение)
|
|
|
|
[SerializeField] private float groundCheckDistance = 0.1f; // Дистанция для проверки земли
|
|
|
|
private Rigidbody rb;
|
|
private bool isGrounded;
|
|
private float sphereRadius;
|
|
|
|
// Переменные для считывания ввода
|
|
private float moveX;
|
|
private float moveZ;
|
|
|
|
void Start()
|
|
{
|
|
rb = GetComponent<Rigidbody>();
|
|
sphereRadius = GetComponent<SphereCollider>().radius;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
// 1. Считываем ввод в Update
|
|
moveX = Input.GetAxisRaw("Horizontal");
|
|
moveZ = Input.GetAxisRaw("Vertical");
|
|
|
|
HandleJumpInput();
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
CheckGrounded();
|
|
HandleMovement();
|
|
}
|
|
|
|
// Свойство для проверки состояния "на земле" из других скриптов
|
|
public bool IsGrounded
|
|
{
|
|
get { return isGrounded; }
|
|
}
|
|
|
|
private void CheckGrounded()
|
|
{
|
|
isGrounded = false;
|
|
Vector3 origin = transform.position;
|
|
if (Physics.Raycast(origin, -Vector3.up, out RaycastHit hit, sphereRadius + groundCheckDistance))
|
|
{
|
|
if (hit.normal.y > 0.7f)
|
|
{
|
|
isGrounded = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Логика Управления Движением ---
|
|
|
|
private void HandleMovement()
|
|
{
|
|
if (isGrounded)
|
|
{
|
|
// Определяем, есть ли ввод от игрока
|
|
bool hasInput = Mathf.Abs(moveX) > 0.01f || Mathf.Abs(moveZ) > 0.01f;
|
|
|
|
if (hasInput)
|
|
{
|
|
ApplyAcceleration();
|
|
}
|
|
else
|
|
{
|
|
ApplyDeceleration();
|
|
}
|
|
|
|
// Ограничение максимальной скорости (применяется всегда, если шарик на земле)
|
|
ClampHorizontalSpeed();
|
|
}
|
|
else
|
|
{
|
|
// Управление в воздухе
|
|
Vector3 movement = new Vector3(moveX, 0.0f, moveZ).normalized;
|
|
rb.AddForce(movement * airControlSpeed, ForceMode.Acceleration);
|
|
}
|
|
}
|
|
|
|
private void ApplyAcceleration()
|
|
{
|
|
Vector3 currentVel = rb.linearVelocity;
|
|
|
|
// 1. Ускорение по X (A/D)
|
|
if (Mathf.Abs(moveX) > 0.01f)
|
|
{
|
|
if (Mathf.Abs(currentVel.x) < maxSpeed)
|
|
{
|
|
rb.AddForce(new Vector3(moveX, 0, 0) * accelerationRate, ForceMode.Acceleration);
|
|
}
|
|
}
|
|
|
|
// 2. Ускорение по Z (W/S)
|
|
if (Mathf.Abs(moveZ) > 0.01f)
|
|
{
|
|
if (Mathf.Abs(currentVel.z) < maxSpeed)
|
|
{
|
|
rb.AddForce(new Vector3(0, 0, moveZ) * accelerationRate, ForceMode.Acceleration);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplyDeceleration()
|
|
{
|
|
Vector3 horizontalVel = new Vector3(rb.linearVelocity.x, 0, rb.linearVelocity.z);
|
|
|
|
// Применяем силу, противоположную скорости (имитация трения)
|
|
if (horizontalVel.sqrMagnitude > 0.01f)
|
|
{
|
|
// Направление силы, противоположное скорости
|
|
Vector3 frictionForce = -horizontalVel.normalized * decelerationRate;
|
|
rb.AddForce(frictionForce, ForceMode.Acceleration);
|
|
}
|
|
else
|
|
{
|
|
// Если скорость очень низка, останавливаем горизонтальное движение, чтобы избежать "дрейфа"
|
|
rb.linearVelocity = new Vector3(0, rb.linearVelocity.y, 0);
|
|
}
|
|
}
|
|
|
|
private void ClampHorizontalSpeed()
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
private void HandleJumpInput()
|
|
{
|
|
if (Input.GetButtonDown("Jump") && isGrounded)
|
|
{
|
|
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
|
|
}
|
|
}
|
|
|
|
// --- Логика Взаимодействия и Тегирования ---
|
|
|
|
private void OnCollisionEnter(Collision collision)
|
|
{
|
|
if (collision.gameObject.CompareTag("Trampoline"))
|
|
{
|
|
HandleTrampolineBounce(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);
|
|
}
|
|
} |