|
|
|
|
Reply From: |
Wakatta |
Came across projects that needed to move all objects UI/3D/Drag-&-Drop 2D~3D and vise-versa so understand the need.
To set the x value on a RichTextLabel you can use either $RichTextLabel.rect_global_position.x = 5
or $RichTextLabel.rect_position.x = 5
The following code is part of a base class that gets extended but you can easily add it to a Singleton and call as needed.
E.g Singleton.set_position($RichTextLabel, Vector2(5, 0))
Pseudo code
func get_position(node):
if node is Control:
return node.rect_global_position
elif node is Spatial:
return node.global_transform.origin
elif node is Node2D:
return node.position
else:
assert(false, "%s nodes contain no position" % node.get_class())
func set_position(node, position):
assert(position is Vector2 or position is Vector3, "Invalid position type")
if node is Control or node is Node2D:
if position is Vector3:
position = Vector2(position.x, position.z)
if node is Control:
node.rect_global_position = position
elif node is Node2D:
node.position = position
elif node is Spatial:
if position is Vector2:
position = Vector3(position.x, 0, position.y)
node.global_transform.origin = position
else:
assert(false, "%s nodes contain no position to set" % node.get_class())
if you want a 3D node’s position in relation to the viewport screen you’ll have to project or unproject a ray and that node would have to be a CollisionObject
For the Spatial sections of the above code you can add
func raycast_from_mouse(position, mask):
var camera = get_viewport().get_camera()
var rayLength = 1000
var rayStart = camera.project_ray_origin(position)
var rayEnd = rayStart + camera.project_ray_normal(position) * rayLength
var spaceState = camera.get_world().direct_space_state
return spaceState.intersect_ray(rayStart, rayEnd, [], mask)
func get_position(node : Node):
if node is CollisionObject:
var mouse_pos = get_viewport().get_mouse_position()
var hit = raycast_from_mouse(mouse_pos, node.collision_layer)
if hit.size():
if hit.collider == node:
return hit.position
Thank you so much for this very helpful answer, Wakatta.
I DO blend 2d and 3d so this is very welcome. The solution to moving labels and richtextlabels was much easier than I thought.
As you wrote - there is no need to put them inside another node. You can change their 2d position manually in code with “rect _ position.x” (or y) or “rect _ global_position.x” (or y)
I also discovered that label and richtextlabel has mouse_entered() and mouse_exited() signals. I guess I didnt do my research good enough. (I come from python so Im used to coding everything manually.)
the raycasting will be useful when I put this section into my 3d world later.
The odd thing with the other answers I got, Is that they suggested Im using richtextlabel and labels wrong just because I want to manually manipulate the position of gui objects in code…
well, I cant see anything wrong in this.
Thank you again.
Timshark | 2021-05-05 16:51
Control nodes are mostly used for GUI and their size and position get set automatically by their parents using margins and anchors.
Don’t mean to sound redundant but Containers were made to sort and arrange it’s children nodes in an automated way eliminating the need to manually reposition or keep track of their location. Hence it coming off as odd.
So for a list generation a VBoxContainer would suffice and you’d just have to manipulate the placement index of the children nodes with functions such as raise(), add_child_below(), move_child(), replace_by()
Wakatta | 2021-05-05 20:26
Not redundant at all. I learn more with every answer.
I´ll check out vboxcontainer!
Timshark | 2021-05-05 20:56