Danro/Assets/Scripts/Entities/Props/Platforms/HidingTriggeringPlatform.cs
Danil Iarosh e7b983b52d level 1-3 finished, bug fixes etc
- закончил структуру уровня 1-3
- пофиксил баги с анимациями
- добавил новый тип платформ: скрывающиеся
- изменил логику платформ
2025-12-02 16:58:31 +03:00

237 lines
9.4 KiB
C#
Raw 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.Collections.Generic;
using System.Linq;
using UnityEngine;
using RR.Game2D.Core;
namespace RR.Game2D.Entities.Platforms
{
public class HidingTriggeringPlatform : MonoBehaviour
{
[Header("Настройки движения платформы")]
[SerializeField] private float moveSpeed = 3f;
[SerializeField] private float pathLength = 5f;
[SerializeField] private Direction2D moveDirection = Direction2D.Right;
[Header("Настройки матрицы объектов")]
[SerializeField] private int matrixWidth = 5;
[SerializeField] private int matrixHeight = 3;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
[Tooltip("Минимальный угол нормали контакта к вертикали для прикрепления (0.7 ≈ 45°)")]
[SerializeField, Range(0f, 1f)] private float normalThreshold = 0.7f;
private Vector3 _startPosition;
private Vector3 _endPosition;
private List<Transform> _platformChildren;
private readonly List<Transform> _hiddenChildren = new ();
private void Awake()
{
_startPosition = transform.position;
_endPosition = moveDirection switch
{
Direction2D.Down => _startPosition + Vector3.down * pathLength,
Direction2D.Left => _startPosition + Vector3.left * pathLength,
Direction2D.Right => _startPosition + Vector3.right * pathLength,
Direction2D.Up => _startPosition + Vector3.up * pathLength,
_ => _startPosition
};
// Собираем все дочерние объекты платформы
_platformChildren = new List<Transform>();
for (int i = 0; i < transform.childCount; i++)
{
_platformChildren.Add(transform.GetChild(i));
}
}
private void OnCollisionEnter2D(Collision2D other)
{
if (!attachPlayer) return;
if (!other.gameObject.CompareTag("Player")) return;
// Проверяем, что игрок стоит на верхней части платформы
if (IsPlayerOnTop(other))
{
other.transform.SetParent(transform);
}
}
private void OnCollisionExit2D(Collision2D other)
{
if (!attachPlayer) return;
if (!other.gameObject.CompareTag("Player")) return;
if (other.transform.parent == transform)
{
other.transform.SetParent(null);
}
}
/// <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);
}
public void Move()
{
StopAllCoroutines();
StartCoroutine(MovePlatformWithHiding(_endPosition, true));
}
public void MoveBack()
{
StopAllCoroutines();
StartCoroutine(MovePlatformWithHiding(_startPosition, false));
}
private IEnumerator MovePlatformWithHiding(Vector3 targetPosition, bool isMovingForward)
{
float distanceTraveled = 0f;
int lastUnitTraveled = 0;
Vector3 previousPosition = transform.position;
while (transform.position != targetPosition)
{
transform.position = Vector3.MoveTowards(
transform.position,
targetPosition,
Time.deltaTime * moveSpeed);
// Вычисляем пройденную дистанцию
distanceTraveled += Vector3.Distance(previousPosition, transform.position);
previousPosition = transform.position;
// Проверяем, прошли ли мы еще один юнит
int currentUnit = Mathf.FloorToInt(distanceTraveled);
if (currentUnit > lastUnitTraveled)
{
if (isMovingForward)
{
HideNextChild();
}
else
{
ShowNextChild();
}
lastUnitTraveled = currentUnit;
}
yield return null;
}
transform.position = targetPosition;
}
/// <summary>
/// Скрывает следующий крайний ряд или колонку в направлении движения
/// </summary>
private void HideNextChild()
{
// Находим видимые объекты
var visibleChildren = _platformChildren.Where(c => c.gameObject.activeSelf).ToList();
if (visibleChildren.Count == 0) return;
// Определяем, скрываем ряд или колонку в зависимости от направления
List<Transform> childrenToHide = moveDirection switch
{
Direction2D.Right => GetRightmostColumn(visibleChildren),
Direction2D.Left => GetLeftmostColumn(visibleChildren),
Direction2D.Up => GetTopmostRow(visibleChildren),
Direction2D.Down => GetBottommostRow(visibleChildren),
_ => new List<Transform>()
};
// Скрываем все объекты в ряду/колонке
foreach (var child in childrenToHide)
{
child.gameObject.SetActive(false);
_hiddenChildren.Add(child);
}
}
/// <summary>
/// Показывает следующий скрытый ряд или колонку (при движении назад)
/// </summary>
private void ShowNextChild()
{
if (_hiddenChildren.Count == 0) return;
// Определяем размер ряда/колонки в зависимости от направления
int countToShow = moveDirection is Direction2D.Right or Direction2D.Left
? matrixHeight
: matrixWidth;
// Показываем последние скрытые объекты (один ряд/колонку)
countToShow = Mathf.Min(countToShow, _hiddenChildren.Count);
for (int i = 0; i < countToShow; i++)
{
int lastIndex = _hiddenChildren.Count - 1;
Transform childToShow = _hiddenChildren[lastIndex];
childToShow.gameObject.SetActive(true);
_hiddenChildren.RemoveAt(lastIndex);
}
}
/// <summary>
/// Получает самую правую колонку объектов
/// </summary>
private static List<Transform> GetRightmostColumn(List<Transform> children)
{
if (children.Count == 0) return new List<Transform>();
// Находим максимальное X
float maxX = children.Max(c => c.position.x);
// Возвращаем все объекты с этим X (колонку)
return children.Where(c => Mathf.Approximately(c.position.x, maxX)).ToList();
}
/// <summary>
/// Получает самую левую колонку объектов
/// </summary>
private static List<Transform> GetLeftmostColumn(List<Transform> children)
{
if (children.Count == 0) return new List<Transform>();
float minX = children.Min(c => c.position.x);
return children.Where(c => Mathf.Approximately(c.position.x, minX)).ToList();
}
/// <summary>
/// Получает самый верхний ряд объектов
/// </summary>
private static List<Transform> GetTopmostRow(List<Transform> children)
{
if (children.Count == 0) return new List<Transform>();
float maxY = children.Max(c => c.position.y);
return children.Where(c => Mathf.Approximately(c.position.y, maxY)).ToList();
}
/// <summary>
/// Получает самый нижний ряд объектов
/// </summary>
private static List<Transform> GetBottommostRow(List<Transform> children)
{
if (children.Count == 0) return new List<Transform>();
float minY = children.Min(c => c.position.y);
return children.Where(c => Mathf.Approximately(c.position.y, minY)).ToList();
}
}
}