the problem i'm having is actually understanding the mathmatics behind it, the diagrams presented don't make alot of sense to me(or arn't very well explained. particularly with how the lines are extruded to x distance, and how to choose a new target.) as well, the mathmatic's is quite heavy, and assumes that i can recognize all the mathmatical symbols/proofs, and interpret them correctly, which clearly i can not.
so, i found this video:
[media]
[/media]
it has a minor explanation of the approach which i used to base a bit more of how the process works, and allowed me to understand the cones of collision, but again, how selecting a new target is made i'm dumbfounded on.
so i finally decided to download the RVO2 source, and actually look at how they do it.
looking at calculateNewVelocitys in Agent.cpp, i'm looking over the neighbor agent code:
for (size_t i = 0; i < agentNeighbors_.size(); ++i) {
const Agent* const other = agentNeighbors_.second;
const Vector2 relativePosition = other->position_ - position_;
const Vector2 relativeVelocity = velocity_ - other->velocity_;
const float distSq = absSq(relativePosition);
const float combinedRadius = radius_ + other->radius_;
const float combinedRadiusSq = sqr(combinedRadius);
Line line;
Vector2 u;
if (distSq > combinedRadiusSq) {
/* No collision. */
const Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
/* Vector from cutoff center to relative velocity. */
const float wLengthSq = absSq(w);
const float dotProduct1 = w * relativePosition;
if (dotProduct1 < 0.0f && sqr(dotProduct1) > combinedRadiusSq * wLengthSq) {
/* Project on cut-off circle. */
const float wLength = std::sqrt(wLengthSq);
const Vector2 unitW = w / wLength;
line.direction = Vector2(unitW.y(), -unitW.x());
u = (combinedRadius * invTimeHorizon - wLength) * unitW;
} else {
/* Project on legs. */
const float leg = std::sqrt(distSq - combinedRadiusSq);
if (det(relativePosition, w) > 0.0f) {
/* Project on left leg. */
line.direction = Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
} else {
/* Project on right leg. */
line.direction = -Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
}
const float dotProduct2 = relativeVelocity * line.direction;
u = dotProduct2 * line.direction - relativeVelocity;
}
} else {
/* Collision. Project on cut-off circle of time timeStep. */
const float invTimeStep = 1.0f / sim_->timeStep_;
/* Vector from cutoff center to relative velocity. */
const Vector2 w = relativeVelocity - invTimeStep * relativePosition;
const float wLength = abs(w);
const Vector2 unitW = w / wLength;
line.direction = Vector2(unitW.y(), -unitW.x());
u = (combinedRadius * invTimeStep - wLength) * unitW;
}
line.point = velocity_ + 0.5f * u;
orcaLines_.push_back(line);
}
this is the code i've extrapolated in actionscript:
var ConeRadius:Number = (m_Radius + m_MoveSpeed * m); //Max 10 steps ahead
var ConeList:Array = new Array();
for (var v:Vehicle = VehicleList; v != null; v = v.m_Next) {
if (v == this) continue;
var xDis:Number = v.m_Vehicle.x - m_Vehicle.x;
var yDis:Number = v.m_Vehicle.y - m_Vehicle.y;
var Dis:Number = xDis * xDis + yDis * yDis;
if (Dis > ConeRadius * ConeRadius || Dis <= 0.001) continue;
var r:Number = v.m_Radius + m_Radius;
var r2:Number = r * r;
var ux:Number = 0.0;
var uy:Number = 0.0;
var dx:Number = 0.0;
var dy:Number = 0.0;
if (Dis > r2) {
//No collision
var xRelVel:Number = m_xVel - v.m_xVel;
var yRelVel:Number = m_yVel - v.m_yVel;
var xW:Number = xRelVel - xDis;
var yW:Number = yRelVel - yDis;
var WLength:Number = (xW * xW + yW * yW);
var dotProductA:Number = xW * xDis + yW * yDis;
if (dotProductA < 0.0 && dotProductA * dotProductA > r2 * WLength) {
var WSqrtLength:Number = Math.sqrt(WLength);
var uxW:Number = xW / WSqrtLength;
var uyW:Number = yW / WSqrtLength;
dx = uyW;
dy = -uxW;
ux = (r - WSqrtLength) * uxW;
uy = (r - WSqrtLength) * uyW;
trace("Direction: " + dx + " " + dy);
}else {
var Leg:Number = Math.sqrt(Dis - r);
if (xDis * yW - yDis * xW > 0.0) {
dx = (xDis * Leg - yDis * r)/Dis;
dy = (xDis * r + yDis * Leg)/Dis;
}else {
dx = -( xDis * Leg + yDis * r)/Dis;
dy = -(-xDis * r + yDis * Leg)/Dis;
}
//trace("Dir: "+dx+" "+dy);
var dotProductB:Number = xRelVel * dx + yRelVel * dy;
ux = dotProductB * dx - xRelVel;
uy = dotProductB * dy - yRelVel;
}
ConeList.push(m_xVel + 0.5 * ux, m_yVel + 0.5 * uy, dx, dy);
}else {
trace("Already Colliding, not bothering with at the moment");
}
}
I then draw all the lines, offset to the vehicles position, since from my understanding, the line/direction is relative to velocity, instead of to the agent.
anyway, i seem to run into this same branch regardless of what i do:
if (dotProductA < 0.0 && dotProductA * dotProductA > r2 * WLength) {
var WSqrtLength:Number = Math.sqrt(WLength);
var uxW:Number = xW / WSqrtLength;
var uyW:Number = yW / WSqrtLength;
dx = uyW;
dy = -uxW;
ux = (r - WSqrtLength) * uxW;
uy = (r - WSqrtLength) * uyW;
trace("Direction: " + dx + " " + dy);
}
the math seems to check out, but when i position my agents where going around the left leg would be shorter than the right, it seems to only want to navigate around the right leg at all costs....
so, hopefully this post isn't too overwhelming, and someone can point out any mistakes i might be making in trying to replicate the code into actionscript.