Is it possible to get 3.0.6 KinematicBody box collision behavior in 3.1.1?

jitspoejitspoe Posts: 7Member

Something with the physics changed after I updated from 3.0.6 to 3.1.1. I'm using a KinematicBody with a BoxShape collision for my character. Before, if I landed on a ledge, I either made it or not. Now it behaves as though the edges of boxes are rounded -- almost as though I'm using a capsule -- and I can land on the edge of a block and slide off.

All the collision here is clean 90 degree angles (might not look like it because of the perspective of the stairs), but I'm getting normals as though there's a curved edge, and the character will slip down off the edge of steps.

I'm using move_and_collide() and the white line is the normal I get close to the edge. Is there a way to get the actual normal of the surface hit?

Also, I tried setting the safe margin to 0 to test, but it didn't seem to make a difference. Had to do it in code, since I can't set it below a certain value in data.

Tags :


  • TwistedTwiglegTwistedTwigleg Posts: 2,468Admin

    What does the project look like if you enable visible collision shapes in the debug dropdown? Maybe something is changing the collision shapes when the game is playing or something.

    From what I know and have used, the move_and_collide function should just stop the KinematicBody at the collision. It sounds like the move_and_collide function is acting more like the move_and_slide function. Maybe there is a regression or bug that is causing move_and_collide to act strangely. Does the project have this problem with Godot 3.1.0?

    Looking through the issues on Github for move_and_collide, it looks like this issue might be the problem. Apparently setting the collision margin to a very small number, like 0.001 might reduce the problem, but unfortunately it doesn’t fix it.

    After taking a closer look at the picture, I wonder if the normal returned from move_and_collide is somehow incorporating the velocity of the KinematicBody. That might explain why the line is at an angle, since gravity would be pushing the character down. Perhaps with a collision to the left/right it is adding the gravity into the normal projection somehow? I dunno, it seems strange.

  • jitspoejitspoe Posts: 7Member

    Here's a shot with visible collision shapes. Interesting fact: If the collision does update, the visuals don't (I change the collision extents when crouching, but the box size doesn't change). None of the world geo should be changing in this case, though. It's all static.

    (Don't mind the box inside of the character -- that's used for attacks and is disabled).

    move_and_collide() does just stop at the object. It also returns the collision info, including the normal (which I'm using for my movement code). I tested 3.1.0, and it also has the issue. 3.0.6 would have the normal going straight up in this case (though it did have an issue where sometimes movement would stop near edges but no collision info would be generated, so maybe this new behavior was to fix that bug?).

    The issue you linked is a different problem. It was also an issue in 3.0.6. It's only an issue when the normal isn't straight up. It would be nice to fix it, but it isn't as critical.

    The normal isn't impacted by velocity, aside from the fact that the velocity is necessary to move toward something to collide with. move_and_collide() doesn't even know what the velocity is -- it just takes an offset.

  • TwistedTwiglegTwistedTwigleg Posts: 2,468Admin

    Ah, okay, I think I understand the problem now. I thought the issue was the move_and_collide function was causing the player to slide on edges, with the normal issue being an additional (minor) issue.

    I don't know why the KinematicBody2D is returning angled normals for surfaces at right angles. Perhaps it is as you said, where the behavior is to fix the issue where collisions at edges were not being returned. Another potential thing that could theoretically be causing the issue is very small corner overlaps, where the corner of the collision boxes intersect and so Godot doesn't know if the collision is going horizontal or vertical, so it returns a mixture of the two (just guessing though, I haven't looked at the code).

    However, I think I know how you could solve the problem. If you send a raycast, either through code or from the Raycast2D node, in the direction that the player is moving towards, you could use the normal vector returned from the raycast collision to detect the angle instead of the result from the KinematicBody2D. Performance shouldn't be impacted so long as you are not sending too many raycasts at once, and last I knew the physics raycast doesn't have an issue with ninety degree angles.

    One snag is that it might be difficult to find the position(s) to place the raycast origins depending on your game and the requirements. Looking at the pictures above, you might be able to get away with sending either a single raycast to the bottom corner of the collision box in the same direction the player is facing, or two raycasts with one going downwards on the vertical axis and another in the same direction the player is facing on the horizontal axis.

    That said, there is probably a better way to get around it, but right off that is what I would do. I would also consider making a GitHub issue on the Godot repository for the strange normals returned by move_and_collide so it can be fixed.

    Hopefully this helps!

  • TwistedTwiglegTwistedTwigleg Posts: 2,468Admin

    I had another thought: Since you already have the position of the collision from move_and_collide, you could just send a raycast from the center of the character and point it towards the collision position. That way you could, with reasonable accuracy, get the normal of the surface the character is colliding with a single raycast.

  • jitspoejitspoe Posts: 7Member

    I suppose using raycasts would be a workaround. I'm a bit concerned about the potential edge cases and other oddities that might happen with this. Sometimes the surface normal isn't what you actually want. If you're standing at the top of a wedge, for example, the normal should point upward. It would be nice to just be able to do sweeps and get collision info. There are functions that sort of do this, but none of them provide the necessary info. test_move() just returns a Boolean. There's a cast_motion() that can see how far a shape can move before hitting something, but it has no normals or info on what was actually hit. get_rest_info() and intersect_shape() have additional info, but only for a stationary shape, not something with a start and end position. Not sure how reliable they would be for this. Meanwhile intersect_ray(), has a start and end position. Feels like I'm just short of having what I need.

    I'm half tempted to just use 2D collision and set the 3D mesh positions based off of that (not sure if it's possible to have 2D stuff drive 3D, or if I'd have to just move it manually every update). Certainly not ideal for asset creation, but 3D collision seems to be very glitchy and unreliable right now. Even had a couple instances where the character moved through solid geo.

  • jitspoejitspoe Posts: 7Member

    I have bad news, and I have worse news. Bad news: The more I thought about the raycast solution, the more I realized there were a number of edge cases that would be problematic (like in the corner between two surfaces -- the raycast might hit the wrong one, and the collision position isn't really as reliable as I hoped). Also the raycasts seem to miss a lot unless they go well into the collision.

    Worse news? I tried the raycast anyway, and [i]it has the same issue[/i]. If you raycast against the edge of an object, you get an angled normal. This is my ray casting straight down from the center of the character (offset forward a bit for better visibility).

    Here's another shot raycasting to the point of collision (had to extend the length of the raycast to actually make it hit):

    This makes me think maybe something fundamentally changed -- new version of Bullet, maybe? I browsed through the Godot code a bit and didn't find anything that looked obviously different. At this point, I think I'd have to compile the code and really step through it to catch what's going on. I'm hoping there's a way around this at the gdscript level, as I'm trying to avoid compiling for multiple platforms.

  • TwistedTwiglegTwistedTwigleg Posts: 2,468Admin

    Maybe make a issue on GitHub and see what they think? Perhaps a bug was introduced between versions.

    Also, have you posted on the Godot Reddit/Facebook? As far as I know, the core developers are more active there, so someone there might know better on what could be causing the different behavior.

  • jitspoejitspoe Posts: 7Member

    Seems there's an issue for it, and it's worse than I thought.

    With a ray cast for every pixel, this was the result:

    No wonder things have felt so sloppy/inconsistent. What's even scarier than the rounded edges are those spots that are well off of the box seemingly randomly generating collision hits.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file