Raycast Gridmap MeshLibrary Help

Godot Version

4.3-stable

Question

I have a Gridmap with a MeshLibrary, I’m firing a raycast from the camera to my mouse position and it’s hitting the Gridmap and returns the cell data but not returning the “Tile” it’s hitting properly. It’s returning -1 which is basically empty

But it’s showing the rest of the data fine :sweat_smile:, so I think I’m pulling the wrong data or the raycast itself is incorrect? I’m not 100% sure.

The end goal is to turn the grass into snow on click

extends GridMap

const GRASS_TILE_ID = 41
const SNOW_TILE_ID = 83

func _input(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        print("Mouse click detected")
        var camera = get_viewport().get_camera_3d()
        
        var from = camera.project_ray_origin(get_viewport().get_mouse_position())
        var to = from + camera.project_ray_normal(get_viewport().get_mouse_position()) * 1000
        print("Raycast origin: ", from)
        print("Raycast direction: ", to)

        var ray_params = PhysicsRayQueryParameters3D.new()
        ray_params.from = from
        ray_params.to = to
        ray_params.collision_mask = 1

        var space_state = get_world_3d().direct_space_state
        var result = space_state.intersect_ray(ray_params)

        if result:
            print("Raycast hit something!")
            print("Result: ", result)
            print("Hit position: ", result.position)
            print("GridMap Cell Size: ", cell_size)

            var cell = local_to_map(result.position)
            print("Converted grid position: ", cell)

            var current_tile_id = get_cell_item(cell)
            print("Tile ID found: ", current_tile_id)

            if current_tile_id == GRASS_TILE_ID:
                print("Tile is grass. Changing to snow.")
                set_cell_item(cell, SNOW_TILE_ID)
            elif current_tile_id == SNOW_TILE_ID:
                print("Tile is snow. Changing to grass.")
                set_cell_item(cell, GRASS_TILE_ID)
            else:
                print("Tile ID doesn't match grass or snow. Tile ID found: ", current_tile_id)
        else:
            print("Raycast didn't hit anything.")

I essentially want to click the tile, get the type of mesh it is and if it’s grass, turn it to snow, but I can’t for the life of me get it to work and I wonder if the issue is the raycast but then it says it’s returning correctly, it’s just the contents it can’t find:

Mouse click detected
Raycast origin: (-1, 17, 8)
Raycast direction: (31.73623, -885.0504, -422.3875)
Raycast hit something!
Result: { “position”: (-0.442934, 1.649989, 0.676182), “normal”: (0, 1, 0), “face_index”: -1, “collider_id”: 41288729800, “collider”: GridMap:<GridMap#41288729800>, “shape”: 0, “rid”: RID(15801184681984) }
Hit position: (-0.442934, 1.649989, 0.676182)
GridMap Cell Size: (1, 0.1, 1)
Converted grid position: (-1, 16, 0)
Tile ID found: -1
Tile ID doesn’t match grass or snow. Tile ID found: -1


What’s inside here?

and what’s the position of your top-left node?

Hey Brunoverissimo,

var cell = local_to_map(result.position) returns: something like:

Converted grid position: (-2, 16, 0)

which is essentially where I’m clicking from the central point of the grid.

The top left one is:
Converted grid position: (-5, 16, -5)

Share the code you have in local_to_map(result.position).

Another thing I would do just to make things easier to find the issue, is to make top left start on (0,0,0).

I have some code on grid that I’m working right now and I have grid position working pretty fine, but it’s C#

So if you share more of your code, I might find what you are missing there

Hi Bruno,

I’m not sure what you’re asking? I have shared all the code for result.position? result is the space_state from intersect_ray via ray_params? I’m also printing out result.position and it’s in the logs I proivded?

I mean how are you calculating the conversion from global position (-0.442934, 1.649989, 0.676182) into a grid position (-1, 16, 0). This is calculate inside your local_to_map().

Plus, how are you calculating this: get_cell_item().

I will show you how I’m doing mine:

public void TestMouseClickOnGrid(string mouseButton){
    Dictionary results = this.ingame_instance.ShootRayCast();
    GridInfo index = this.grid_manager.GetGridIndex((Vector3)results["position"]);

    GD.Print(mouseButton + " clicked on index: " + index.ToString());

    Node scene = ResourceLoader.Load<PackedScene>(this.ingame_instance.buildings[GameManager.building_index].ResourcePath).Instantiate();
    Node3D building = scene as Node3D;
    building.Position = this.grid_manager.GetWorldPosition(index.columns, index.rows);
    Node3D gameNode = RequestNodeFromTree("/root/Game") as Node3D;
    gameNode.AddChild(building);

    this.grid_manager.AddNodetoTile(index, building);
}

public Dictionary ShootRayCast()
{
var camera = GetViewport().GetCamera3D();
var mousePosition = GetViewport().GetMousePosition();
var space = GetWorld3D().DirectSpaceState;

	PhysicsRayQueryParameters3D ray_query = new();
	ray_query.From = camera.ProjectRayOrigin(mousePosition); ;
	ray_query.To = ray_query.From + camera.ProjectRayNormal(mousePosition) * 100; ;
	var results = space.IntersectRay(ray_query);
	return results;
}
public GridInfo GetGridIndex(Vector3 worldposition)
{
    Vector3 gridIndex = (worldposition - origin_position) / this.grid_info.cell_size;

    if (gridIndex.X < 0 || gridIndex.Z < 0)
    {
        //throw new IndexOutOfRangeException("Index not valid");
        //gridIndex = new Vector3(-1,-1,-1);
        return null;
    }
    else if (gridIndex.X > grid_info.columns || gridIndex.Z > grid_info.rows)
    {
        //throw new IndexOutOfRangeException("Index not valid");
        return null;
    }

    return new GridInfo(Mathf.FloorToInt(gridIndex.X), Mathf.FloorToInt(gridIndex.Z), 0);
}
public Vector3 GetWorldPosition(int col, int row){
    return new Vector3(col, 0, row) * this.grid_info.cell_size + origin_position;
}

Ignore the origin_position, as this is 0 now and was from an old code…