1
0
Fork 0

Permit AI model to define basic submodel collision parameters.

AI models have rudimentary collision detection with submodels that performs two tests.

1. The height difference must be less than a defined amount
2. The centre point range must be less than a defined amount.

(2) above by itself would result in a spherical comparison; however (1) effectively modifies this to slice off the top and bottom of the sphere so that the sphere heigh is half of the value in (1).

Previously these heights and lengths were hardcoded - this change allows these to be defined in the xml instead using the <collision-length> and <collision-height> tags

e.g.
    <entry>
      <type>ship</type>
      <collision-length type="double">50</collision-length>
      <collision-height type="double">50</collision-height>
    </entry>

Default values:
+---------------+-------------+------------+
| Type          | Height(m)   |  Length(m) |
+---------------+-------------+------------+
| Null          |      0      |        0   |
| Aircraft      |     50      |      100   |
| Ship          |    100      |      200   |
| Carrier       |    250      |      750   |
| Ballistic     |      0      |        0   |
| Rocket        |    100      |       50   |
| Storm         |      0      |        0   |
| Thermal       |      0      |        0   |
| Static        |     50      |      200   |
| Wingman       |     50      |      100   |
| GroundVehicle |     20      |       40   |
| Escort        |    100      |      200   |
| Multiplayer   |     50      |      100   |
+---------------+-------------+------------+
This commit is contained in:
Richard Harrison 2022-11-21 21:59:30 +00:00
parent 95a274c135
commit bd4e7462ac
3 changed files with 72 additions and 10 deletions

View file

@ -273,6 +273,8 @@ void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
setLatitude(scFileNode->getDoubleValue("latitude", 0.0));
setBank(scFileNode->getDoubleValue("roll", 0.0));
setPitch(scFileNode->getDoubleValue("pitch", 0.0));
setCollisionHeight(scFileNode->getDoubleValue("collision-height", 0.0));
setCollisionLength(scFileNode->getDoubleValue("collision-length", 0.0));
SGPropertyNode* submodels = scFileNode->getChild("submodels");

View file

@ -138,6 +138,9 @@ public:
bool setParentNode();
void setParentName(const std::string& p);
void setCollisionLength(int range);
void setCollisionHeight(int height);
void calcRangeBearing(double lat, double lon, double lat2, double lon2,
double &range, double &bearing) const;
double calcRelBearingDeg(double bearing, double heading);
@ -167,6 +170,9 @@ public:
osg::LOD* getSceneBranch() const;
virtual int getCollisionHeight() const;
virtual int getCollisionLength() const;
/**
*
* @return true if at least one model (either low_res or high_res) is loaded
@ -190,6 +196,9 @@ protected:
double _max_speed = 300.0;
int collisionHeight = 0;
int collisionLength = 0;
std::string _path;
std::string _callsign;
std::string _submodel;
@ -488,6 +497,14 @@ inline void FGAIBase::setName(const std::string& n) {
_name = n;
}
inline void FGAIBase::setCollisionLength(int length){
collisionLength = length;
}
inline void FGAIBase::setCollisionHeight(int height){
collisionHeight = height;
}
inline void FGAIBase::setDie( bool die ) { delete_me = die; }
inline bool FGAIBase::getDie() { return delete_me; }
@ -525,3 +542,47 @@ inline void FGAIBase::setMaxSpeed(double m) {
_max_speed = m;
}
/*
* Default height and lengths for AI submodel collision detection.
* The difference in height is used first and then the range must be within
* the value specifed in the length field. This effective chops the top and
* bottom off the circle - but does not take into account the orientation of the
* AI model; so this algorithm is fast but fairly innaccurate.
*
* Default values:
* +---------------+-------------+------------+
* | Type | Height(m) | Length(m) |
* +---------------+-------------+------------+
* | Null | 0 | 0 |
* | Aircraft | 50 | 100 |
* | Ship | 100 | 200 |
* | Carrier | 250 | 750 |
* | Ballistic | 0 | 0 |
* | Rocket | 100 | 50 |
* | Storm | 0 | 0 |
* | Thermal | 0 | 0 |
* | Static | 50 | 200 |
* | Wingman | 50 | 100 |
* | GroundVehicle | 20 | 40 |
* | Escort | 100 | 200 |
* | Multiplayer | 50 | 100 |
* +---------------+-------------+------------+
*/
const static double tgt_ht[] = {0, 50, 100, 250, 0, 100, 0, 0, 50, 50, 20, 100, 50};
const static double tgt_length[] = {0, 100, 200, 750, 0, 50, 0, 0, 200, 100, 40, 200, 100};
inline int FGAIBase::getCollisionHeight() const
{
if (collisionHeight == 0)
return tgt_ht[static_cast<int>(_otype)];
return collisionHeight;
}
inline int FGAIBase::getCollisionLength() const
{
if (collisionLength == 0)
return tgt_length[static_cast<int>(_otype)];
return collisionLength;
}

View file

@ -708,9 +708,6 @@ FGAIManager::loadScenarioFile(const std::string& scenarioName, SGPath& outPath)
const FGAIBase *
FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range)
{
// we specify tgt extent (ft) according to the AIObject type
double tgt_ht[] = {0, 50, 100, 250, 0, 100, 0, 0, 50, 50, 20, 100, 50};
double tgt_length[] = {0, 100, 200, 750, 0, 50, 0, 0, 200, 100, 40, 200, 100};
ai_list_iterator ai_list_itr = ai_list.begin();
ai_list_iterator end = ai_list.end();
@ -718,11 +715,12 @@ FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range
SGVec3d cartPos(SGVec3d::fromGeod(pos));
while (ai_list_itr != end) {
double tgt_alt = (*ai_list_itr)->_getAltitude();
FGAIBase::object_type type = (*ai_list_itr)->getType();
tgt_ht[static_cast<int>(type)] += fuse_range;
FGAIBasePtr aiModel = *ai_list_itr;
FGAIBase::object_type type = aiModel->getType();
double tgt_alt = aiModel->_getAltitude();
int tgt_ht = aiModel->getCollisionHeight() + fuse_range;
if (fabs(tgt_alt - alt) > tgt_ht[static_cast<int>(type)] || type == FGAIBase::object_type::otBallistic
if (fabs(tgt_alt - alt) > tgt_ht || type == FGAIBase::object_type::otBallistic
|| type == FGAIBase::object_type::otStorm || type == FGAIBase::object_type::otThermal ) {
//SG_LOG(SG_AI, SG_DEBUG, "AIManager: skipping "
// << fabs(tgt_alt - alt)
@ -746,16 +744,17 @@ FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range
// << " alt " << tgt_alt
// );
tgt_length[static_cast<int>(type)] += fuse_range;
int tgt_length = aiModel->getCollisionLength() + fuse_range;
if (range < tgt_length[static_cast<int>(type)]){
if (range < tgt_length){
SG_LOG(SG_AI, SG_DEBUG, "AIManager: HIT! "
<< " (h:" << tgt_ht << ", w:" << tgt_length << ")"
<< " type " << static_cast<int>(type)
<< " ID " << id
<< " range " << range
<< " alt " << tgt_alt
);
return (*ai_list_itr).get();
return aiModel.get();
}
++ai_list_itr;
}