//========================================================================================= /// <summary> /// Scores the current behaviour and returns how relevant the AI thinks this action is /// </summary> /// <returns> A score for this current behaviour. </returns> //========================================================================================= public override float ScoreBehaviour() { // Get the AI sight module: AI_Sight b_sight = (AI_Sight) BehaviourSet.GetBehaviour("AI_Sight"); // If not there abort: if ( b_sight == null ) return 0; // If there is no player then abort: if ( b_sight.Player == null ) return 0; // Otherwise see if the player is currenly marked as visible to the ai: if ( b_sight.PlayerInSight ) { // Store the previous left and right scores here: float prev_score_left = m_score_left; float prev_score_right = m_score_right; // Player is in sight: see how high above the ai character the player/breacrumb is float player_y_relative = b_sight.PlayerBreadcrumb.Y - ControlCharacter.Position.Y; // If the player is not above enough then forget this behaviour: if ( player_y_relative > PLAYER_MIN_RELATIVE_Y ) { // Ok.. player is above. Cast two rays to the left and right of the AI to look for walls Core.Level.Collision.Intersect ( ControlCharacter.Position , ControlCharacter.Position - Vector2.UnitX * RAY_CAST_DISTANCE , null ); IntersectQueryResult intersect_l = Core.Level.Collision.GetClosestIntersect(); Core.Level.Collision.Intersect ( ControlCharacter.Position , ControlCharacter.Position + Vector2.UnitX * RAY_CAST_DISTANCE , null ); IntersectQueryResult intersect_r = Core.Level.Collision.GetClosestIntersect(); // See if there is a wall to the left: if ( intersect_l.ValidResult && intersect_l.Normal.Y <= WALL_MAX_NORMAL_Y && intersect_l.Normal.Y >= WALL_MIN_NORMAL_Y ) { // Wall to the left.. get our distance to the wall and the player/breacrumb distance float c_dist = Vector2.Dot( ControlCharacter.Position - intersect_l.Point , intersect_l.Normal ); float p_dist = Vector2.Dot( b_sight.PlayerBreadcrumb - intersect_l.Point , intersect_l.Normal ); // Make sure we are not behind that wall: if ( c_dist >= 0 ) { // Increase score by how close the player/breadcrumb is to that wall and how high up it is: m_score_left += ( RAY_CAST_DISTANCE - p_dist ) * player_y_relative * PLAYER_HEIGHT_IMPORTANCE; // Decrease the score by how far away we are from the wall m_score_left -= c_dist * AI_WALL_DISTANCE_IMPORTANCE; // Save this wall as the last left wall: m_last_left_wall = intersect_l; } else { // Not behind wall: set left score to zero m_score_left = 0; // No last left wall: m_last_left_wall.ValidResult = false; } } else { // No wall to the left: set left score to zero m_score_left = 0; // No last left wall: m_last_left_wall.ValidResult = false; } // See if there is a wall to the right: if ( intersect_r.ValidResult && intersect_r.Normal.Y <= WALL_MAX_NORMAL_Y && intersect_r.Normal.Y >= WALL_MIN_NORMAL_Y ) { // Wall to the left.. get our distance to the wall and the player/breadcrumb distance float c_dist = Vector2.Dot( ControlCharacter.Position - intersect_r.Point , intersect_r.Normal ); float p_dist = Vector2.Dot( b_sight.PlayerBreadcrumb - intersect_r.Point , intersect_r.Normal ); // Make sure we are behind that wall: if ( c_dist >= 0 ) { // Increase score to the right by how close we are to the wall and how high up the player/breadcrumb is m_score_right += ( RAY_CAST_DISTANCE - p_dist ) * player_y_relative * PLAYER_HEIGHT_IMPORTANCE; // Decrease the score by how far away we are from the wall m_score_right -= c_dist * AI_WALL_DISTANCE_IMPORTANCE; // Save this wall as the last right wall: m_last_right_wall = intersect_r; } else { // No wall to the right: set left score to zero m_score_right = 0; // No last right wall: m_last_right_wall.ValidResult = false; } } else { // No wall to the right: set right score to zero m_score_right = 0; // No last right wall: m_last_right_wall.ValidResult = false; } } else { // Player/breadcrumb is not above the ai. forget the behaviour m_score_right = 0; m_score_left = 0; // No last left and right walls: m_last_left_wall.ValidResult = false; m_last_right_wall.ValidResult = false; } // Interploate the current left and right scores with the previous m_score_left *= ( 1.0f - SCORE_SMOOTHING ); m_score_right *= ( 1.0f - SCORE_SMOOTHING ); m_score_left += prev_score_left * SCORE_SMOOTHING; m_score_right += prev_score_right * SCORE_SMOOTHING; // Return the largest wall run score: if ( m_score_left > m_score_right ) return m_score_left * Importance; else return m_score_right * Importance; } else { // Player is not in sight: this behaviour does not apply m_last_left_wall.ValidResult = false; m_last_right_wall.ValidResult = false; return 0; } }
//===================================================================================== /// <summary> /// Intersect query function. If an object is collideable it should also implement code to /// do a line / line intersection test here. It should return all of the intersections /// found. /// </summary> /// <param name="lineStart"> Start point of the line involved. </param> /// <param name="lineEnd"> End point of the line involved. </param> /// <param name="otherObject"> Object making the collision query, may be null. </param> /// <param name="results"> Array to save the results to. </param> /// <param name="results_index"> Index in the array to save the results to. </param> /// <returns> Number of results from the intersection test. </returns> //===================================================================================== public override int OnIntersectQuery( Vector2 lineStart , Vector2 lineEnd , GameObject otherObject , IntersectQueryResult[] results , int results_index ) { // Abort if no room to save new result: if ( results_index >= results.Length ) return 0; // Store the result here: Vector2 intersect_point = Vector2.Zero; // Do it: bool intersection = m_line.IntersectInfinite( new Line(lineStart,lineEnd) , ref intersect_point ); // See if there was an intersection: if ( intersection ) { // Make up the result: IntersectQueryResult result; result.ValidResult = true; result.QueryObject = this; result.Point = intersect_point; result.Normal = Vector2.UnitY; result.PointDistance = Vector2.Distance(lineStart,intersect_point); // Save the result: results[results_index] = result; // Got a result: return 1 return 1; } else { // No result: return 0; } }
//===================================================================================== /// <summary> /// Intersect query function. If an object is collideable it should also implement code to /// do a line / line intersection test here. It should return all of the intersections /// found. /// </summary> /// <param name="lineStart"> Start point of the line involved. </param> /// <param name="lineEnd"> End point of the line involved. </param> /// <param name="otherObject"> Object making the collision query, may be null. </param> /// <param name="results"> Array to save the results to. </param> /// <param name="results_index"> Index in the array to save the results to. </param> /// <returns> Number of results from the intersection test. </returns> //===================================================================================== public override int OnIntersectQuery( Vector2 lineStart , Vector2 lineEnd , GameObject otherObject , IntersectQueryResult[] results , int results_index ) { // Abort if there is no more room for results: if ( results_index >= results.Length ) return 0; // Check out the collision cache and see if the ellipse is within bounds of our lines: if ( LevelCollisionQuery.IntersectionCache.RayBoxTopLeft.X > m_lines_bb_bottom_right.X ) return 0; if ( LevelCollisionQuery.IntersectionCache.RayBoxBottomRight.X < m_lines_bb_top_left.X ) return 0; if ( LevelCollisionQuery.IntersectionCache.RayBoxTopLeft.Y < m_lines_bb_bottom_right.Y ) return 0; if ( LevelCollisionQuery.IntersectionCache.RayBoxBottomRight.Y > m_lines_bb_top_left.Y ) return 0; // Store the number of results here: int num_results = 0; // Make a new line to test with: Line line = new Line( lineStart , lineEnd ); // Collide the line with each of this object's lines: for ( int i = 0 ; i < m_collision_lines.Length ; i++ ) { // Store the collision point here: Vector2 intersection_point = Vector2.Zero; // Do the intersection: bool lines_intersect = m_collision_lines[i].Intersect( line , ref intersection_point ); // See if we got an intersection if ( lines_intersect ) { // Increment number of results: num_results++; // Get vector from line start to point of intersection Vector2 r = intersection_point - lineStart; // Get the distance to the point float intersection_distance = Vector2.Dot( r , line.Direction ); // Make up the result: IntersectQueryResult result; result.ValidResult = true; result.QueryObject = this; result.Point = intersection_point; result.Normal = m_collision_lines[i].Normal; result.PointDistance = intersection_distance; // Save the result: results[results_index] = result; // Increment results index: results_index++; // If past the end then return number of results: if ( results_index >= results.Length ) return num_results; } } // Return the number of collision results return num_results; }