public override void Tick() { deltaTime += Time.deltaTime; if (deltaTime >= 1f) { deltaTime = 0; if (parentBehaviour.attrsWriter.Data.CurrentFood + parentBehaviour.ScriptableAnimalStats.liveCost >= parentBehaviour.attrsWriter.Data.MaxFood) { // 吃饱了,不吃了,离开本状态 Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); return; } DinoBehaviour corpse = null; if (DinoBehaviour.AllAnimals.TryGetValue(Owner.Data.TargetEntityId.Id, out corpse)) { if (corpse.IsVanish) { Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } else { if (!corpse.Dead) { Debug.LogError("DinoEatState - Cannot eat live animals! Id:" + corpse._entityId + " state:" + corpse.stateMachine.CurrentState); } parentBehaviour.DoEat(corpse); } } else { Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } } }
// Use this for initialization void Start() { posInicialY = transform.position.y; Dino = GameObject.FindGameObjectWithTag("Player"); db = GameObject.FindGameObjectWithTag("Player").GetComponent <DinoBehaviour>(); rb = gameObject.GetComponent <Rigidbody2D>(); Attack(); }
public override void Tick() { int arrived = 0; if (parentBehaviour.navMeshAgent.remainingDistance < parentBehaviour.navMeshAgent.stoppingDistance) { arrived = 1; } float deltaTime = Time.time - Owner._startTime; if (deltaTime > parentBehaviour.ScriptableAnimalStats.stamina) { arrived = 2; if (parentBehaviour.logChanges) { Debug.Log("Time's up."); } } if (arrived > 0) { if (parentBehaviour.ScriptableAnimalStats.vegetarian) { if (Owner.Data.TargetEntityId.Id == 0) { Debug.LogError("Look For Food Error : TargetEntityId is ZERO!"); } Owner.TriggerTransition(DinoAiFSMState.StateEnum.EAT_FOOD, Owner.Data.TargetEntityId, Owner.Data.TargetPosition.ToUnityVector()); } else { DinoBehaviour corpse = null; if (DinoBehaviour.AllAnimals.TryGetValue(Owner.Data.TargetEntityId.Id, out corpse)) { if (corpse.Dead && !corpse.IsVanish) { if (!corpse.Dead) { Debug.LogError("DinoLookForFoodState - Cannot eat live animals! Id:" + corpse._entityId + " state:" + corpse.stateMachine.CurrentState); } Owner.TriggerTransition(DinoAiFSMState.StateEnum.EAT, Owner.Data.TargetEntityId, Owner.Data.TargetPosition.ToUnityVector()); } else { Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } } else { Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } } } }
public void DinoEnter(DinoBehaviour d) { if (!dinoNames.Contains(d.name)) { dinoNames.Add(d.name); int score = dinoNames.Count; Debug.Log("Score: " + score); } }
public void DinoExit(DinoBehaviour d) { if (dinoNames.Contains(d.name)) { dinoNames.Remove(d.name); int score = dinoNames.Count; Debug.Log("Score: " + score); } }
/// <summary> /// 寻找天敌 /// </summary> /// <returns></returns> private bool LookforPredator() { if (ScriptableAnimalStats.awareness <= 0) // 没有感知能力,不进入此逻辑 { return(false); } if (stateMachine.CurrentState == DinoAiFSMState.StateEnum.RUN_AWAY) // 如果已经处于本状态,则继续 { return(true); } float distMin = float.MaxValue; DinoBehaviour predator = null; foreach (var iter in allAnimals) { var animal = iter.Value; if (!animal.IsAlive || animal == this || animal.Species == Species || animal.ScriptableAnimalStats.dominance <= ScriptableAnimalStats.dominance || animal.ScriptableAnimalStats.stealthy) { continue; } float dist = Vector3.Distance(transform.position, animal.transform.position); if (dist > ScriptableAnimalStats.awareness) { continue; } if (dist < distMin) { distMin = dist; predator = animal; } } if (predator != null) { if (logChanges) { Debug.Log(string.Format("{0}: Found predator ({1}), running away.", gameObject.name, predator.gameObject.name)); } var targetPosition = RandomPointAwayFromDestination(predator.transform.position, 30f); if (!IfWithinMap(targetPosition)) { // 目标点无法走到,就随机一个点 targetPosition = RandomPoint(predator.transform.position, 30f); } // 这里不能给天敌的ID,因为WanderingState逻辑里,有对目标物体距离的判定,如果太近,就意味着到达了,状态会结束。 stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.RUN_AWAY, new EntityId(), targetPosition); return(true); } return(false); }
public void DoAttack(DinoBehaviour target) { var request = new AttackRequest() { Attacker = _entityId, Damage = attrsWriter.Data.Power }; cmdSender.SendAttackCommand(target._entityId, request, OnDoAttack); }
// Use this for initialization void Start() { Dino = GameObject.FindGameObjectWithTag("Player"); db = Dino.GetComponent <DinoBehaviour>(); rbDino = Dino.GetComponent <Rigidbody2D>(); jumpDino = Dino.GetComponent <DinoBehaviour>().jumpForce; velDinoMax = Dino.GetComponent <DinoBehaviour>().maxSpeed; velY = rbDino.velocity.y; accel = db.maxAccel; }
public void OnAttack(DinoAiData.Attack.ReceivedRequest request) { var payload = request.Payload; _curHealth = health.Data.CurrentHealth; _curHealth -= payload.Damage; if (logChanges) { Debug.Log(string.Format("{0}: Taking Damage {1} HP {2}!", gameObject.name, payload.Damage, _curHealth)); } // 生命减少 var update = new Health.Update { CurrentHealth = _curHealth }; health.SendUpdate(update); // 把生命减少的一半变成粮食储存起来,便于死后给食肉恐龙提供食物,否则如果食肉恐龙杀死一只饥饿(Food为零)的食草恐龙以后,什么都没得吃 _curFood = attrsWriter.Data.CurrentFood; float addFood = payload.Damage / 2; if (addFood + _curFood > attrsWriter.Data.MaxFood) { addFood = attrsWriter.Data.MaxFood - _curFood; } var update2 = new DinoAttrs.Update { CurrentFood = _curFood + addFood }; attrsWriter.SendUpdate(update2); // 如果血不够了,立即死亡。不用等到下一个AI周期了。 if (_curHealth <= 0) { if (IsAlive) { Die(); } } else {// 挨打的一方也进入战斗状态 DinoBehaviour attacker = null; if (allAnimals.TryGetValue(payload.Attacker.Id, out attacker)) { if (IsAlive && stateMachine.CurrentState != DinoAiFSMState.StateEnum.ATTACK) { stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.ATTACK, payload.Attacker, attacker.transform.position); } } } }
public void DinoEat(DinoBehaviour d) { // Detach camera gameObject.GetComponentInChildren <Camera>().transform.parent = null; Destroy(gameObject); Debug.Log("Eaten"); if (FindObjectsOfType <PlayerController> ().Length == 1) { // Last player left; end game Debug.Log("Game over"); } }
// Use this for initialization void Start() { Dino = FindObjectOfType <DinoBehaviour>().GetComponent <DinoBehaviour>(); compagTime = 0; compag = transform.position; if (Dino.facingRight) { Left = 0; } else { Left = 1; } }
public override void Tick() { // 时间到,不追了 float deltaTime = Time.time - Owner._startTime; if (deltaTime > parentBehaviour.ScriptableAnimalStats.stamina) { if (parentBehaviour.logChanges) { Debug.Log("Time's up."); } Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); return; } DinoBehaviour prey = null; if (DinoBehaviour.AllAnimals.TryGetValue(Owner.Data.TargetEntityId.Id, out prey)) { if (!prey.IsAlive) {// 敌人已经死亡 Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } else { float dist = Vector3.Distance(parentBehaviour.transform.position, prey.transform.position); if (dist < parentBehaviour.ScriptableAnimalStats.contingencyDistance) { Owner.TriggerTransition(DinoAiFSMState.StateEnum.ATTACK, Owner.Data.TargetEntityId, prey.transform.position); // 这里不让对方也进入“攻击状态”,为了保证线程安全,尽量只对自己的实例进行操作,对方挨打后自己设置攻击状态。 // 详见DinoBehaviour.cs里的OnAttack()函数 } else if (parentBehaviour.navMeshAgent.remainingDistance < parentBehaviour.navMeshAgent.stoppingDistance) {// 重新寻路,注意,这里直接重新寻路,而不是切换到休闲,然后再寻找猎物,主要是为了让霸王龙更加容易追到猎物 parentBehaviour.navMeshAgent.SetDestination(prey.transform.position); parentBehaviour.navMeshAgent.speed = parentBehaviour.ScriptableAnimalStats.runSpeed; parentBehaviour.stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.CHASE, prey._entityId, prey.transform.position); } } } else {// 敌人已经消失 Owner.TriggerTransition(DinoAiFSMState.StateEnum.IDLE, new EntityId(), DinoStateMachine.InvalidPosition); } }
public void DoEat(DinoBehaviour corpse) { var hungry = attrsWriter.Data.MaxFood - attrsWriter.Data.CurrentFood; var resNeed = ScriptableAnimalStats.appetite; if (hungry < ScriptableAnimalStats.appetite) { resNeed = hungry; } var request = new EatRequest() { Attacker = _entityId, ResNeed = resNeed }; if (!corpse.Dead) { Debug.LogError("DoEat - Cannot eat live animals! Id:" + corpse._entityId + " state:" + corpse.stateMachine.CurrentState); } cmdSender.SendEatCommand(corpse._entityId, request, OnDoEat); }
public DinoWanderState(DinoStateMachine owner, DinoBehaviour behaviour) : base(owner) { parentBehaviour = behaviour; }
public float _startTime; // 本状态开始的时间 public DinoStateMachine(DinoBehaviour behaviour) { _behaviour = behaviour; var idleState = new DinoIdleState(this, behaviour); var wanderState = new DinoWanderState(this, behaviour); var eatState = new DinoEatState(this, behaviour); var runawayState = new DinoRunAwayState(this, behaviour); var chaseState = new DinoChaseState(this, behaviour); var attackState = new DinoAttackState(this, behaviour); var deadState = new DinoDeadState(this, behaviour); var hatchState = new DinoHatchState(this, behaviour); var lookforfoodState = new DinoLookForFoodState(this, behaviour); var eatfoodState = new DinoEatFoodState(this, behaviour); var vanishState = new DinoVanishState(this, behaviour); var stateList = new Dictionary <DinoAiFSMState.StateEnum, IFsmState> { { DinoAiFSMState.StateEnum.IDLE, idleState }, { DinoAiFSMState.StateEnum.EAT, eatState }, { DinoAiFSMState.StateEnum.WANDER, wanderState }, { DinoAiFSMState.StateEnum.RUN_AWAY, runawayState }, { DinoAiFSMState.StateEnum.CHASE, chaseState }, { DinoAiFSMState.StateEnum.ATTACK, attackState }, { DinoAiFSMState.StateEnum.DEAD, deadState }, { DinoAiFSMState.StateEnum.HATCH, hatchState }, { DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, lookforfoodState }, { DinoAiFSMState.StateEnum.EAT_FOOD, eatfoodState }, { DinoAiFSMState.StateEnum.VANISH, vanishState }, }; SetStates(stateList); var allowedTransitions = new Dictionary <DinoAiFSMState.StateEnum, IList <DinoAiFSMState.StateEnum> >(); allowedTransitions.Add(DinoAiFSMState.StateEnum.IDLE, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.EAT, DinoAiFSMState.StateEnum.WANDER, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.CHASE, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.HATCH, DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, DinoAiFSMState.StateEnum.EAT_FOOD, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.WANDER, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.CHASE, DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.EAT, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.EAT_FOOD, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.EAT_FOOD, DinoAiFSMState.StateEnum.EAT, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.RUN_AWAY, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.CHASE, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.ATTACK, DinoAiFSMState.StateEnum.RUN_AWAY, DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, DinoAiFSMState.StateEnum.CHASE, // 唯一一个地方:可以切换为自己当前的状态 DinoAiFSMState.StateEnum.HATCH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.ATTACK, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.EAT, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.HATCH, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.DEAD, DinoAiFSMState.StateEnum.ATTACK, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.DEAD, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, DinoAiFSMState.StateEnum.VANISH, }); allowedTransitions.Add(DinoAiFSMState.StateEnum.VANISH, new List <DinoAiFSMState.StateEnum> { DinoAiFSMState.StateEnum.IDLE, }); SetTransitions(allowedTransitions); }
private bool LookforFood() { if (stateMachine.CurrentState == DinoAiFSMState.StateEnum.LOOK_FOR_FOOD) { return(true); } _curFood = attrsWriter.Data.CurrentFood; if (_curFood / attrsWriter.Data.MaxFood >= ScriptableAnimalStats.HungryRate) { // 不饿 return(false); } if (ScriptableAnimalStats.vegetarian) // 素食主义者,吃树 { List <TreeBehaviour> treeList = new List <TreeBehaviour>(); foreach (var iter in TreeBehaviour.AllTrees) { var tree = iter.Value; float dist = Vector3.Distance(transform.position, tree.transform.position); if (dist > ScriptableAnimalStats.scent) { continue; } if (!tree.IsHavestable()) { continue; } treeList.Add(tree); } // 收集范围内的所有目标,随机找一个作为最终目标 TreeBehaviour aTree = null; if (treeList.Count > 0) { int rand = Random.Range(0, treeList.Count); aTree = treeList[rand]; } if (aTree != null) { var targetPosition = aTree.transform.position; if (aTree._entityId.Id == 0) { Debug.LogError("Look For Food EntityId is ZERO!!!"); } stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, aTree._entityId, targetPosition); return(true); } } else // 肉食主义者,吃尸体 { List <DinoBehaviour> corpseList = new List <DinoBehaviour>(); foreach (var iter in allAnimals) { var animal = iter.Value; if (!(animal.Dead && !animal.IsVanish)) { continue; } float dist = Vector3.Distance(transform.position, animal.transform.position); if (dist > ScriptableAnimalStats.scent) { continue; } corpseList.Add(animal); } // 收集范围内的所有目标,随机找一个作为最终目标 DinoBehaviour corpse = null; if (corpseList.Count > 0) { int rand = Random.Range(0, corpseList.Count); corpse = corpseList[rand]; } if (corpse != null) { var targetPosition = corpse.transform.position; if (!corpse.Dead) { Debug.LogError("DinoBehaviour - Cannot eat live animals!"); } stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.LOOK_FOR_FOOD, corpse._entityId, targetPosition); return(true); } } return(false); }
public DinoRunAwayState(DinoStateMachine owner, DinoBehaviour behaviour) : base(owner) { parentBehaviour = behaviour; }
public DinoLookForFoodState(DinoStateMachine owner, DinoBehaviour behaviour) : base(owner) { parentBehaviour = behaviour; }
/// <summary> /// 寻找猎物 /// </summary> /// <returns></returns> private bool LookforPrey() { if (ScriptableAnimalStats.dominance <= 0) // 处于食物链的低端,不会寻找猎物 { return(false); } if (stateMachine.CurrentState == DinoAiFSMState.StateEnum.CHASE) // 已经处于本状态,继续 { return(true); } List <DinoBehaviour> preyList = new List <DinoBehaviour>(); foreach (var iter in allAnimals) { var animal = iter.Value; if (!animal.IsAlive || animal == this || animal.ScriptableAnimalStats.dominance > ScriptableAnimalStats.dominance || animal.ScriptableAnimalStats.stealthy) { continue; } if (animal.Species == Species && !ScriptableAnimalStats.territorial) { // 不可以攻击同类 continue; } if (animal.Species == Species && ScriptableAnimalStats.territorial && (animal.IsChild || IsChild)) { // 不可以攻击同类的孩子 continue; } if (animal.Species == Species && ScriptableAnimalStats.territorial && (animal.OwnerTokenId == OwnerTokenId)) { // 不可以攻击归属同一个玩家的恐龙 continue; } int p = System.Array.IndexOf(ScriptableAnimalStats.nonAgressiveTowards, animal.Species); if (p > -1) { continue; } // 如果太饿了,嗅觉会增加一倍的距离 float scent = ScriptableAnimalStats.scent; _curFood = attrsWriter.Data.CurrentFood; if (_curFood / attrsWriter.Data.MaxFood < ScriptableAnimalStats.HungryRate) { scent *= 2; } float dist = Vector3.Distance(transform.position, animal.transform.position); if (dist > scent) { continue; } if (Random.Range(0, 100) > ScriptableAnimalStats.agression) { continue; } preyList.Add(animal); } // 收集范围内的所有目标,随机找一个作为最终目标 DinoBehaviour prey = null; if (preyList.Count > 0) { int rand = Random.Range(0, preyList.Count); prey = preyList[rand]; } if (prey != null) { if (logChanges) { Debug.Log(string.Format("{0}: Found prey ({1}), chasing.", gameObject.name, prey.gameObject.name)); } stateMachine.TriggerTransition(DinoAiFSMState.StateEnum.CHASE, prey._entityId, prey.transform.position); return(true); } return(false); }