Skip to content

Instantly share code, notes, and snippets.

@noidexe
Last active October 20, 2017 19:52
Show Gist options
  • Save noidexe/8263b062faac3e4401d91e51dfcd67c3 to your computer and use it in GitHub Desktop.
Save noidexe/8263b062faac3e4401d91e51dfcd67c3 to your computer and use it in GitHub Desktop.
Drag n Drop example in Godot
extends Node2D
signal picked
signal dropped
enum DRAGSTATES { PICKED, DROPPED }
var drag_state = DRAGSTATES.DROPPED
var prev_mouse_pos = Vector2(0,0)
var absolute_z = IntArray([0])
var last_event
func _ready():
if 0 != get_node("area").connect("input_event", self, "_on_area_input_event"):
g.g.console.perror("Error: Failed to connect area to input event")
pass
_calculate_absolute_z()
set_process_unhandled_input(true)
func _on_area_input_event( viewport, event, shape_idx ):
if (
event.is_action_pressed("click")
and drag_state == DRAGSTATES.DROPPED
and not g.picking_object
):
#g.console.pprint("picked " + str(get_name()) )
#_on_picked(event)
last_event = event
g.pickup_candidates.push_back(self)
elif event.is_action_released("click") and drag_state == DRAGSTATES.PICKED:
g.console.pprint("dropped " + str(get_name()) )
_on_dropped(event)
pass
func _on_picked(event):
drag_state = DRAGSTATES.PICKED
g.picking_object = true
prev_mouse_pos = get_global_mouse_pos()
pass
func _on_dropped(event):
#if !event: event = last_event
drag_state = DRAGSTATES.DROPPED
g.picking_object = false
_calculate_absolute_z()
pass
func _unhandled_input(event):
if (
event.type == InputEvent.MOUSE_MOTION and
drag_state == DRAGSTATES.PICKED
):
set_pos(get_pos() + (get_global_mouse_pos() - prev_mouse_pos))
g.camera.move_to(get_global_pos())
prev_mouse_pos = get_global_mouse_pos()
pass
func _calculate_absolute_z():
absolute_z = IntArray([])
var node = self
#Add node indices from leaf to trunk excluding root and scene root
while node.get_parent().get_name() != "root":
absolute_z.append(node.get_index())
#if it's a child of YSort append the y position so that is used
#first and index only in case both y are equal
if node.get_parent() extends YSort:
absolute_z.append(node.get_pos().y)
node = node.get_parent()
pass
#invert array so indices are arranged trunk to leaf
absolute_z.invert()
#this node extends draggableObject.gd and plays an animation when the object is picked or dropped
extends "res://scenes/draggableObject/draggableObject.gd"
onready var anims = get_node("anims")
func _ready():
pass
func _on_picked(event):
._on_picked(event)
anims.play("picked")
func _on_dropped(event):
._on_dropped(event)
anims.play("dropped")
extends Node
## Reference to globally available systems and states.
#In game console
var console #Node
#Main camera
var camera #Node
#StreamPlayer for backgroud music
var music #StreamPlayer
#Drag n Drop state
var picking_object #bool
var pickup_candidates = []
func _ready():
_initialize()
set_process(true)
pass
#Reload current scene
func reset():
set_process(false)
_initialize()
get_tree().reload_current_scene()
#Initialization code for this node. To be called on run and on reset
func _initialize():
console = null
camera = null
music = null
picking_object = false
pickup_candidates = []
set_process(true)
print("Initialized %s" % get_name())
func _process(delta):
if pickup_candidates.size() > 0:
_resolve_pickup()
#This picks the topmost candidate taking into account position within the scene tree and YSort nodes. It currenty ignores the Z property.
func _resolve_pickup():
var good_list = []
var iteration = 0
while pickup_candidates.size() > 1:
good_list = []
for candidate in pickup_candidates:
if good_list.size() == 0:
good_list.push_back(candidate)
else:
var abs_z = good_list[good_list.size()-1].absolute_z[iteration]
if candidate.absolute_z[iteration] == abs_z:
good_list.push_back(candidate)
elif candidate.absolute_z[iteration] > abs_z:
good_list = [candidate]
pickup_candidates = good_list
iteration +=1
var winner = pickup_candidates[0]
winner._on_picked(winner.last_event)
pickup_candidates = []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment