AI - Steering behaviorsII (collision avoidance, following)

Collision avoidance, path following, captain following in the Steering Behaviors system

Collision Avoid

In the direction in which the object is moving, a vector extending a certain length is detected. It is equivalent to the collision of an object with a certain range in front to detect obstacles
Insert image description here
If the distance between the extended vector and the center of the collision object is less than the radius of the collision object, it is judged that there is an obstacle in the forward direction
Insert image description here
We will perform collision detection on all obstacles, but only the nearest one will be processed
Insert image description here

You can extend multiple vectors in the same direction with different lengths for detection to avoid getting too close to the object and causing the detection vector to exceed the collision object
Insert image description here
If the front view vector detects an obstacle, It will avoid. If there is an obstacle, subtract the detection vector from the center of the circle to get the direction of the avoidance force
Insert image description here
Note that this is the main difference from flee. The avoidance force is equivalent to detecting in advance whether there are obstacles in the direction of travel ahead, and then starting to avoid them in advance. The flee force uses its current position to determine whether it is a flee target point, and uses its own position to perform reverse escape calculations
A key point here is the vector of ahead. If the vector of ahead is a fixed length Yes, there is a problem that the object cannot stop in front of the obstacle. Because it is possible that the detection vector in this life has always been within the range of the obstacle. As shown below
Insert image description here
Therefore, the length of the ahead vector should be set by the ratio of the current speed and the maximum speed. If the current speed is close to 0, the length of the ahead vector is also close to 0

Vec2 MoveNode::collisionAvoid(float maxSpeed) {
    
    
    Vec2 avoidForce = Vec2::ZERO;
    float dynamicLen = _velocity.getLength() / maxSpeed;
    //Vec2 ahead = this->getPosition() + _velocity.getNormalized() * _aheadLen;
    Vec2 ahead = this->getPosition() + _velocity.getNormalized() * dynamicLen;
    Vec2 obstaclePos = findNearestObstacle(maxSpeed);
    if (obstaclePos != Vec2(-1, -1)) {
    
    
        avoidForce = ahead - obstaclePos;
        avoidForce.normalize();
        avoidForce *= _avoidForce;
    }
    return avoidForce;
}
//找到最具威胁的阻碍物,ahead为检测向量,与所有障碍物的圆心进行距离判定
Vec2 MoveNode::findNearestObstacle(float maxSpeed) {
    
    
    Vec2 pos = this->getPosition();
    /*Vec2 ahead = pos + _velocity.getNormalized() * _aheadLen;
    Vec2 ahead2 = pos + _velocity.getNormalized() * _aheadLen / 2;*/
    float dynamicLen = _velocity.getLength() / maxSpeed;
    Vec2 ahead = pos + _velocity.getNormalized() * dynamicLen;
    Vec2 ahead2 = pos + _velocity.getNormalized() * dynamicLen / 2;
    Vec2 v = Vec2(-1, -1);
    for (auto obstacle : _obstacles) {
    
    
        Vec2 center = obstacle.first;
        float radius = obstacle.second;
        bool isCollision = ahead.getDistance(center) < radius || ahead2.getDistance(center) < radius;
        if(isCollision && (v == Vec2(-1,-1) || pos.getDistance(center) < pos.getDistance(v))) v = center;
    }
    return v;
}

Effect
Insert image description here

Path Following

A relatively simple implementation is to divide the path into multiple path points and seek for each path point
Insert image description here
Because objects have similar inertia, so for each path point When seeking, you need to determine if you reach the current path point within a certain range of the path point, and then go to the next path point, otherwise it will loop infinitely at the initial point
Insert image description here
Note that if the arrival radius of the path point is too short, , the object may circle around the way point due to its too fast speed, and only then moves into the arrival range before heading to the next way point
Insert image description here

Insert image description here

//_pathDir表示了路径点索引的方向,我们这里是抵达起始点或终点后进行反向
Vec2 MoveNode::pathFollowing() {
    
    
    Vec2 steering = Vec2::ZERO;
    if (_pathNodes.empty()) return steering;
    auto pathNode = _pathNodes[_pathNodeIdx];
    Vec2 pos = pathNode.first;
    float arriveRadius = pathNode.second;
    if (this->getPosition().getDistance(pos) <= arriveRadius) {
    
    
        _pathNodeIdx += _pathDir;
        if (_pathNodeIdx >= _pathNodes.size() || _pathNodeIdx < 0) {
    
    
            _pathDir *= -1;
            _pathNodeIdx += _pathDir;
        }
    }
    return seek(_pathNodes[_pathNodeIdx].first);
}

Insert image description here

Leader Following

Follow the path of a captain
Captain following is similar to chasing the target, except that the pursuit target is to predict the direction of the target point a few frames forward and seek, but following is the opposite direction of the captain's forward direction. Follow to a certain distance
Insert image description here
As shown in the figure above, find the reverse direction of the captain's speed. Behind a certain length of position, the team member will arrive at the position behind

//_leaderBehindDist:跟随在队长背后的距离
Vec2 MoveNode::leaderFollowing() {
    
    
    Vec2 steering = Vec2::ZERO;
    if (_leader == nullptr) return steering;
    Vec2 tv = _leader->getVelocity() * -1;
    tv.normalize();
    tv *= _leaderBehindDist;
    Vec2 followPos = _leader->getPosition() + tv;

    steering += seek(followPos);
    return steering;
}

Insert image description here
We see that the team members are following behind the captain, but at this time the team members are all huddled together, so the separation force of the cluster simulation is added to the team members
Insert image description here
Another problem is that following The captain's team members are not allowed to block the captain's progress. At this time, we give the captain a forward sight detection vector and a detection radius. If the team member is within this sight detection range, the captain must evade
Insert image description here

//pos是队员的坐标位置,_leaderAhead是队长视线的检测的长度,与队长速度方向求的检测向量,_leaderAheadRadius是检测的范围半径。该函数判定队员位置是否在队长前进的方向上
bool MoveNode::isInAheadArea(Vec2 pos) {
    
    
    Vec2 srcPos = this->getPosition();
    Vec2 aheadPos = _velocity.getNormalized()* _leaderAhead + srcPos;
    return srcPos.getDistance(pos) < _leaderAheadRadius || aheadPos.getDistance(pos) < _leaderAheadRadius;
}

The logic of evade is similar to that of pursuit. It predicts the forward position of the captain a few frames later and flees the position.

Vec2 MoveNode::leaderFollowing() {
    
    
    Vec2 steering = Vec2::ZERO;
    if (_leader == nullptr) return steering;
    Vec2 tv = _leader->getVelocity() * -1;
    tv.normalize();
    tv *= _leaderBehindDist;
    Vec2 followPos = _leader->getPosition() + tv;
    
    //如果在队长视野前方,则预测队长行进路线进行逃离evade
    if (_leader->isInAheadArea(this->getPosition())) {
    
    
        Vec2 leadPos = _leader->getPosition();
        float t = this->getPosition().getDistance(leadPos) / _dtSpeed;
        Vec2 fleePos = leadPos + _leader->getVelocity() * t;
        steering += flee(fleePos);
    }
    steering += seek(followPos);
    return steering;
}

Insert image description here
The following is an example of a combination of the leader following the path and the team members following the leader.
Insert image description here

Guess you like

Origin blog.csdn.net/Mhypnos/article/details/134723823