/// <summary> /// get closest npc /// </summary> /// <returns>returns closest npc</returns> private NPCScript _getClosest() { NPCScript cur = null; float curDist = float.MaxValue; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.isDead) { continue; } if (npc.npcState != NPCScript.NPCState.Chase) { float dist = Vector3.Distance(m_Player.transform.position, npc.transform.position); if (dist < curDist) { curDist = dist; cur = npc; } } } } return(cur); }
void _createNPCScript() { NPCScript npcscript = character.GetComponent <NPCScript>(); if (!npcscript) { npcscript = Undo.AddComponent <NPCScript>(character); } npcscript.blockOdds = 10; npcscript.attackInterval = 1.0f; Transform sweepCapsule = Utils.FindChildTransformByName(character.transform, "AttackSweepCapsule"); Rigidbody sweepBody = null; if (!sweepCapsule) { Debug.Log("Creating attack sweep capsule"); sweepBody = Resources.Load <Rigidbody>("AttackSweepCapsule"); sweepBody = Instantiate(sweepBody); sweepBody.transform.SetParent(npcscript.transform); sweepBody.transform.localPosition = new Vector3(0.0f, 1.276f, 0.0f); sweepBody.name = "AttackSweepCapsule"; } if (!sweepBody) { Debug.LogError("Cannot find Rigidbody on 'AttackSweepCapsule'" + " < " + character.ToString() + ">"); return; } npcscript.attackSweepBody = sweepBody; }
/// <summary> /// add all npcs that are in range and under angle from direction to the list. /// </summary> /// <param name="range">range condition</param> /// <param name="angle">angle condition</param> /// <param name="position">test position</param> /// <param name="direction">test direction</param> /// <param name="npcList">list on which to add</param> public void CollectNpcsInRangeAngle(float range, float angle, Vector3 position, Vector3 direction, List <IGameCharacter> npcList) { npcList.Clear(); for (int i = 0; i < m_Npcs.Length; i++) { NPCScript npc = m_Npcs[i]; if (npc.isDead) { continue; } if (npc.ragdollState != RagdollManager.RagdollState.Animated) { continue; } Vector3 dir2npc = npc.transform.position - position; float dist = Vector3.Distance(position, npc.transform.position); if (dist <= range) { float cur_angle = Vector3.Angle(direction, dir2npc.normalized); if (cur_angle <= angle) { npcList.Add(npc); } } } }
/// <summary> /// Unity Start method /// Start is called on the frame when a script is enabled just before any of the Update methods is called the first time /// </summary> void Start() { // check if guard zone is assigned on all for (int i = 0; i < npc_list.Count; i++) { NPCScript npc = npc_list[i]; npc.guardZone = this; } }
/// <summary> /// add local avoidance around npcs and player /// </summary> /// <param name="move">ref current move velocity</param> private void _add_local_avoidance(ref Vector3 move) { float repulseDistance = avoidanceDistance; Vector3 toPlayer = transform.position - m_Player.transform.position; Vector3 dir2player = toPlayer.normalized; float dist2player = toPlayer.magnitude; // avoidance of npcs float power = 8; Vector3 force = Vector3.zero; for (int i = 0; i < m_NPCManager.npcs.Length; i++) { NPCScript npc = m_NPCManager.npcs[i]; if (this == npc) { continue; } if (npc.ragdollState != RagdollManager.RagdollState.Animated) { continue; } Vector3 toNpc = transform.position - npc.transform.position; Vector3 dir2npc = toNpc.normalized; float dist2npc = toNpc.magnitude; float val = Mathf.Clamp01(repulseDistance / dist2npc); val = Mathf.Pow(val, power); float strength = Mathf.Lerp(0.0f, 1.0f, val); force += dir2npc * strength; } // avoidance of player if (dist2player < 0.45f) { float val = Mathf.Clamp01(repulseDistance / dist2player); val = Mathf.Pow(val, power); float strength = Mathf.Lerp(0.0f, 1.0f, val) * 4f; force += dir2player * strength; } move += force; #if SMOOTH_MOVEMENT avgMove[avgIdx] = move; avgIdx++; if (avgIdx >= avgMove.Length) { avgIdx = 0; } #endif }
/// <summary> /// provides info is any npc in combat /// </summary> /// <param name="caller">pass caller so it can be skipped</param> /// <returns>true or false</returns> public bool AnyNpcInCombat(NPCScript caller) { for (int i = 0; i < npcs.Length; i++) { NPCScript npc = npcs[i]; if (npc == caller) { continue; } if (npc.inCombat) { return(true); } } return(false); }
/// <summary> /// npc chase state /// </summary> private void chase() { NUM_CHASERS_GLOBAL = 0; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { zone.npc_list[i].npcState = NPCScript.NPCState.Return; } zone.numChasers = 0; for (int i = zone.numChasers; i < zone.allowedAttackers; i++) { NPCScript npc = _getClosest(); if (npc) { if (npc.isDead) { continue; } npc.startChase(); zone.numChasers++; NUM_CHASERS_GLOBAL++; } } for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc) { if (npc.isDead) { continue; } if (npc.npcState != NPCScript.NPCState.Chase) { npc.npcState = NPCScript.NPCState.Wait; } } } } }
/// <summary> /// number of npcs in range in current zone/s /// </summary> /// <returns></returns> public int NumInRangeInZone() { if (m_CurrentZones.Count == 0) { return(0); } int num = 0; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.inAttackRange) { num++; } } } return(num); }
/// <summary> /// provides info of number of npcs in combat in current zone /// </summary> /// <returns>true or false</returns> public int NumNpcInCombatInZone() { if (m_CurrentZones.Count == 0) { return(0); } int count = 0; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.inCombat) { count++; } } } return(count); }
/// <summary> /// return number of attacker in current zone /// </summary> /// <returns></returns> public int NumNpcAttackingInZone() { if (m_CurrentZones.Count == 0) { return(0); } int count = 0; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.animator.GetCurrentAnimatorStateInfo(0).IsName("AttackCombo")) { count++; } } } return(count); }
/// <summary> /// number of npcs chasing in current zone/s /// </summary> /// <returns></returns> public int NumChasingInZone() { if (m_CurrentZones.Count == 0) { return(0); } int num = 0; foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.npcState == NPCScript.NPCState.Chase) { num++; } } } return(num); }
/// <summary> /// provides info is any npc is attacking in current zone /// </summary> /// <param name="caller">pass caller so it can be skipped</param> /// <returns>true or false</returns> public bool AnyNpcAttackingInZone(NPCScript caller) { if (m_CurrentZones.Count == 0) { return(false); } foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc == caller) { continue; } if (npc.animator.GetCurrentAnimatorStateInfo(0).IsName("AttackCombo")) { return(true); } } } return(false); }
/// <summary> /// in current zone/s add all npcs that are in range and under angle of transform.forward to the list. /// </summary> /// <param name="range">range condition</param> /// <param name="angle">angle condition</param> /// <param name="xform">transform ( position/ forward )</param> /// <param name="npcList">list on which to add</param> public void CollectNpcsInRangeAngleInZone(float range, float angle, Transform xform, List <NPCScript> npcList) { npcList.Clear(); if (m_CurrentZones.Count == 0) { return; } foreach (NPCGuardZone zone in m_NpcZones) { if (zone.playerInZone) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc.isDead) { continue; } if (npc.ragdollState != RagdollManager.RagdollState.Animated) { continue; } Vector3 dir2npc = npc.transform.position - xform.position; float dist = Vector3.Distance(xform.position, npc.transform.position); if (dist < range) { float cur_angle = Vector3.Angle(xform.forward, dir2npc.normalized); if (cur_angle <= angle) { npcList.Add(npc); } } } } } }
/// <summary> /// provides info is any npc in combat in current zone /// </summary> /// <param name="caller">pass caller so it can be skipped</param> /// <returns>true or false</returns> public bool AnyNpcInCombatInZone(NPCScript caller) { if (m_CurrentZones.Count == 0) { return(false); } foreach (NPCGuardZone zone in m_CurrentZones) { for (int i = 0; i < zone.npc_list.Count; i++) { NPCScript npc = zone.npc_list[i]; if (npc == caller) { continue; } if (npc.inCombat) { return(true); } } } return(false); }
/// <summary> /// Unity OnTriggerStay method /// OnTriggerStay is called once per frame for every Collider other that is touching the trigger /// </summary> /// <param name="col">collider staying in the trigger</param> void OnTriggerStay(Collider col) { if (m_CollectingNPCs) { if (col.tag == "NPC") { NPCScript npc = col.GetComponent <NPCScript>(); if (npc) { if (!npc_list.Contains(npc)) { npc.guardZone = this; npc_list.Add(npc); } } } } // if player is inside, flag as true if (col.gameObject.tag == "Player") { m_PlayerInZone = true; } }