//========================================================================================= /// <summary> /// Updates the scores for all behaviours, and selects a new behaviour if neccessary. /// Also runs the currently selected behaviour. /// </summary> //========================================================================================= public void RunBehaviours() { // If there are no behaviours then abort: if ( m_behaviours.Count <= 0 ) return; // Add to the list of all the behaviours being processed: { // Get enumerator into behaviours dictionary: Dictionary<string,AIBehaviour>.Enumerator e = m_behaviours.GetEnumerator(); // Run through list: while ( e.MoveNext() ) { // Add this behaviour into list of behaviours to proccess: m_behaviours_to_process.Add( e.Current.Value ); } } // There should be a current behaviour at this point: #if WINDOWS_DEBUG if ( m_current_behaviour == null ) { throw new Exception( "AIBehaviourSet.RunBehaviours() - no current behaviour !!" ); } #endif // Process the list of behaviours, one by one: { // Save the behaviour with the highest score here: float highest_score = 0; AIBehaviour highest_score_behaviour = m_current_behaviour; // Get enumerator into list of behaviours to process: List<AIBehaviour>.Enumerator e = m_behaviours_to_process.GetEnumerator(); // Run through the list: while ( e.MoveNext() ) { // Get this behaviour: AIBehaviour behaviour = e.Current; // Get it's current score: float score = behaviour.ScoreBehaviour(); // Get the saved score for the behaviour: float last_score = m_behaviour_scores[behaviour.Name]; // Caculate it's new score: float new_score = ( last_score * m_behaviour_smooth ) + ( 1.0f - m_behaviour_smooth ) * score; // Save the new score: m_behaviour_scores[behaviour.Name] = new_score; // Ok, see if the new score is higher than the current behaviour: if ( new_score > highest_score ) { // New higher ranked behaviour: save it highest_score = new_score; highest_score_behaviour = behaviour; } } // Now see can we switch behaviours: if ( m_current_behaviour_time >= m_behaviour_hold_time ) { // Can switch behaviours: do it if ( highest_score_behaviour != m_current_behaviour ) { // Switch m_current_behaviour = highest_score_behaviour; // Reset time in current behaviour m_current_behaviour_time = 0; } } // Increase the time the current behaviour has been active for: m_current_behaviour_time += Core.Timing.ElapsedTime; // Finally.. peform the current behaviour action m_current_behaviour.PerformBehaviour(); // Clear the list of behaviours: m_behaviours_to_process.Clear(); } }
//========================================================================================= /// <summary> /// Performs the next most important behaviour from the given behaviour. Allows the most /// important behaviour to reliquinish total control and allows for combinations of /// behaviours. /// </summary> /// <param name="behaviour"> Behaviour to peform next most important behaviour for. </param> //========================================================================================= public void PerformNextMostImportantBehaviour( AIBehaviour behaviour ) { // If behaviour is null then don't bother: if ( behaviour == null ) return; // Make sure this behaviour exists in the map: if ( m_behaviour_scores.ContainsKey(behaviour.Name) ) { // Good get it's score: float behaviour_score = m_behaviour_scores[behaviour.Name]; // Store the next lowest score here: float next_lowest_score = float.NegativeInfinity; // Store the behaviour with the next lowest score here: AIBehaviour next_lowest_behaviour = null; // Try and find the next lowest score: Dictionary<string,float>.Enumerator e = m_behaviour_scores.GetEnumerator(); while ( e.MoveNext() ) { // Make sure this isn't the same behaviour as what we passed in: if ( e.Current.Key == behaviour.Name ) continue; // See if this score is lower or equal to the current behaviour and higher than the current lowest: if ( e.Current.Value >= next_lowest_score && e.Current.Value <= behaviour_score ) { // Better match for the next lowest score: save next_lowest_score = e.Current.Value; next_lowest_behaviour = m_behaviours[e.Current.Key]; } } // See if we found a next lowest scored behaviour: if ( next_lowest_behaviour != null ) { // Do the next lowest behaviour next_lowest_behaviour.PerformBehaviour(); } } }
//========================================================================================= /// <summary> /// Removes a behaviour from the behaviour set. /// </summary> /// <param name="behaviour_class_name"> Name of the behaviour to remove. </param> //========================================================================================= public void RemoveBehaviour( string behaviour_class_name ) { // See if this behaviour exists in the behaviour set: if ( m_behaviours.ContainsKey(behaviour_class_name) ) { // Good: now remove it from the behaviours m_behaviours.Remove(behaviour_class_name); m_behaviour_scores.Remove(behaviour_class_name); // If this behaviour is the current behaviour then pick another one: if ( m_current_behaviour.GetType().Name == behaviour_class_name ) { if ( m_behaviours.Count > 0 ) { // Get enumerator into behaviours: Dictionary<string,AIBehaviour>.Enumerator e = m_behaviours.GetEnumerator(); // Move onto next one: e.MoveNext(); // Set new current behaviour m_current_behaviour = e.Current.Value; } else { // No behaviours left: m_current_behaviour = null; } } } }
//========================================================================================= /// <summary> /// Adds a behaviour to the behaviour set. The behaviour must be a valid AIBehaviour class /// name and the name given is case sensitive. /// </summary> /// <param name="behaviour_class_name"> Name of the behaviour to add - E.G "AI_Rest"</param> /// <param name="importance"> /// How important the behaviour is. How much to scale behaviour scores by. /// </param> //========================================================================================= public void AddBehaviour( string behaviour_class_name , float importance ) { // Try and get the class type: try { // Try and get the type: Type behaviour_type = Type.GetType( "NinjaGame." + behaviour_class_name); // If it couldn't be found then throw an exception: if ( behaviour_type == null ) throw new ArgumentException("Invalid behaviour class name given"); // Get the root behaviour class Type root_behaviour_type = Type.GetType("NinjaGame.AIBehaviour"); // Make sure it is not abstract: if ( behaviour_type.IsAbstract ) throw new Exception("Behaviour class for AI cannot be abstract!"); // Make sure this is of type AIBehaviour if ( behaviour_type.IsSubclassOf(root_behaviour_type) == false ) { throw new Exception("AI Behaviour given is not of type 'AIBehaviour'"); } // Get the constructor for the object: ConstructorInfo constructor = behaviour_type.GetConstructor ( new Type[] { Type.GetType("System.Single") , Type.GetType("NinjaGame.Character") , Type.GetType("NinjaGame.AIBehaviourSet") } ); // Good: now create the object AIBehaviour behaviour = (AIBehaviour) constructor.Invoke( new object[]{ importance , m_character , this } ); // Add it to the list of behaviours: m_behaviours[behaviour_type.Name] = behaviour; // Set current behaviour score to zero: m_behaviour_scores[behaviour_type.Name] = 0; // If there is no current behaviour then make this the current behaviour if ( m_current_behaviour == null ) m_current_behaviour = behaviour; } #if WINDOWS_DEBUG catch ( Exception e ){ DebugConsole.PrintException(e); } #else catch ( Exception ){} #endif }