using System;
using UnityEngine;
using System.Collections;
using UnityEngine.AI;
using Random = UnityEngine.Random;
namespace BoatAttack
{
///
/// AIController is for non-human boats to control the engine of the boat
///
public class AiController : BaseController
{
[NonSerialized] public NavMeshPath NavPath;// navigation path
private Vector3[] _pathPoint;
private Vector3 _curWpPos;
private int _curPoint;
[NonSerialized] public int CurWp;
private bool _foundPath;
private int _pathPointNum;
private float _idleTime;
private Vector3 _tempFrom;//nav from position
private Vector3 _tempTo;//nav to position
private float _targetSide;//side of destination, positive on right side, negative on left side
private WaypointGroup.Waypoint[] _wPs;
private void Start ()
{
RaceManager.raceStarted += StartRace;
}
private void StartRace(bool start)
{
AssignWp(WaypointGroup.Instance.GetWaypoint(0));
InvokeRepeating(nameof(CalculatePath), 1f, 1f);
}
private void LateUpdate()
{
if(NavPath?.status == NavMeshPathStatus.PathInvalid)
CalculatePath();
if (_pathPoint != null &&_pathPoint.Length > _curPoint && _foundPath)
{
// If we are close to the current point on the path get the next
if (Vector3.Distance(transform.position, _pathPoint[_curPoint]) < 8)
{
_curPoint++; // Move on to next point
if (_curPoint >= _pathPoint.Length)
AssignWp(WaypointGroup.Instance.GetWaypoint(CurWp));
}
}
if(RaceManager.RaceStarted)
{
if (_idleTime > 3f) // if been idle for 3 seconds assume AI is stuck
{
Debug.Log($"AI boat {gameObject.name} was stuck, re-spawning.");
_idleTime = 0f;
controller.ResetPosition();
}
_idleTime = (engine.VelocityMag < 0.15f || transform.up.y < 0) ? _idleTime + Time.deltaTime : _idleTime = 0f;
}
}
// Update is called once per frame
private void FixedUpdate ()
{
if (_pathPoint == null || _pathPoint.Length <= _curPoint) return;
//\\\\\\\\Get angle to the destination and the side
var normDir = _pathPoint[_curPoint] - transform.position;
normDir = normDir.normalized;
var dot = Vector3.Dot(normDir, transform.forward);
_targetSide = Vector3.Cross(transform.forward, normDir).y;//positive on right side, negative on left side
engine.Turn(Mathf.Clamp(_targetSide, -1.0f, 1.0f));
engine.Accelerate(dot > 0 ? 1f : 0.25f);
}
private void AssignWp(WaypointGroup.Waypoint wp)
{
var offset = (Random.value * 2f - 1f) * wp.width * Vector3.left;
_curWpPos = wp.point + wp.rotation * offset;
CurWp = CurWp >= WaypointGroup.Instance.WPs.Count ? 0 : CurWp + 1;
CalculatePath();
}
///
/// Calculates a new path to the next waypoint
///
private void CalculatePath()
{
NavPath = new NavMeshPath(); // New nav path
NavMesh.CalculatePath(transform.position, _curWpPos, 255, NavPath);
if (NavPath.status == NavMeshPathStatus.PathComplete) // if the path is good(complete) use it
{
_pathPoint = NavPath.corners;
_curPoint = 1;
_foundPath = true;
}
else if(NavPath == null || NavPath.status == NavMeshPathStatus.PathInvalid) // if the path is bad, we haven't found a path
{
_foundPath = false;
}
}
// Draw some helper gizmos
private void OnDrawGizmosSelected()
{
var c = Color.green;
c.a = 0.5f;
Gizmos.color = c;
if (!_foundPath) return;
Gizmos.DrawLine(transform.position + (Vector3.up * 0.1f),
WaypointGroup.Instance.GetWaypoint(CurWp).point);
Gizmos.DrawSphere(_curWpPos, 1);
c = Color.red;
Gizmos.color = c;
if (_pathPoint[_curPoint] != Vector3.zero)
Gizmos.DrawLine(transform.position + (Vector3.up * 0.1f), _pathPoint[_curPoint]);
}
private void OnDrawGizmos()
{
var c = Color.yellow;
Gizmos.color = c;
for (var i = 0; i < _pathPoint.Length - 1; i++)
{
if (i == _pathPoint.Length - 1)
Gizmos.DrawLine(_pathPoint[_pathPoint.Length - 1], _pathPoint[i]);
else
Gizmos.DrawLine(_pathPoint[i], _pathPoint[i + 1]);
}
}
}
}