[Godot 2] How to click and drag an Area in 3D space?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By woopdeedoo

The purpose is to make handles for editing 3D meshes, and my desired behavior is quite the same as the little handles that you find in Godot’s CollisionShapes, to adjust their extents.

Below is the code I have so far in the Area’s script. The area is ray pickable, and I’m using input events as they seem straightforward and easy to use, and it seems like this might be achievable with that.

As it is though, I can only drag the thing if I move the mouse slowly, or else it goes outside and stops receiving input events. I managed to make it so I can move the mouse outside the Area a little bit, but it has problems, as it doesn’t reset the state (frame) of the Sprite, at least in the way I’ve coded it. It’s suppose to work a bit like a button, so the Sprite has 3 frames for normal state, clicked and hovered.

The scene tree is just an Area, with a billboard Sprite3D (for the icon) and a sphere CollisionShape. Its parent is a spatial, which is the 3D view scene of my app.

It might help if someone could point me to the files in Godot’s own source code where the CollisionShape handles are implemented, so I could see how they did this. I’ve been trying to find that, but so far no luck…

extends Area

onready var view = get_parent().get_parent().get_parent()
onready var sprite = get_node("Sprite3D")

enum {NONE, HOVERED, CLICKED}
var state

func _ready():
	switch_state(NONE)

func switch_state(st):
	if st != state:
		state = st
		sprite.set_frame(state)

func _on_TopHandle_input_event( camera, event, click_pos, click_normal, shape_idx ):
	if event.type==InputEvent.MOUSE_MOTION and state == CLICKED:
		set_translation(Vector3(get_translation().x, click_pos.y, get_translation().z))

	if event.is_action_pressed("editor_select"):
		switch_state(CLICKED)
	elif event.is_action_released("editor_select"):
		switch_state(HOVERED)

func _on_TopHandle_mouse_enter():
	switch_state(HOVERED)

func _on_TopHandle_mouse_exit():
	# my attempt at making it not let go until I release the mouse button 
	if state != CLICKED:		
		switch_state(NONE)