CanvasLayer offset behavior

Godot Version

v4.2.2.stable.official.15073afe3

Question

How does CanvasLayer offset work in relation to viewport?

Im trying to center my “level” on the y axis of viewport. For that Im calculating a scaling factor by givin a margin in pixels on the X axis.

I then calculate the middle point with a simple formula of d = (y - y.a)/2 where “a” is the scalling and “y” is the viewport.y

This is the result and its clearly not in the middle of the screen. The pink line is a draw_line positioned at “viewport.y/2”.

This is the structure (Im trying to mimic my main project structure).

This is the Node code:

extends Node

var viewport_size_rec
var viewport_size
var device_safe_area
var safe_area: Rect2i
var safe_area_top
var scaleFactor
var new_position
var dpi
@export var CanvasLayer_Level: CanvasLayer

func _ready():
	_handle_screen_resize() 
	

	
func clamp_safe_area(sa:Vector2i, vp: Vector2i) -> Vector2i:
	if sa.x > vp.x:
		sa.x = vp.x
	if sa.y > vp.y:
		sa.y = vp.y
	return sa
	
	
func _handle_screen_resize():

	var os_name = OS.get_name()
	print(os_name)
	if os_name == "Android" || os_name == "Windows"  :
		
		viewport_size_rec 	= get_viewport().get_visible_rect().size
		viewport_size 		= get_viewport().size
		device_safe_area 	= DisplayServer.get_display_safe_area()	
		
		if os_name == "Windows"  :
			device_safe_area.position = Vector2i(0,0) #this depends on which screen will game launch
		device_safe_area.size = clamp_safe_area(device_safe_area.size, viewport_size)
		
		safe_area.position 	= device_safe_area.position
		safe_area.size 		= device_safe_area.size - Vector2i(960,0) # added safe marging on X axis
		scaleFactor 		= float(safe_area.size.x)/float(viewport_size.x)
		new_position 		= Vector2(
			safe_area.position.x,
			(viewport_size.y-(viewport_size.y * scaleFactor))*0.5)
			
		CanvasLayer_Level.set_scale(Vector2(scaleFactor,scaleFactor))
		CanvasLayer_Level.set_offset(new_position)	

		

		
		print("viewport_size_rec>",viewport_size_rec)
		print("viewport_size>",viewport_size)
		print("device_safe_area>",device_safe_area)
		print("safe_area>",safe_area)
		print("scaleFactor>",scaleFactor)
		print("new_position>",new_position)



and the draw_line code:

extends Control

func _draw():
	var viewport_size = get_viewport().get_visible_rect().size
	var mid_y = viewport_size.y / 2
	draw_line(Vector2(0, mid_y), Vector2(viewport_size.x, mid_y), Color.DEEP_PINK, 10)

The relevant project settings are:

Viewport Width: 800
Viewport Height: 360
Mode: Exclusive Fullscreen
Stretch Mode: canvas_items
Aspect: keep

This is my output:

Windows
viewport_size_rec>(800, 360)
viewport_size>(1920, 1080)
device_safe_area>[P: (0, 0), S: (1920, 1032)]
safe_area>[P: (0, 0), S: (960, 1032)]
scaleFactor>0.5
new_position>(0, 270)

My screen resolution is 1920x1080 and I set the “Safe Margin” to be -960 so that the scalling factor is 0.5 to make it easier to understand the pixel values.

My calculated new_position is (0, 270) which is correct given the formula but the offset is way off screen. What am I missing?

Thank you

SOLVED:
You have to divide

d = (y - y.a)/2

by the scaling of the viewport in relation to the rect. In this case:

d = (y - y.a) / 2
d = d / (viewport_size.y/viewport_size_rec.y)

I don’t know where in the docs it says that “offset” is affected by the viewport scaling but at least its fixed.

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