|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: "Force-field" obstacle avoidance & steering
//
// @Note (toml 06-18-02): Currently only controls direction. Ultimately could
// also incorporate body facing (yaw), speed, and translational/rotational
// acceleration.
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_MOVESOLVER_H
#define AI_MOVESOLVER_H
#if defined( _WIN32 )
#pragma once
#endif
#include "utlvector.h"
#include "ai_obstacle_type.h"
//-----------------------------------------------------------------------------
inline float NormalizeAngle( float angle ) { if ( angle < 0.0 ) angle += 360.0; else if ( angle >= 360.0 ) angle -= 360.0; return angle; }
//-----------------------------------------------------------------------------
// ENUMERATIONS
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// STRUCTURES
//-----------------------------------------------------------------------------
//-------------------------------------
// AI_Arc_t
//
// Purpose: Represents an arc.
//
//-------------------------------------
struct AI_Arc_t { AI_Arc_t() : center( 0 ), span( 0 ) { }
// Set by center and span
void Set( float newCenter, float newSpan );
// Set by the right and left extremes (coordinates run counter clockwise)
void SetByLimits( float yawRight, float yawLeft );
// Center of the arc (as "yaw")
float center;
// Span of the arc (in degrees)
float span; };
//-------------------------------------
// AI_MoveSuggestion_t
//
// Purpose: Suggests a possible move/avoidance, with a range of acceptable alternatives
//
// @Note (toml 06-20-02): this probably will eventually want to incorporate facing and
// destination of the motivating goal.
//
//-------------------------------------
enum AI_MoveSuggestionFlags_t { AIMS_FAVOR_LEFT = 0x01, AIMS_FAVOR_RIGHT = 0x02 };
//-----------------
struct AI_MoveSuggestion_t { AI_MoveSuggestion_t(); AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity = NULL ); AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity = NULL );
void Set( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity = NULL ); void Set( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity = NULL );
//---------------------------------
// The kind of suggestion
AI_MoveSuggType_t type;
// The unadjusted weight of the suggestion [0..1], although [-1..1] within the solver
float weight;
// The desired direction to move/avoid
AI_Arc_t arc;
// The causing entity, if any
EHANDLE hObstacleEntity; // Flags
unsigned flags;
};
//-----------------
typedef CUtlVector<AI_MoveSuggestion_t> CAI_MoveSuggestions;
//-------------------------------------
// AI_MoveSolution_t
//
// Purpose: The result of resolving suggestions
//
// @Note (toml 06-18-02): Currently, this is a very dopey little structure.
// However, it will probably eventually incorporate much of the info
// passed or calculated piecemeal between Move...() and Move...Execute()
// functions. Once suggestions incorprate more information, the solution
// may want to include a copy of the winning suggestion, so that the
// caller need retain less state. If this is not the case, reduce it to just
// a yaw.
//
//-------------------------------------
struct AI_MoveSolution_t { AI_MoveSolution_t() : dir(0) { }
// The direction to move
float dir; };
//-----------------------------------------------------------------------------
// class CAI_MoveSolver
//
// Purpose: Given a set of precalculated "regulations" (typically negative),
// and a set of instantaneous suggestions (usually positive)
//-----------------------------------------------------------------------------
class CAI_MoveSolver { public: CAI_MoveSolver();
//---------------------------------
// Purpose: A regulation is a suggestion that is kept around as a rule until
// cleared. They are generally negative suggestions.
//---------------------------------
void AddRegulation( const AI_MoveSuggestion_t &suggestion ); void AddRegulations( const AI_MoveSuggestion_t *pSuggestion, int nSuggestions );
bool HaveRegulations() const; void ClearRegulations();
//---------------------------------
// Purpose: Solve the move, picking the best direction from a set of suggestions,
// after applying the regulations
//---------------------------------
bool Solve( const AI_MoveSuggestion_t *pSuggestions, int nSuggestions, AI_MoveSolution_t *pResult ); bool Solve( const AI_MoveSuggestion_t &suggestion, AI_MoveSolution_t *pResult );
//---------------------------------
bool HaveRegulationForObstacle( CBaseEntity *pEntity);
//---------------------------------
// Visualization
void VisualizeRegulations( const Vector& origin );
private: enum { REGS_RESERVE = 8, };
//---------------------------------
void NormalizeSuggestions( AI_MoveSuggestion_t *pBegin, AI_MoveSuggestion_t *pEnd );
//---------------------------------
CAI_MoveSuggestions m_Regulations; };
//-----------------------------------------------------------------------------
// AI_Arc_t inline methods
//-----------------------------------------------------------------------------
inline void AI_Arc_t::Set( float newCenter, float newSpan ) { center = NormalizeAngle( newCenter ); span = NormalizeAngle( newSpan ); }
//-------------------------------------
inline void AI_Arc_t::SetByLimits( float yawRight, float yawLeft ) { // Yaw runs counter-clockwise
span = yawLeft - yawRight;
if ( span < 0 ) span += 360;
center = yawRight + span * 0.5;
if ( center >= 360 ) center -= 360; }
//-----------------------------------------------------------------------------
// AI_MoveSuggestion_t inline methods
//-----------------------------------------------------------------------------
inline void AI_MoveSuggestion_t::Set( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity ) { type = newType; weight = newWeight; hObstacleEntity = pEntity; flags = 0;
arc.Set( newDir, newSpan ); }
//-------------------------------------
inline AI_MoveSuggestion_t::AI_MoveSuggestion_t() : type( AIMS_INVALID ), weight( 0 ), flags( 0 ) { }
//-------------------------------------
inline AI_MoveSuggestion_t::AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, float newDir, float newSpan, CBaseEntity *pEntity ) { Set( newType, newWeight, newDir, newSpan, pEntity ); }
//-------------------------------------
inline AI_MoveSuggestion_t::AI_MoveSuggestion_t( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity ) { Set( newType, newWeight, arc.center, arc.span, pEntity ); }
//-------------------------------------
inline void AI_MoveSuggestion_t::Set( AI_MoveSuggType_t newType, float newWeight, const AI_Arc_t &arc, CBaseEntity *pEntity ) { Set( newType, newWeight, arc.center, arc.span, pEntity ); }
//-----------------------------------------------------------------------------
// CAI_MoveSolver inline methods
//-----------------------------------------------------------------------------
inline CAI_MoveSolver::CAI_MoveSolver() { m_Regulations.EnsureCapacity( REGS_RESERVE ); }
//-------------------------------------
inline void CAI_MoveSolver::AddRegulation( const AI_MoveSuggestion_t &suggestion ) { m_Regulations.AddToTail( suggestion ); }
//-------------------------------------
inline void CAI_MoveSolver::AddRegulations( const AI_MoveSuggestion_t *pSuggestions, int nSuggestions ) { for (int i = 0; i < nSuggestions; ++i) { m_Regulations.AddToTail( pSuggestions[i] ); } }
//-------------------------------------
inline bool CAI_MoveSolver::HaveRegulations() const { return (m_Regulations.Count() > 0); }
//-------------------------------------
inline void CAI_MoveSolver::ClearRegulations() { m_Regulations.RemoveAll(); }
//-------------------------------------
inline bool CAI_MoveSolver::Solve( const AI_MoveSuggestion_t &suggestion, AI_MoveSolution_t *pResult) { return Solve( &suggestion, 1, pResult); }
//=============================================================================
#endif // AI_MOVESOLVER_H
|