190 lines
6.9 KiB
C#
190 lines
6.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
public class AlliesMovement : MonoBehaviour
|
|
{
|
|
public GameObject m_ArrowPrefab = null;
|
|
public NavMeshAgent playerAgent;
|
|
public GameObject targetPosition;
|
|
public GameObject ExitPosition;// Just so AlliesManager doesn't need to track it
|
|
private Animator selfAnimator = null;
|
|
private ArcPrediction m_Predictor = null;
|
|
private float triggerRadius = 1f;
|
|
private bool previousAnimationStateWasAiming = false;
|
|
public float arrowForceMin = 0.3f;
|
|
public float arrowForceMax = 0.9f;
|
|
private Vector3 target;
|
|
private string ennemyChestName = "Spine_01";
|
|
private string selfHeadName = "Head";
|
|
public AudioSource m_bowShootingSound;
|
|
|
|
// Update is called once per frame
|
|
void FixedUpdate()
|
|
{
|
|
NavMeshSetup();
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
selfAnimator = GetComponent<Animator>();
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
m_Predictor = GetComponentInChildren<ArcPrediction>();
|
|
m_Predictor.HideArc();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
playerAgent.enabled = false;
|
|
}
|
|
|
|
private void NavMeshSetup()
|
|
{
|
|
if (!playerAgent.enabled)
|
|
{
|
|
playerAgent.enabled = true;
|
|
}
|
|
|
|
NavmeshAgentMovement();
|
|
}
|
|
|
|
void NavmeshAgentMovement()
|
|
{
|
|
if (NearTargetPosition())
|
|
{
|
|
TryShootEnemy();
|
|
}
|
|
else
|
|
{
|
|
selfAnimator.runtimeAnimatorController = Resources.Load("Animations/SlowRun/SlowRunController") as RuntimeAnimatorController;
|
|
playerAgent.SetDestination(targetPosition.transform.position);
|
|
}
|
|
}
|
|
|
|
void TryShootEnemy()
|
|
{
|
|
Enemy[] enemies = GameObject.FindObjectsOfType<Enemy>();
|
|
if (enemies.Length > 0)
|
|
{
|
|
Vector3 selfHead = GetChildWithName(transform, selfHeadName).position;
|
|
Enemy closestVisibleEnemy = null;
|
|
float enemyClosestDistence = 1000000000f;
|
|
foreach (Enemy enemy in enemies)
|
|
{
|
|
//Aim for the chest for higher odds of touching
|
|
Vector3 enemyChest = GetChildWithName(enemy.transform, ennemyChestName).position;
|
|
if (Vector3.Distance(enemyChest, selfHead) < enemyClosestDistence)
|
|
{
|
|
if (Physics.Linecast(selfHead, enemyChest, out RaycastHit hit))
|
|
{
|
|
if (hit.collider.transform.IsChildOf(enemy.transform))// Found a closer enemy that is visible that can be shot
|
|
{
|
|
closestVisibleEnemy = enemy;
|
|
enemyClosestDistence = Vector3.Distance(enemyChest, selfHead);
|
|
}
|
|
} else// Did not colide anything, including the enemy, so it should be fine to shoot?
|
|
{
|
|
closestVisibleEnemy = enemy;
|
|
enemyClosestDistence = Vector3.Distance(enemyChest, selfHead);
|
|
}
|
|
}
|
|
}
|
|
if (closestVisibleEnemy != null)
|
|
{
|
|
//Aim for the chest for higher odds of touching
|
|
Vector3 enemyChest = GetChildWithName(closestVisibleEnemy.transform, ennemyChestName).position;
|
|
transform.LookAt(enemyChest);
|
|
|
|
bool nextAnimationStateWasAiming = selfAnimator.GetCurrentAnimatorStateInfo(0).IsName("Aiming");
|
|
if(nextAnimationStateWasAiming != previousAnimationStateWasAiming){
|
|
target = enemyChest;
|
|
}
|
|
|
|
previousAnimationStateWasAiming = nextAnimationStateWasAiming;
|
|
if (selfAnimator.runtimeAnimatorController.name != "BowDrawController")
|
|
{
|
|
selfAnimator.runtimeAnimatorController = Resources.Load("Animations/BowDraw/BowDrawController") as RuntimeAnimatorController;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (selfAnimator.runtimeAnimatorController.name != "Idle")
|
|
{
|
|
selfAnimator.runtimeAnimatorController = Resources.Load("Animations/Idle/Idle") as RuntimeAnimatorController;
|
|
}
|
|
}
|
|
}else
|
|
{
|
|
if (selfAnimator.runtimeAnimatorController.name != "Idle")
|
|
{
|
|
selfAnimator.runtimeAnimatorController = Resources.Load("Animations/Idle/Idle") as RuntimeAnimatorController;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Transform GetChildWithName(Transform parent, string name)
|
|
{
|
|
if(parent.childCount > 0)
|
|
{
|
|
foreach (Transform child in parent)
|
|
{
|
|
if (child.name == name)
|
|
return child;
|
|
|
|
if (child.childCount > 0)
|
|
{
|
|
Transform subChild = GetChildWithName(child, name);
|
|
if (subChild != null)
|
|
{
|
|
return subChild;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
bool NearTargetPosition()
|
|
{
|
|
if (targetPosition != null)
|
|
{
|
|
return Vector3.Distance(targetPosition.transform.position, this.transform.position) < triggerRadius;
|
|
}
|
|
return true; // If no target is set, assume it's in position
|
|
}
|
|
|
|
// Called by an animation event
|
|
private void FireArrow()
|
|
{
|
|
// Arrow setup
|
|
Transform bowTransform = GetChildWithName(transform, "ModifiedAssetBowWithBlender");
|
|
GameObject arrowObject = Instantiate(m_ArrowPrefab, bowTransform.position, new Quaternion(0, 1f, -0.1f, 0.2f));
|
|
Arrow arrow = arrowObject.GetComponent<Arrow>();
|
|
Vector3 shootingDirection = new Vector3(target.x,bowTransform.position.y, target.z);
|
|
arrowObject.transform.LookAt(shootingDirection);
|
|
arrowObject.GetComponent<Rigidbody>().detectCollisions = false;
|
|
|
|
// Figuring out the required force
|
|
float arrowForce = arrowForceMin;
|
|
float flightTime = 1.4142135f*Mathf.Sqrt((target.y - bowTransform.position.y)/Physics.gravity.y);
|
|
float distanceX = target.x - bowTransform.position.x;
|
|
float distanceZ = target.z - bowTransform.position.z;
|
|
float targetSpeed = Mathf.Sqrt(distanceX*distanceX+distanceZ*distanceZ)/flightTime;
|
|
float neededPower = targetSpeed / arrow.m_MaxLaunchSpeedMeterPerSecond;
|
|
|
|
if(neededPower > arrowForceMin && neededPower < arrowForceMax){
|
|
arrowForce = neededPower;
|
|
} else if (neededPower > arrowForceMax){ // Likely gonna miss, but lmao nice try
|
|
arrowForce = arrowForceMax;
|
|
}
|
|
// Fire the arrow
|
|
m_Predictor.RenderArc(arrowForce * arrow.m_MaxLaunchSpeedMeterPerSecond, 20, arrowObject.transform.forward);
|
|
arrow.Fire(arrowForce, arrowObject.transform.forward, m_bowShootingSound);
|
|
}
|
|
}
|