Hi. I’m working on pixel-perfect platformer. For a long time I was very happy with just using move_and_slide() for prototyping but I finally got to the point in which I need much more control. So I started implementing my own collision response behavior using ShapeCast2D. So far it’s going rather good but sometimes I feel like it’s still may not be low-level enough API. Are there some better ways to attack this task?
Currently I’m trying to add support for one-way collisions. It is kinda weird that it looks like it’s not supported out of the box by any of the casting methods and Nodes. I read some source code of the engine and I found out that test_body_motion() used by move_and_collide() handles one-way collisions while cast_motion(), while having very similar implementation, does not. And it seems like it there is actually no support for it anywhere else beside move_and_collide()/GodotSpace2D::test_body_motion().
What I could try is:
casting a shape
checking colliding object if it’s oriented properly
exclude the object if it’s not
cast again
But it seems more like a workaround than a proper solution. So is there any more convenient way to handle one-way collisions without using move_and_collide()?
Is there in general better way of implementing custom collision response behavior and movement?
If you’re going for a pixel-perfect game, you may wind up having to do your own collision engine in general to ensure that the boxes and pixels match up; after all, the physics engine lets collision points take decimal values, while pixels are all full integers.
The method you suggested sounds decent, except why would you need to cast a 2nd time? Would the 1st cast not simply catch all objects collided, and then you can pop out the non-colliding objects before handling the collision check?
If you’re going for a pixel-perfect game, you may wind up having to do your own collision engine in general to ensure that the boxes and pixels match up; after all, the physics engine lets collision points take decimal values, while pixels are all full integers.
I was able to work around it with an assumption that all my collisions boxes are rectangles parallel to coordinate system axes and adding some rounding and negative margins.
Would the 1st cast not simply catch all objects collided, and then you can pop out the non-colliding objects before handling the collision check?
The issues with it is that after the first cast I get get_closest_collision_safe_fraction() only for first colliding object. So even if I find the first obstacle that I actually what to consider as colliding I don’t know how far body can move without another casting.
It is even worse than that. Looks like ShapeCase2D doesn’t even return info about all the collision along the motion. It seems like collision_result and int get_collision_count() (and thus all the methods taking index argument) only provide info about collisions at current resting place of a ShapeChast2D first point of impact. So it’s even more useless. It seems like a bug. I only get any useful information from safe/unsafe fraction - they both return values lower than 1.0 but all the other methods return 0s, falses, and empty arrays.
But even putting this bug aside, collision_result still does not return all the collisions along the whole motion vector. Only the few ones occurring at the first point of impact.
So even if there was no mentioned bug then still I need multiple casts and excluding one-way objects one-by-one.