Andrew Grothe
Andrew Grothe

Reputation: 2374

Determine visible area of TileMapLayer in Godot

I’m playing around with procedurally generated terrain and the new TileMapLayer in Godot 4. Very nice and easy to generate terrain.

Basic terrain generation

I’d like to generate the terrain in the visible area of the Camera2D, regardless of current zoom.

My zoom function in Camera2D:

public void ZoomCamera(double delta)
{
    Vector2 zoom = Zoom;
    if (Input.IsActionJustPressed("camera_zoom_in"))
    {
        zoom.X = Mathf.Clamp(zoom.X * 1.1f, MinZoom, MaxZoom);
        zoom.Y = Mathf.Clamp(zoom.Y * 1.1f, MinZoom, MaxZoom);
    }

    if (Input.IsActionJustPressed("camera_zoom_out"))
    {
        zoom.X = Mathf.Clamp(zoom.X * 0.9f, MinZoom, MaxZoom);
        zoom.Y = Mathf.Clamp(zoom.Y * 0.9f, MinZoom, MaxZoom);
    }
    Zoom = Zoom.Slerp(zoom, (float)(ZoomSpeed * delta));
}

I can translate the current mouse position and use that to select any tile:

var clickedCell = LocalToMap(GetLocalMousePosition());
SetCell(clickedCell, 0, new Vector2I(6, 0), 0);

Now when I try and calculate the viewport bounds and convert to local, its not the same coordinates as the mouse position.

public void ReCalculateViewPortBounds()
{
    var viewport = GetViewport();
    var camera = viewport.GetCamera2D();

    var viewport_size = viewport.GetVisibleRect().Size; // {(1152, 648)}
    var cameraPosition = camera.GlobalPosition; // {(0, 0)}

    var x = viewport_size.X; // 1152
    var y = viewport_size.Y; // 648
    var zx = Zoom.X; // 0.4
    var zy = Zoom.Y; // 0.4

    var half_width = (viewport_size.X * Zoom.X) / 2f; //  230.400009
    var half_height = (viewport_size.Y * Zoom.Y) / 2f; // 129.6

    // mouse position from as close to top left corner as I could get
    var mousePosition 
        = camera.GetGlobalMousePosition(); // { (2615.0005, -5132.5005)}


    // Define corners
    var top_left = cameraPosition 
        + (new Vector2(-half_width, -half_height)); //{(-230.40001, -129.6)}

    var top_right = cameraPosition 
        + (new Vector2(half_width, -half_height)); // {(230.40001, -129.6)}

    var bottom_left = cameraPosition
        + (new Vector2(-half_width, half_height)); //{(-230.40001, 129.6)}

    var bottom_right = cameraPosition 
        + (new Vector2(half_width, half_height)); //{(230.40001, 129.6)}


    // Send event
    EventBus.Instance.Bus.Publish<CameraEvent>(new CameraEvent
    {
        BottomLeft = ToLocal(bottom_left),
        BottomRight = ToLocal(bottom_right),
        TopLeft = ToLocal(top_left),
        TopRight = ToLocal(top_right)
    });
}

Which produces:

Basic terrain generation 2

Essentially, I’m trying to get the same coordinates as if I click the mouse in all four corners of the map at any given zoom level.

The camera.GetGlobalMousePosition() produces much different looking coordinates from the viewport numbers.

EDIT: As zennehoy pointed out, the math is wrong. Also, the camera position can be added to account for panning.

// Define corners
var top_left = cameraPosition 
    + (new Vector2(-half_width, -half_height)) + cameraPosition; 

Upvotes: 1

Views: 98

Answers (1)

zennehoy
zennehoy

Reputation: 6856

Looking only at the rendered output for an issue such as this makes it very difficult to tell what is going on, even more so for anyone unfamiliar with the code. In general, stepping through your code in a debugger or even just temporarily printing some intermediate values should help enormously to figure out what is going wrong.

That said, I believe your problem is that camera zoom increases the further you zoom in, so you should be dividing the viewport size by the camera zoom to calculate the visible world dimensions:

    var half_width = (viewportSize.X / Zoom.X) / 2f;
    var half_height = (viewportSize.Y / Zoom.Y) / 2f;

If that doesn't solve it, please add a print statement for the CameraEvent parameters and add the results at various zoom levels to your question, together with the values you are expecting.

Upvotes: 2

Related Questions