using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; [RequireComponent(typeof(NPC))] [RequireComponent(typeof(Enemy))] public class ThugNPCFollowing : MonoBehaviour { public const string ACTION_KEY = "ATTACKING"; private Rigidbody2D myRigidbody; public Animator anim; private Vector2 movement; public bool shouldRotate; public Vector3 dir; [Header("Following Logic")] public Vector3 homePosition; public Transform targetPosition; public AStarPathfindingAgent agent; public bool isDuringFollowing = false; // var is setted by trigger range //public GameObject player; [Header("Core Logic")] public bool approaching = false; public bool isAfterAction = false; public float chasingRadius = 6f; // radious where Npc start attacking ! ! ! [Header("Attacking Logic")] // TRASH - dupplicated from Following Enemy - move params to Enemy public float attackingRadius = 1.5f; // radious where Npc start attacking ! ! ! public bool hit = false; public bool firstAttack = false; public float timerDmg = 0f; public float waitTime = 1.0f; public float timerHit = 0f; public float hitWaitTime = 0.55f; public float expValue; public float thrust; public float knockTime; //public int isKilled; - movet do Enemy //isKilled = 0 - mob ALIVE //isKilled = 1 - mob DEAD public int isKilled2; public bool isPanelEnabled = true; void Awake() { agent = GetComponent(); homePosition = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, gameObject.transform.position.z); } // Start is called before the first frame update void Start() { targetPosition = GameObject.FindWithTag("Player").transform; //Copy from Eollwoing if (OnMapAppearanceMethod.IsNewGame()) { gameObject.GetComponent().isKilled = 0; } if (gameObject.GetComponent().health <= 0) gameObject.GetComponent().isKilled = 1; else // Else read saved value gameObject.GetComponent().isKilled = PlayerPrefs.GetInt(gameObject.GetComponent().enemyName + "-S"); if (gameObject.GetComponent().isKilled == 1) { gameObject.SetActive(false); gameObject.GetComponent().isKilled = 0; } myRigidbody = GetComponent(); anim = GetComponent(); } // Update is called once per frame public void Update() { // 0 Cofigure Animator if (Vector2.Distance(targetPosition.position, transform.position) <= chasingRadius) { dir = targetPosition.position - transform.position; float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg; dir.Normalize(); movement = dir; anim.SetBool("isRunning", movement != Vector2.zero); if (shouldRotate) { anim.SetFloat("Xinfo", dir.x); anim.SetFloat("Yinfo", dir.y); } } // 1. Check range and decide which action do // Following player detection if (IsInChassingRadious()) { // 2'nd state alow us to brak going to hom,e action to follow player again if (gameObject.GetComponent().State == NPCStateEnum.Pending || gameObject.GetComponent().State == NPCStateEnum.Walking) { approaching = true; gameObject.GetComponent().State = NPCStateEnum.Walking; } } else { // Turn around and go to home position if (approaching) { approaching = false; anim.SetBool("isRunning", true); gameObject.GetComponent().State = NPCStateEnum.Walking; } } // 2.Take action based on conditions around HandleState(); // 3. // COPIED FROM Following Enemy scripts // Taking hit logic timerHit += Time.deltaTime; if (hit == true) { if (timerHit >= hitWaitTime) { TakeDamage(PlayerPrefs.GetFloat("attackValue")); hit = false; timerHit = 0f; TakeKnockback(); } } // Detecting "is alive" logic if (gameObject.active == false) { gameObject.GetComponent().isKilled = 1; PlayerPrefs.SetInt(gameObject.GetComponent().enemyName, gameObject.GetComponent().isKilled); } } public void CheckDistance() { StopAllCoroutines(); // isDuringFollowing - avr is setted by trigger range if (approaching && !IsInActionRadious()) { agent.FindPath(); StartCoroutine(agent.FollowPath()); } else if (approaching) { // in this script we set attacking mode SetActionAfterMetConditions(); agent.path.Clear(); // if we are able to talgk we dont want go go further player } else if (!approaching) { if (Vector2.Distance(transform.position, homePosition) > 0.8f) // cont vale - path finding stop moving them before reachin position well.. { agent.point = homePosition; agent.FindPoint(); StartCoroutine(agent.FollowPath()); } else { anim.SetBool("isRunning", false); gameObject.GetComponent().State = NPCStateEnum.Pending; } } } #region Taking damage from Player detection public void OnTriggerEnter2D(Collider2D collision) { // Hit logic if (collision.gameObject.tag == "AttackHitbox" || collision.gameObject.tag == "PickaxeHitbox") { hit = true; } } public void OnTriggerExit2D(Collider2D other) { // Hit logic if (other.tag == "AttackHitbox" || other.tag == "PickaxeHitbox") { timerDmg = 0f; hit = false; } } #endregion public void HandleState() { switch (gameObject.GetComponent().State) { case NPCStateEnum.Walking: { CheckDistance(); break; } case NPCStateEnum.Talking: { TalkingAction(); break; } case NPCStateEnum.Pending: { break; } case NPCStateEnum.Attacking: { AttackingAction(); break; } default: { Debug.Log("Nieopisane zachowanie NPC ! ! !"); break; } } } public bool IsInChassingRadious() { if (Vector2.Distance(targetPosition.position, transform.position) >= chasingRadius) return false; return true; } public bool IsInActionRadious() { if (Vector2.Distance(targetPosition.position, transform.position) >= attackingRadius) return false; return true; } public void SetActionAfterMetConditions() { gameObject.GetComponent().State = NPCStateEnum.Attacking; } public void TalkingAction() { // Not required in this script } public void AttackingAction() { // if during Attacking mode player GO OUT of the attacking radious if(!IsInActionRadious()) { gameObject.GetComponent().State = NPCStateEnum.Walking; return; } // Attacking logic if (firstAttack == false) { if (timerDmg >= 0.15f) { firstAttack = true; GameObject.FindGameObjectWithTag("Player").GetComponent().TakeDamage( gameObject.GetComponent().baseAttack, isPanelEnabled ); timerDmg = 0f; } } if (timerDmg >= waitTime) { timerDmg = 0f; GameObject.FindGameObjectWithTag("Player").GetComponent().TakeDamage( gameObject.GetComponent().baseAttack, isPanelEnabled ); } timerDmg += Time.deltaTime; } #region dupplicated from Following :) public void TakeDamage(float damage) { Debug.Log("TakeDamage"); gameObject.GetComponent().health -= damage; if (gameObject.GetComponent().health <= 0) { gameObject.SetActive(false); gameObject.GetComponent().isKilled = 1; GameObject.FindGameObjectWithTag("Player").GetComponent().GetExp(expValue); // pass info about killing assigned enemy to mission manager listener // pass enemy name from script NOT object name (thats allow to have many different objects variantsa with this same aggregate key (private name - not preffab name) ) ConditionManager.Instance.UpdateKillCondition(gameObject.GetComponent().MinionName); } } public void TakeKnockback() { Rigidbody2D enemy = gameObject.GetComponent(); Rigidbody2D player = GameObject.FindGameObjectWithTag("Player").GetComponent(); if (enemy != null) { enemy.isKinematic = false; Vector2 difference = enemy.transform.position - player.transform.position; difference = difference.normalized * thrust; enemy.AddForce(difference, ForceMode2D.Impulse); //StartCoroutine(KnockCo(enemy)); } } #endregion public void AfterAction() { approaching = false; isAfterAction = true; //isDuringConversation = false; //PlayerPrefs.SetInt(gameObject.name + ".FirstDialogue", System.Convert.ToInt32(isAfterAction)); gameObject.GetComponent().State = NPCStateEnum.Walking; } }