You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
8.4 KiB
312 lines
8.4 KiB
//========= Copyright © 1996-2005, 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
|
|
|