RayCast2D collision position doesn't get accurately rounded when converting ToLocal

Godot Version

v4.2.2.stable.mono.official [15073afe3]


My main goal is to have a RayCast in all 4 directions of my player that can detect a piece of TileData from the tile at the centre of whatever side of the player it’s on. This data is SurfaceType in this case. I have 4 RayCasts going out of the centre of the player in each direction

My issue is that when colliding with a tile on the left or top of the player, TileData returns null, despite working perfectly on the bottom and right of the player.

The following is my code that takes in a RayCast2D and returns the TileData.

private SurfaceType GetSurfaceFromRayCast(RayCast2D RayCast)
	TileMap Map = (TileMap)RayCast.GetCollider();

	Vector2I Cell = Map.LocalToMap(Map.ToLocal(RayCast.GetCollisionPoint()));
	TileData Data = Map.GetCellTileData(0, Cell);

	if (Data != null) 
		return (SurfaceType)(int)Data.GetCustomData("SurfaceType");
	return SurfaceType.NoSurface;

I have found that when creating a wall that is 1 tile wide in my map and pressing up against it, if I print Cell, it will print a different coordinate if I am on the left side of the wall than if I am on the right side.

So my only thought as to why it would not work properly on the left and top is that the way RayCast collision positions are converted into local coordinates isn’t entirely accurate due to rounding or something like that. Is there some kind of way I can change the accuracy of the coordinates by making them check a smaller region or is there some other glaring issue with my code here?


Forgot to mention this is for a 2D platformer

Why not use the collision body position over the collision position?

I suspect that the collision position will be on the edge of the collision shape and if the collision shape is not centered in the tile properly, or extends past the tile, the collision position could be outside the tile given you the wrong coordinate.

My RayCasts only extend 3 pixels out of the player so theres no way for it to extend past a tile of 16 pixels width.

I should mention I also played around with using GetSlideCollisionCount() but found it to be really inconsistent. If I run left it would get a bunch of values of 0 despite never leaving the ground and if pressed up against a wall it wouldn’t read the floor and the wall as 2 separate collisions. Feel like I should justify why I’m not just using that.

When you say “collision body position” are you saying to use the position of the Collider rather than doing RayCast.GetCollisionPoint()?

I guess is your intention to find the tile that contains the wall?

I missed the null part

And was focused on

Rays can miss in certain scenarios. When in 2d a collision shape will only detect collisions from the outside (or the front face). This is basically for optimization purposes, but can be enabled to collide on the back face. There are also collision margins to help detect collisions with faster objects. (I don’t know if a rays have a speed, or step distance, I wouldn’t think so but idk for sure.). And maybe if a rays is entirely inside a collision object it may not detect a collision because it did not collide with a face?

But since you say your rays are only 3 pixels I wonder where the boundaries of the player collider, the wall collider and the ray path exists as a whole.

Since you use raycast object, if you turn on the collision debugger it will show lines for the rays, as well as the collision bodies. This may give us a clue to figure out what’s going on.