using Saltyfish.Util;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Saltyfish.Logic
{
public class SnakeMovement : MonoBehaviour
{
[SerializeField]
private List<SnakePoint> m_SnakePath = new List<SnakePoint>();
[SerializeField]
private List<Unit> m_Bodies = new List<Unit>();
public List<Unit> Bodies => m_Bodies;
[SerializeField]
[Range(0.1f, 5)]
private float m_BodySpace;
public Unit Head => m_Bodies.SafeGet(0);
private bool m_Moved;
// Update is called once per frame
void Update()
{
OnUpdate();
}
protected virtual void OnUpdate()
{
UpdateBodies();
}
protected void UpdateMovement(Vector2 direction)
{
if (Head == null)
return;
Vector2 curPos = transform.position;
var nextPos = curPos + direction * Head.GetSpeed() * Time.deltaTime;
transform.position = new Vector3(nextPos.x, nextPos.y, transform.position.z);
// Optimization 1 : Only update path when moved
if(direction != Vector2.zero)
{
UpdatePath();
}
// Optimization 1
}
private void UpdatePath()
{
if (Head == null)
return;
var curPoint = new SnakePoint(Head.transform.position);
if (m_SnakePath.Count > 0)
{
var lastPoint = m_SnakePath[m_SnakePath.Count - 1];
curPoint.deltaDistance = Vector3.Distance(curPoint.Position, lastPoint.Position);
}
m_SnakePath.Add(curPoint);
}
private void UpdateBodies()
{
if (m_Bodies.Count <= 1)
return;
for (int i = 1; i < m_Bodies.Count; ++i)
{
if (m_Bodies[i].IsDead)
continue;
float remainDistance = Mathf.Clamp(m_BodySpace, 0.1f, 5) * i;
for (int j = m_SnakePath.Count - 1; j > 0; j--)
{
if (remainDistance <= m_SnakePath[j].deltaDistance)
{
float LerpProgress = 0;
if (m_SnakePath[i]m_SnakePath[j].deltaDistance > 0)
{
LerpProgress = remainDistance / m_SnakePath[j].deltaDistance;
}
m_Bodies[i].transform.position = Vector3.Lerp(
m_SnakePath[j].Position,
m_SnakePath[j - 1].Position,
LerpProgress);
// Optimization 2 : remove the points before the waypoint that last body has reached
if (i == m_Bodies.Count - 1)
{
m_SnakePath.RemoveRange(0, j - 1);
}
// Optimization 2
break;
}
remainDistance -= m_SnakePath[j].deltaDistance;
}
}
}
public void InitBodies(IList<Unit> units)
{
m_Bodies.Clear();
for (int i = 0; i < units.Count; i++)
{
m_Bodies.Add(units[i]);
}
}
public void PushBody(Unit unit)
{
if (m_Bodies.Contains(unit))
{
return;
}
m_Bodies.Add(unit);
}
public void InsertBody(Unit unit, int pos = 0)
{
if (pos < 0 || pos >= m_Bodies.Count)
return;
m_Bodies.Insert(pos, unit);
}
public Unit GetBody(int pos)
{
var unit = m_Bodies.SafeGet(pos);
return unit;
}
public bool RemoveBody(Unit unit)
{
return m_Bodies.Remove(unit);
}
public void RemoveAt(int pos)
{
m_Bodies.RemoveAt(pos);
}
private void OnGUI()
{
GUIStyle textStyle = new GUIStyle();
textStyle.fontSize = 35;
GUI.Label(new Rect(25, 25, 200, 100),"BodySpace", textStyle);
m_BodySpace = GUI.HorizontalSlider(new Rect(25, 100, 200, 80), m_BodySpace, 0.1F, 5);
}
}
}