/** * Forces a behaviour, interrupting the one being currently executed. */ public void SetBehaviour(int behaviorHash) { // Safely disable the current behaviour. if (currentBehaviour) { currentBehaviour.enabled = false; currentBehaviour.onExitState(); } try { // Start the new behaviour. currentBehaviour = behaviours[behaviorHash]; currentBehaviour.enabled = true; currentBehaviour.onEnterState(); } catch (KeyNotFoundException) { currentBehaviour = null; } }
private void UpdateParticipantsList() { participants.Clear(); participants.Add(Brain); GenericActorInteractionBehaviour[] behaviours; for (int i = 0; i < SensedThings.Count; i++) { //TODO would be more efficient to pull the behaviours from the target brain //TODO this is duplicated in StartBehaviour behaviours = SensedThings[i].GetComponentsInChildren <GenericActorInteractionBehaviour>(); if (behaviours.Length == 0) { continue; } //TODO Don't test if the currently active behaviour is the same. Instead have a "handshake" protocol in which both actors agree to participate in the same behaviour on the next frame. AbstractAIBehaviour behaviour = behaviours[0].Brain.ActiveBlockingBehaviour; if (behaviour != null && behaviour.DisplayName == this.DisplayName) { participants.Add(behaviours[0].Brain); } } }
/// <summary> /// Deegister a behaviour from the active list for this brain. Only registered behaviours will /// be evaluated for execution according to the brains decision making cycle. /// </summary> /// <param name="behaviour">The behaviour to deregister.</param> /// <returns>True if removed from the active list of behaviours.</returns> public bool DeregisterBehaviour(AbstractAIBehaviour behaviour) { return(m_AvailableBehaviours.Remove(behaviour)); }
/// <summary> /// Iterates over all the behaviours available to this actor and picks the most important one to be executed next. /// </summary> private void UpdateActiveBehaviour() { if (ActiveBlockingBehaviour != null && ActiveBlockingBehaviour.IsExecuting && !ActiveBlockingBehaviour.IsInteruptable) { return; } bool isInterupting = false; if (ActiveBlockingBehaviour != null && ActiveBlockingBehaviour.IsExecuting) { isInterupting = true; } StringBuilder log = new StringBuilder(); AbstractAIBehaviour candidateBehaviour = null; float highestWeight = float.MinValue; float currentWeight = 0; for (int i = 0; i < m_AvailableBehaviours.Count; i++) { log.Append("Considering: "); log.AppendLine(m_AvailableBehaviours[i].DisplayName); if (m_AvailableBehaviours[i].IsExecuting) { if (m_AvailableBehaviours[i].IsInteruptable) { log.AppendLine("Already executing but can interupt - checking requirements are still valid."); } else { log.AppendLine("Already executing and cannot interupt - no need to start it again though."); if (m_AvailableBehaviours[i].Weight(this) > highestWeight) { candidateBehaviour = m_AvailableBehaviours[i]; highestWeight = m_AvailableBehaviours[i].Weight(this); log.Append(m_AvailableBehaviours[i].DisplayName); log.Append(" has a weight of "); log.AppendLine(currentWeight.ToString()); } continue; } } if (m_AvailableBehaviours[i].IsAvailable) { log.AppendLine(m_AvailableBehaviours[i].reasoning.ToString()); currentWeight = m_AvailableBehaviours[i].Weight(this); log.Append(m_AvailableBehaviours[i].DisplayName); log.Append(" has a weight of "); log.AppendLine(currentWeight.ToString()); if (currentWeight > highestWeight) { candidateBehaviour = m_AvailableBehaviours[i]; highestWeight = currentWeight; } } log.AppendLine(m_AvailableBehaviours[i].reasoning.ToString()); } if (candidateBehaviour == null) { return; } if (isInterupting && candidateBehaviour != ActiveBlockingBehaviour) { ActiveBlockingBehaviour.FinishBehaviour(); } if (candidateBehaviour.IsBlocking) { ActiveBlockingBehaviour = candidateBehaviour; if (ActiveBlockingBehaviour is GenericInteractionAIBehaviour) { TargetInteractable = ((GenericInteractionAIBehaviour)ActiveBlockingBehaviour).CurrentInteractableTarget; if (TargetInteractable == null) { ActiveBlockingBehaviour = m_FallbackBehaviour; if (ActiveBlockingBehaviour != null) { ActiveBlockingBehaviour.StartBehaviour(ActiveBlockingBehaviour.MaximumExecutionTime); } } else { ActiveBlockingBehaviour.IsExecuting = true; // Don't start the behaviour since we need the interactable to trigger the start. } } else { TargetInteractable = null; ActiveBlockingBehaviour.StartBehaviour(ActiveBlockingBehaviour.MaximumExecutionTime); } } else { candidateBehaviour.EndTime = 0; candidateBehaviour.IsExecuting = true; candidateBehaviour.StartBehaviour(ActiveBlockingBehaviour.MaximumExecutionTime); ActiveNonBlockingBehaviours.Add(candidateBehaviour); } log.Insert(0, "\n"); // Note this section is inserted in reverse as we want it at the start of the string. if (TargetInteractable != null) { log.Insert(0, TargetInteractable.name); log.Insert(0, " at "); log.Insert(0, TargetInteractable.InteractionName); } else { if (ActiveBlockingBehaviour == candidateBehaviour) { log.Insert(0, candidateBehaviour.DisplayName); } else { log.Insert(0, candidateBehaviour.DisplayName); log.Insert(0, " look for a place to "); } } log.Insert(0, " decided to "); log.Insert(0, DisplayName); Log(log.ToString()); }
/// <summary> /// Register a behaviour as being active for this brain. All registered behaviours will /// be evaluated for execution according to the brains decision making cycle. /// </summary> /// <param name="behaviour">The behaviour to register.</param> public void RegisterBehaviour(AbstractAIBehaviour behaviour) { m_AvailableBehaviours.Add(behaviour); }