Danil Iarosh 4d05d1adbb
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
FEAT: Added new settings system
- Добавил новую систему настроек, возможности:
    - Динамически создает список настроек
    - Сохраняет настройки в JSON-файл
    - Возможность группировать настройки
    - Широкие возможности по кастомизации
    - Применение настроек в реальном времени (частично)
- Добавил префабы для новых элементов настроек
- Изменил поведение игры исходя из нового формата настроек
2026-02-04 14:32:15 +03:00

129 lines
5.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Linq;
using RR.Game2D.Core;
using UnityEngine;
namespace RR.Game2D.Entities.Platforms
{
public class ShiftingPlatform : MonoBehaviour
{
[Header("Настройки смещения платформы")]
[SerializeField] private Vector3 shiftAmount = new Vector3(0f, 2f, 0f);
[SerializeField] private float shiftDuration = 1f;
[SerializeField] private Direction2D shiftDirection = Direction2D.Down;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
[Tooltip("Минимальный угол нормали контакта к вертикали для прикрепления (0.7 ≈ 45°)")]
[SerializeField, Range(0f, 1f)] private float normalThreshold = 0.7f;
private Rigidbody2D _attachedPlayerRb;
private void FixedUpdate()
{
// Если игрок прикреплён к платформе, корректируем его velocity
if (!_attachedPlayerRb) return;
// Конвертируем мировую скорость игрока в локальную относительно платформы
Vector2 worldVelocity = _attachedPlayerRb.linearVelocity;
Vector2 localVelocity = transform.InverseTransformDirection(worldVelocity);
// Устанавливаем обратно, чтобы избежать конфликта с движением платформы
_attachedPlayerRb.linearVelocity = transform.TransformDirection(localVelocity);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
// Проверяем, что игрок стоит на верхней части платформы
if (attachPlayer && IsPlayerOnTop(other))
{
other.transform.SetParent(transform);
_attachedPlayerRb = other.rigidbody;
}
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.down * shiftAmount.y,
Direction2D.Left => Vector3.left * shiftAmount.x,
Direction2D.Right => Vector3.right * shiftAmount.x,
Direction2D.Up => Vector3.up * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
private void OnCollisionStay2D(Collision2D other)
{
if (!attachPlayer) return;
if (!other.gameObject.CompareTag("Player")) return;
// Если игрок уже прикреплён, но больше не на верхней части - отсоединяем
if (other.transform.parent == transform && !IsPlayerOnTop(other))
{
other.transform.SetParent(null);
_attachedPlayerRb = null;
}
// Если игрок не прикреплён, но теперь на верхней части - прикрепляем
else if (other.transform.parent != transform && IsPlayerOnTop(other))
{
other.transform.SetParent(transform);
_attachedPlayerRb = other.rigidbody;
}
}
private void OnCollisionExit2D(Collision2D other)
{
if (!other.gameObject.CompareTag("Player")) return;
if (attachPlayer && other.transform.parent == transform)
{
other.transform.SetParent(null);
_attachedPlayerRb = null;
}
Vector3 shiftVector = shiftDirection switch
{
Direction2D.Down => Vector3.up * shiftAmount.y,
Direction2D.Left => Vector3.right * shiftAmount.x,
Direction2D.Right => Vector3.left * shiftAmount.x,
Direction2D.Up => Vector3.down * shiftAmount.y,
_ => Vector3.zero
};
StopAllCoroutines();
StartCoroutine(ShiftPlatform(shiftVector));
}
/// <summary>
/// Проверяет, находится ли игрок на верхней части платформы
/// </summary>
/// <param name="collision">Данные о столкновении</param>
/// <returns>True, если игрок стоит сверху</returns>
private bool IsPlayerOnTop(Collision2D collision)
{
// Проверяем нормали всех контактных точек
// Нормаль направлена от другого объекта (игрока) к платформе,
// поэтому если игрок сверху, нормаль будет направлена вниз
return collision.contacts.Any(contact => Vector2.Dot(contact.normal, Vector2.down) > normalThreshold);
}
private IEnumerator ShiftPlatform(Vector3 shiftVector)
{
Vector3 initialPosition = transform.position;
Vector3 finalPosition = initialPosition + shiftVector;
float elapsedTime = 0f;
while (elapsedTime < shiftDuration)
{
transform.position = Vector3.Lerp(initialPosition, finalPosition, (elapsedTime / shiftDuration));
elapsedTime += Time.deltaTime;
yield return null;
}
transform.position = finalPosition;
}
}
}