//轉身讓視野進行範圍的掃描,原地停留 protected virtual void Scan() { if (scanTimer == 0) { navAgent.destination = myTransform.position; scanTimer = Time.time; //決定這次scan的方向 switch (Random.Range(0, 2)) { case 0: scanAngle = RotationSpeed * -1; break; case 1: scanAngle = RotationSpeed; break; default: break; } } else if (Time.time - scanTimer > scanTimeStep) { //搜索結束 scanTimer = 0; } //轉身搜索 rotationAngle = scanAngle; //myTransform.Rotate(Vector3.up, scanAngle* UPDATE_INTERVAL); if (animationController != null) { animationController.PlayScan(); } state = NPCMotion.Deciding; }
//定點守備 protected virtual void Garrison() { if (garrisonTarget != null) { if (garrisonTarget.CompareTag(Tags.DeadBody)) { GarrisonTarget = null; state = NPCMotion.Deciding; } else { InGarrison = Vector3.ProjectOnPlane(myTransform.position - GarrisonTarget.position, Vector3.up).magnitude < garrisonRange; if ((myTransform.position - garrisonTarget.position).magnitude < navAgent.stoppingDistance && navAgent.remainingDistance == 0) { state = NPCMotion.Idle; } else { mainTarget = garrisonTarget; state = NPCMotion.Move; } } } else { state = NPCMotion.Deciding; } }
//待命 protected virtual void Idle() { if (animationController != null) { animationController.PlayIdle(); } navAgent.destination = myTransform.position; //else //{ if (!IsGarrison && mainTarget == null && !isGuardPlayer) { //索敵 float seed = Random.Range(0, CHANCE_TO_SEARCH_WIS_RATIO); //機率進入索敵狀態 if (Time.time - _searchTimer > SearchTime + .1f && seed < status.GetPrimaryAttrubute(PrimaryAttributeName.Wisdom).AdjustedValue) { _searchTimer = 0; state = NPCMotion.Search; } else { state = NPCMotion.Deciding; } } else { state = NPCMotion.Deciding; } //} }
protected virtual void onTriggerExit(Collider other) { if (_targetsInVision.Contains(other.transform)) { _targetsInVision.Remove(other.transform); CheckTarget(); state = NPCMotion.Deciding; } //} }
protected virtual void onTriggerEnter(Collider other) { if (other.GetComponent <Damagable>() != null) { _targetsInVision.Add(other.transform); CheckTarget(); //_targetInVision = other.transform; state = NPCMotion.Deciding; } }
//護衛目標附近徘徊,太遠會回來,無護位目標則遊蕩 protected virtual void Search() { if (npc.IsCasting) { state = NPCMotion.Casting; return; } if (_searchTimer == 0) { if (guardTarget != null && Vector3.ProjectOnPlane((myTransform.position - guardTarget.position), Vector3.up).magnitude > PatrolMaxDistance) { //Debug.Log(SearchCenterPosition); float angle = Vector3.Angle( Vector3.ProjectOnPlane(myTransform.forward, Vector3.up), Vector3.ProjectOnPlane(guardTarget.position - myTransform.position, Vector3.up)) * (Vector3.Dot(myTransform.right, guardTarget.position - myTransform.position) > 0 ? 1 : -1); myTransform.Rotate(Vector3.up, angle); //rotationAngle = angle; } else { //隨機轉身 myTransform.Rotate(Vector3.up, Random.Range(0, 360)); //rotationAngle = Random.Range(0, 360); } searchTo = myTransform.position + myTransform.forward * MoveSpeed * SearchTime; _searchTimer = Time.time; } else { if (Time.time - _searchTimer > SearchTime) { //索敵結束,重新判斷 state = NPCMotion.Deciding; searchTo = null; } else { //索敵時間中往該方向前進 state = NPCMotion.Search; } } if (searchTo != null) { navAgent.destination = (Vector3)searchTo; if (animationController != null) { animationController.PlayWalk(); } } }
//施法中,原地停留 protected virtual void Casting() { if (npc.IsCasting) { navAgent.destination = transform.position; state = NPCMotion.Casting; if (animationController != null) { animationController.PlayCast(); } } else { state = NPCMotion.Deciding; } }
//網主要目標移動 protected virtual void Move() { if (npc.IsCasting) { state = NPCMotion.Casting; return; } //Debug.Log(GetComponent<NPCController>().IsAttacking +" || "+ GetComponent<NPCController>().IsSkilling); if (npc.IsAttacking || npc.IsSkilling) { state = NPCMotion.Deciding; return; } navAgent.destination = mainTarget.position - mainTarget.forward * -1 * MinDistance; if (animationController != null) { animationController.PlayRun(); } state = NPCMotion.Deciding; }
protected virtual void Awake() { myTransform = transform; state = NPCMotion.Idle; isAlive = true; _targetsInVision = new List <Transform>(); CommandTargets = new List <Transform>(); //NPCType = Type; _searchTimer = 0; controller = GetComponent <CharacterController>(); GameObject visionObject = new GameObject("Vision"); visionObject.transform.parent = myTransform; visionObject.transform.position = myTransform.position; VisionCollision visionCollision = visionObject.AddComponent <VisionCollision>(); visionCollision.onTriggerEnter += onTriggerEnter; visionCollision.onTriggerExit += onTriggerExit; vision = visionObject.AddComponent <SphereCollider>(); vision.center = controller.center; vision.isTrigger = true; }
//轉向主要目標,決定是否靠近 protected virtual void Follow() { if (npc.IsCasting) { state = NPCMotion.Casting; return; } //有跟隨對象 if (mainTarget) { //轉往目標方向 //float angle = RotationSpeed * (Vector3.Dot(myTransform.right, mainTarget.position - myTransform.position) > 0 ? 1 : -1); float angle = Vector3.Angle(myTransform.forward, Vector3.ProjectOnPlane(mainTarget.position - myTransform.position, myTransform.up)) * (Vector3.Dot(myTransform.right, mainTarget.position - myTransform.position) > 0 ? 1 : -1); rotationAngle = angle; //myTransform.Rotate(Vector3.up, angle); //目標體寬 var targetWidth = mainTarget.GetComponentInParent <Build>() != null?mainTarget.GetComponent <MeshFilter>().mesh.bounds.size.x *mainTarget.transform.localScale.x : mainTarget.GetComponent <CharacterController>().radius; //是否已經進入視當的距離 if (Vector3.Distance(mainTarget.position, myTransform.position) < MinDistance + targetWidth) { //已經進入視當的距離,停下來 navAgent.destination = myTransform.position; //Debug.Log("Stop"); state = NPCMotion.Idle; } else { //沒進入視當的距離,繼續移動 state = NPCMotion.Move; } } else { //無跟隨對象,待機 state = NPCMotion.Deciding; } }
//決策 protected virtual void Deciding() { if (npc.IsCasting) { state = NPCMotion.Casting; } else { CheckTarget(); npc.attackTarget = null; //有目標 if (mainTarget != null) { if (IsGarrison && Vector3.ProjectOnPlane(mainTarget.position - GarrisonTarget.position, Vector3.up).magnitude > garrisonRange) { state = NPCMotion.Garrison; } else { if (guardTarget != null) { //攻擊目標超出護位目標時往護位目標移動,追擊1.5被距離 if (Vector3.ProjectOnPlane( (mainTarget.position - guardTarget.position), Vector3.up).magnitude > (isGuardPlayer ? PatrolCharMaxDistance : PatrolMaxDistance) * 1.5F) { mainTarget = guardTarget; state = NPCMotion.Move; return; } } bool mainTargetOutOfRange = false; if (mainTarget.GetComponentInParent <Build>() == null) { //距離外的人 mainTargetOutOfRange = !_targetsInVision.Contains(mainTarget); } bool mainTargetOutOfVision = Mathf.Abs(Vector3.Angle( //視野外 Vector3.ProjectOnPlane( mainTarget.position - myTransform.position, myTransform.up), myTransform.forward)) > VisionWidth && (mainTarget.position - myTransform.position).magnitude >= MinDistance * 2; if (mainTargetOutOfRange) { //超出距離,靠過去 state = NPCMotion.Fallow; } else { //距離內 if (mainTargetOutOfVision) { //視線外,尋找 state = NPCMotion.Scan; } else { //視線內,跟上 state = NPCMotion.Fallow; npc.attackTarget = mainTarget; } } } } else { if (IsGarrison) { state = NPCMotion.Garrison; } else { //沒有主要目標 //有護衛目標時 if (guardTarget != null) { //超出護位目標時往護位目標移動 if (Vector3.ProjectOnPlane((myTransform.position - guardTarget.position), Vector3.up).magnitude > (isGuardPlayer? PatrolCharMaxDistance: PatrolMaxDistance)) { mainTarget = guardTarget; state = NPCMotion.Move; } else { //靠近護位目標時護位待命 state = NPCMotion.Idle; } } else { //無護位目標時待命 if (npc.commander != null) { //npc.commander.CommandFollowerInvade(npc); if (npc.commander is Tower) { npc.Patrol((npc.commander as Tower).MainFlag); } else if (npc.commander is Player) { npc.Patrol((npc.commander as Player).myTransform); } state = NPCMotion.Deciding; } else { state = NPCMotion.Idle; } } } } } }