Why would space_state.intersect_ray() collide in such a way?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By BarbosNikitos

I am getting familiar with the Godot, getting some basic work done and everything has been rather nice and easy to get behind, but I’ve stumbled onto a problem I can’t seem to fix.

Trying to build a rogue-like dungeon, I’ve been following a tutorial to create a FOV effect. It’s very simple - loop through every single tile, raycast to check if player can see it. Slight adjustments for the direction, but that’s not the point.

The issue that I’m having is that the collisions occurs all over the place… For example, on this picture I cast ray from player (cyan heart) to every tile (green dot), but don’t get collision on the walls (even though they have colliders):
enter image description here

Here, I’m getting collisions everywhere, but there is nothing to collide with, floor tiles have no colliders:
enter image description here

Finally, here I’m getting something similar to the result I’m looking for, but some walls are still ignored and not collided with, while others work just fine:
enter image description here

I have no clue what it is… There shouldn’t be any colliders in the scene apart from generated ones in the tilemap (walls and doors). I’ve checked, and the positions for raycasting are selected rather precisely, so the problem is the collision.

Why is it like this? What can I do to avoid it?

Here’s the code for visual’s update and FOV calculation (and highlighting raycast points + collisions):

func update_visuals():
	for entity in game_map.entities:
		entity.position = Vector2(entity.grid_x * game_map.TILE_SIZE, entity.grid_y * game_map.TILE_SIZE)
		
	call_deferred("recalc_fov")

func recalc_fov():
	for n in $test.get_children():
		$test.remove_child(n)
		n.queue_free()
	
	var player_center = tile_to_pixel_center(player.grid_x, player.grid_y)
	$"test-heart".position = player_center
	var space_state = get_world_2d().direct_space_state
	for x in range(game_map.level_size.x):
		for y in range(game_map.level_size.y):
			var sprite_cell = Sprite.new()
			var x_dir = 1 if x < player.grid_x else -1
			var y_dir = 1 if y < player.grid_y else -1
			var test_point = tile_to_pixel_center(x,y) + (Vector2(x_dir,y_dir) * (game_map.TILE_SIZE / 2))
			
			sprite_cell.position = test_point
			sprite_cell.texture = load("res://assets/sprites/test-dot.png")
			
			var occlusion = space_state.intersect_ray(player_center, test_point)
			if !occlusion || (occlusion.position - test_point).length() < 1:
				game_map.visibility_map.set_cell(x, y, -1)
				
			else:
				game_map.visibility_map.set_cell(x, y, 0)
				
			if (occlusion):
				var sprite = Sprite.new()
				sprite.texture = load("res://assets/sprites/test-cross.png")
				sprite.position = occlusion.position
				$test.add_child(sprite)
				
			$test.add_child(sprite_cell)

I’m really are a bit of a noob with the engine, although have done similar things before, but if I’m missing something obvious - like a setting or two, please, let me know! Or if it’s something more complex - I would also love to find out.

Just in case, this is definitely not extra colliders, I’ve found and turned on the Visible collision shapes, here’s the result:
enter image description here

BarbosNikitos | 2020-01-17 10:07

The problem might be outside of this code. Make sure you haven’t swapped X and Y or wrote twice X or twice Y.

Zylann | 2020-01-17 13:38

But that’s the thing, I don’t see how the problem can occur outside of this code. Only position handling is not included, but all the positions highlighted with green dots are actual positions in the scene, it clearly knows what the player center and test points are for space_state.intersect_ray(player_center, test_point) - that’s why I highlighted them with these gizmos, to check that the places are detected correctly.

It’s the check that happens that just appears very weird…

BarbosNikitos | 2020-01-17 18:00

What is the code of tile_to_pixel_center? Did you check if it could be a problem about local vs global, child vs parent relative positions? Raycasts expect world space positions.

Zylann | 2020-01-17 19:40

:bust_in_silhouette: Reply From: BarbosNikitos

Thank you, Zylan! Your comments actually gave me an idea and it did turn out true…

All my positioning is correct, but I’ve had root Node with Transform/Scale x and y set to 2, instead of 1. It allowed me to easily scale up everything to look presentable on the screen, while keeping the low pixel count, but it did screw up the raycast.

I’ve changed Scale x and y back to 1, and eveything works as expected! I’ll be on the lookout for ways to zoom in without hurting the raycast calculation, and this question can be considered solved!

enter image description here