Collisions between objects in different CanvasLayers

Godot Version

v4.2.1.stable.official [b09f793f5]

Question

Hello. I’m trying to use a CanvasLayer built on top of the root node as an interface layer to interact with root node objects. I have an Area2D node on the top CanvasLayer to collide with root node objects. It works fine as long as the Viewport isn’t moving, but when I add a Camera to the character on the root node and the character starts moving along with the view, the collision stops working. I understand that the position of the Area2D that is on the CanvasLayer stays relative to the screen. And that’s how I intend it to be. But apparently this interferes with the collision calculation. It still collides with objects on the root node, but it uses it’s own coordinates on the top CanvasLayer. Is there some way to make this Area2D on the top CanvasLayer use the root node coordinates only for detecting collisions?

You could write a simple script that translates a 2D coordinate into a coordinate on your canvas layer, and do calculations like that. I wrote this in C# but I did my best to translate it into GDScript, if it doesn’t quite work, I apologise.

func world_to_viewport(target: Node2D) -> Vector2:
    var target_canvas_position = target.get_screen_transform().origin.clamped(Vector2.ZERO, target.get_viewport_rect().size)
    return target_canvas_position
1 Like

How come you want them on different layers? My recommendation without knowing more would be to use a Tilemap. Then you get different layers for whatever your are displaying, plus control over collisions on all those layers. I also do not understand why you are using CanvasLayers at all for this. They are Control Nodes. You want to use Node2D nodes for gameplay.

Yes, if I feed these new coordinates to the CollisionShape it will likely work, thanks. I was wondering if there’s some way to tell Area2D in wich CanvasLayer it will collide with, regardless of where it is. Like you do with Z layers for drawing.

I want to make something that works like the Lakitu on 2D Mario games. It moves following the screen coordinates, so it’s always visible, but it collides with the game characters, that move relative to the world coordinates.

Hmmm have you looked at ParallaxBackground? Regardless, if you use a Node2D instead of a CanvasLayer to display it and set the z-order, you should get your collisions without having to do anything else.

regardless of layer you could just make distance check (its like colliding spheres).

if node.global_position.distance_to(node2.global_position) < 100.0: print("collides")

or rectangular variant:

var rect:Rect2
	if rect.has_point(target.global_position): print("position inside")
1 Like

I used CanvasLayer because I want it to move along with the game interface, relative to the screen position, even though it collides with objects on the root node. Since there’s a Camera that changes the screen position when the character moves, if I put it on a Node2D child to the root node, it will not move along with the screen.

Yes, but this won’t work because the collider nodes inside a CanvasLayer use a global_position relative to the CanvasLayer itself, not the root node where the colliding character nodes are (that apparently has it’s own CanvasLayer). It’s likely the same reason why, even though the collision is calculated, and works properly on a static screen, as soon as the Camera moves, and the root coodinates are no longer the same as the one from the new CanvasLayer, they do not work anymore.

Try this:

  1. Right-Click on the CanvasLayer node.
  2. Select Change Type from the pop-up menu.
  3. Select Node2D in the dialog box.

See if that solves your problem.

No. By putting it on a Node2D it does not move relative to the screen anymore. I can understand what you’re trying to do and I see it may work, but the way you’re guiding me I’ll have to refactor a huge portion of my code and it’s likely to break more stuff than it fixes. At this point I’ll go with tibaverus answer that, even though does not use a native solution, it’s more practical to implement. Thanks for your time anyway.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.