I’m currently attempting to prototype a set of gameplay mechanics that centre around exploring a landscape. To this end, I’m experimenting with the Panda built-in physics system – PhysicsCollisionHandler, ActorNode, etc. For the most part it seems to be working well – better than my previous attempt, which involved a ray and three spheres, and which was both slower and less stable.
However, I’m finding that it seems to be all too easy for my object to penetrate my test landscape, both in my initial drop from a height and when running into terrain; when such a penetration occurs my object either ends up caught by its top sphere (it has two CollisionSpheres, one placed a little above the other) or simply passes through, to fall until I reset its position.
It looks as though CollisionHandlerFluidPusher would likely deal more robustly with such cases, but it also looks as though it likely doesn’t work with the physics system.
So, what might I do here? I could try Bullet, but I’d rather get this working under the built-in physics system if feasible.
For the similar problem I used ray or segment with CollisionHandlerQueue - for the ground check, and sphere with CollisionHandlerPusher - for the environment obstacles. This system works well for me. One thing - I made special collision geometry with bevels on the edges with angle <= 90 degrees to avoid some problems with pusher.
Hmm… That sounds much like what I had previously. In my case I had more than one sphere because I wanted to detect collisions near both the character’s “head” and “legs”; the third sphere was used to detect the character leaving the terrain (so that I could differentiate between the character being on the ground and being airborne), although it occurs to me now that I could just use the ray’s height above the terrain to determine this.
In my case this seemed slower than I’d prefer, especially given the rather small test terrain and presence of only a single character; removing the “ground detection sphere” might help that, and I might give it a shot again, but I’m not terribly hopeful that there will be a significant gain in speed…
Nevertheless, thank you for the suggestion.
I’m using panda’s collision system for a similar project, but I’m testing a collision sphere into collision polygons so my solution might not work in your case. I handle collisions using a CollisionHandlerQueue: when a collision is detected I determine how far the “from” object has penetrated into the “into” object and then correct its position by this depth so that the surface of the “from” object is just touching the surface of the “into” object when the next frame is rendered. In my case this prevents the collision sphere from ever sinking into the surface of the polygon and getting stuck there.
Here’s the gist of the code I use:
def handle_collision(self, obj):
# Get collision info.
entry = obj.col_handler.getEntry(0)
into_np = entry.getIntoNodePath()
from_np = entry.getFromNodePath()
# Calculate collision depth.
col_surface_pt = entry.getSurfacePoint(from_np)
col_interior_pt = entry.getInteriorPoint(from_np)
col_depth = col_surface_pt - col_interior_pt
# Correct position of object.
I just pieced this together from a larger algorithm so I doubt it would work as is, but maybe you could apply something like it to your problem.
As for performance - possible you used visible geometry for collisions. It’s not best choose. Collision geometry should be quite simple and it’s desirable to use octreefy octreefy optimize collisions
I am actually using spheres tested against polygons at the moment, I believe – it was my previous attempt that used a ray. What you suggest might well work – I’ll likely give it a shot and report back. Thank you!
Indeed, I’m well aware. However, my current test “terrain” is a rather small, static mesh, and I don’t think that I’m testing against visible geometry: I exported with the tag " polyset keep descend" and am testing against the resultant collision geometry, I believe.
All right, I’ve tied cslos77’s suggestion, and thus far it seems to work rather well! Thank you, cslos77 – and I’ll confess that I do feel silly for not having thought to try it before it was suggested.
My implementation is a little more complex than the version above: I’ve incorporated a friction, velocity reflection with a restitution component, detection of whether the player is “on the ground” or not and a factor that makes slopes more difficult to move up the steeper they are (and theoretically unclimbable if they are too steep).
I’m still working on allowing the player to stop on a slope without slipping down it.
Thank you both for your suggestions, ninth and cslos77!
Glad the idea helped, I also use friction, bounce, etc. One thing to mention is that this method won’t prevent objects from flying right through the polygon if they’re moving fast enough to avoid generating a collision; I believe this is where setFluidPos comes in but I haven’t got too far in experimenting with it.
To help with your sliding problem you could always try using a flag on the player (player.is_moving = False) that allows it to be skipped by whatever forces you’re using (i.e. gravity), but this would only work if you’re coding your own forces and not relying on built in physics.
Indeed; for now I’m simply not worrying about that: I don’t intend to have anything moving quite that fast, and the sorts of speed that I intend are likely to only produce such tunnelling in cases in which the frame-rate is nigh-unplayably low anyway.
I have tried that – I am indeed using my own forces – but I wasn’t terribly happy with the result, I believe. I’m currently experimenting with other methods, but have yet to achieve the results that I hope for.