I thought I’d put this question out on the forums for a while before I decide on an approach.
The question is about my steering behaviours code.
My moving characters use a CollisionTube to detect upcoming collisions, like so:
Perhaps it’s a little hard to see, but the CollisionTube is placed around the character and extends out ahead of the character. The tube increases and decreases in length with the character’s velocity. So if the character is moving toward an obstacle (like the CollisionSphere in the screenshot) the tube will collide with the sphere before the character does. The character then uses the point and normal information from this collision to safely steer away from or around the sphere. You can see it in action if you download the code from the link above. It is modelled on this obstacle avoidance steering demo.
Panda’s CollisionTube is so perfect for this task that I don’t want to give it up. But there is a problem: in Panda, the CollisionTube can only be used as an “into” object in the collision system. This means that tubes can only collide with “from” objects: spheres, rays, lines and segments.
I have my characters running around on an island which is square in shape. I need to put some kind of collision wall around the borders of the island, so that the characters will steer to remain on the island in the same way that they steer to avoid obstacles represented by CollisionSpheres. Four CollisionPlanes or CollisionPolygons could represent this wall very well, but they cannot act as “from” objects in Panda so they don’t work. Panda seems to detect the tube-plane collision but is not able to construct the point and normal for the collision and prints out an error instead.
So how to keep the characters on the island? I’ve considered three possibilities so far:
- Place a lot of CollisionSpheres around the borders of the island to approximate a wall, like buoys. Since tubes can collide with spheres, the characters will be able to steer away from this wall. A wall made of spheres would look something like this:
This has the advantage of being quick and easy to do. The disadvantage is that it would use a very large number of spheres and might be very inefficient.
- Replace the characters CollisionTube with a wall of spheres (as above) approximating a CollisionTube. It could vary in length by adding or removing spheres. This sphere-tube would be able to collide with spheres, inverse spheres, tubes, polygons, planes, any “into” object in the panda collision system, as the sphere-tube itself would be a collection of “from” objects.
This seems like it might be worth doing as it affords a lot more freedom to represent obstacles for collision avoidance – you can now use tubes, planes and polygons as obstacles. But it would take some work from me to make a sphere-tube class, and I already feel like I’m running behind. Also I think it’d be a little awkward, especially compared to the perfect fit of the CollisionSphere.
A problem with both of these solutions is that a wall or tube constructed out of spheres is only approximately the right shape. As you can see from the image there are little bumps where one sphere goes in and the next goes out. I’m worried that this might cause erratic steering.
- Don’t use Panda’s collision system for keeping characters on the island at all, but instead fake it. To steer away from an obstacle a character needs a point on the surface of the obstacle where a predicted collision will occur and a surface normal on the obstacle at this point.
If the obstacle is a plane then the surface normal is the same everywhere.
So I could write a task that each frame looks for characters that are within a certain range of the edge of the island. If one is found, the task projects the characters forward direction onto the plane representing the island boundary to get a point of collision which is combined with the surface normal of the plane and passed to the character, the character steers away from the boundary exactly like it would steer to avoid any other obstacle.
Assuming projecting the forward direction to get the point on the plane would be easy (I don’t actually know how to do it, but think it should be simple, just computing a line-plane intersection) this approach might work nicely.
Edit: An alternative way to do this one would be to add a CollisionSegment to each character as well as the CollisionTube, and point it out ahead of the character like the tube. The segment can be used as a from object only to detect collisions with CollisionPlanes marking the boundaries of the island as into objects. The original CollisionTube can be used for colliding with spherical obstacles.
So, any comments or advice on the problem and/or the suggested solutions? Any better solutions?
Thanks in advance
P.S. I tried forcing my island to be circular in shape, so I could wrap an inverse sphere around it. But it turns out that tubes cannot collide with inverse spheres either: inverse spheres can be used as from objects only. I got the same error message from Panda as I got when I tried to use a Plane or a Tube as a from object:
P.P.S. I suppose a fourth solution would be to use CollisionSegments (or lines, or rays) to make walls surrounding the island. Several lines at different heights not too far apart ought to catch any character approaching the wall.
P.P.P.S. Lines don’t work very well either. They catch the collisions, but the wall they make is too thin. If the character doesn’t steer sharp enough (and they don’t) then as soon as the tube is on the other side of the line it is no longer in collision and the character passes through the wall. A plane that divides the space so that everything behind the plane is in collision is needed (or better steering).