using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEditor;
using UnityEngine;
using static UnityEditor.PlayerSettings;
public class Trail
{
public Vector3 pos;
public Quaternion rot;
public Trail(Vector3 _pos, Quaternion _rot)
{
pos = _pos;
rot = _rot;
}
}
public class PlayerMovement : MonoBehaviour
{
[SerializeField]
[Range(0, 2)]
private float bodyDistance = 0.5f;
[SerializeField]
[Range(0.05f, 0.2f)]
private float speedFrequency = 0.1f;
[Range(0.05f, 0.2f)]
private float rotationSpeed = 0.1f;
private float interactionTime = 0.1f;
private float maxAngle = 135f;
private Transform tr;
private Vector2 inputDir;
private List<Transform> bodyPartsList;
//Se utiliza para ir guardando las posiciones a las que va cada parte del cuerpo
private Dictionary<int, List<Trail>> bodyPartsDic;
private float timeElapsed;
private bool newBodyAdded;
private bool canRotate;
private void Awake()
{
tr = transform;
bodyPartsDic = new Dictionary<int, List<Trail>>();
}
private void Update()
{
timeElapsed += Time.deltaTime;
if (timeElapsed >= interactionTime)
{
canRotate = true;
}
}
public void StartMovement()
{
MoveHead();
}
public void SetMoveDirection(Vector2 _inputDir)
{
inputDir = _inputDir;
}
public void UpdateBodyParts(List<Transform> _bodyParts)
{
int indexPart = _bodyParts.Count - 1;
int targetToFollow = _bodyParts.Count - 2;
bodyPartsDic.Add(indexPart, new List<Trail>());
bodyPartsList = _bodyParts;
if (indexPart > 0)
{
Trail r = new Trail(bodyPartsList[indexPart].position, bodyPartsList[indexPart].rotation);
bodyPartsDic[targetToFollow].Add(r);
newBodyAdded = true;
}
}
private void MoveHead()
{
tr.DOMove(tr.position + (tr.forward * bodyDistance), speedFrequency).SetEase(Ease.Linear).OnComplete(() =>
{
//si soy el único de la fila, no guardo mi posición
if (bodyPartsList.Count > 1)
{
Trail r = new Trail(tr.position, tr.rotation);
bodyPartsDic[0].Add(r);
}
if (newBodyAdded)
{
newBodyAdded = false;
MoveBody(bodyPartsList[^1]);
}
if (canRotate)
{
CheckRotation();
}
MoveHead();
});
}
private void CheckRotation()
{
Vector3 desiredDirection = new Vector3(Mathf.Round(inputDir.x), 0, Mathf.Round(inputDir.y));
if (desiredDirection != Vector3.zero)
{
float angle = Vector3.Angle(tr.forward, desiredDirection);
Quaternion desiredRot = Quaternion.identity;
if (angle <= maxAngle && angle != 0)
{
if (desiredDirection == Vector3.forward)
{
desiredRot = Quaternion.Euler(0, 0, 0);
}
else if (desiredDirection == Vector3.back)
{
desiredRot = Quaternion.Euler(0, 180, 0);
}
else if (desiredDirection == Vector3.right)
{
desiredRot = Quaternion.Euler(0, 90, 0);
}
else if (desiredDirection == Vector3.left)
{
desiredRot = Quaternion.Euler(0, -90, 0);
}
tr.rotation = desiredRot;
timeElapsed = 0;
canRotate = false;
}
}
}
private void MoveBody(Transform bodyPart)
{
int bodyIndex = bodyPartsList.IndexOf(bodyPart);
int targetToFollowIndex = bodyIndex - 1;
if (bodyPartsDic.ContainsKey(bodyIndex))
{
bodyPart.DOMove(bodyPartsDic[targetToFollowIndex][0].pos, speedFrequency).SetEase(Ease.Linear).
OnComplete(() => OnCompleteMoveBody(bodyPart, targetToFollowIndex));
}
}
private void OnCompleteMoveBody(Transform bodyPart, int targetToFollowIndex)
{
bodyPartsDic[targetToFollowIndex].RemoveAt(0);
//Si no soy el último de la fila, guardo mi posición
if (bodyPartsList[^1] != bodyPart)
{
Trail r = new Trail(bodyPart.position, bodyPart.rotation);
bodyPartsDic[targetToFollowIndex + 1].Add(r);
}
CheckBodyRotation(bodyPart, bodyPartsDic[targetToFollowIndex][0].rot);
MoveBody(bodyPart);
}
private void CheckBodyRotation(Transform bodyPart, Quaternion targetToFollow)
{
if (bodyPart.rotation != targetToFollow)
{
bodyPart.DORotateQuaternion(targetToFollow, rotationSpeed).SetDelay(speedFrequency * 0.5f);
}
}
}