Godot用Area2D实现带层次拖动

效果
Node2D.gd: 于 2022-01-05 编辑

extends Node2D

var ball = preload("res://Area2D.tscn") 
var prv
onready var viewSize = get_viewport_rect().size

class Sorter:
	static func sort(a, b):
		if a["collider"].get_index() > b["collider"].get_index():
			return true
		return false

func _ready():	
	randomize()
	for i in 200:
		new(i > 100)

func _input(event):
	if event is InputEventMouseButton:
		match event.button_index:
			BUTTON_LEFT:
				if event.is_pressed():
					#这里可以应用各种规则来提高效率,比如减少intersect_point检测数量,减少intersect_point触发次数
					var stime = OS.get_ticks_msec()
					var shapes = get_world_2d().direct_space_state.intersect_point(get_global_mouse_position(), 9999, [], 0x7fffffff, false, true)
					var size = shapes.size()
					if size > 0:
						if size > 1:
							shapes.sort_custom(Sorter, "sort")
						var etime = OS.get_ticks_msec() - stime
						print("检测耗时(毫秒)", etime)
						var collider = shapes[0]["collider"]
						if collider.has_method("_on_drag"):
							if collider.get_index() < collider.get_parent().get_child_count() - 1:
								collider.raise()
								print("置顶", collider.get_instance_id())
							prv = collider
							collider._on_drag(true)
					else:
						print("intersect_point zero")
				else:
					if prv:
						prv._on_drag(false)
						prv = null
			BUTTON_RIGHT:
				if event.is_pressed():
					new(false)

func new(rnd):
	var node = ball.instance()
	var size = node.get_node("Sprite").texture.get_size()
	if rnd:
		node.position = Vector2(rand_range(size.x * 4, viewSize.x - size.x), rand_range(size.y, viewSize.y - size.y))
	else:
		node.position = size
	add_child(node)

Area2D.gd:

extends Area2D

var isDrag = false
var offset
onready var label = $Label
onready var sprite = $Sprite
onready var id = self.get_instance_id()

func _ready():
	label.text = str(id);
	sprite.self_modulate = Color(randf(), randf(), randf(), 1)

func _process(delta):
	if isDrag:
		self.position = get_global_mouse_position() + offset

func _on_drag(state):
	if state:
		offset = self.position - get_global_mouse_position()
		isDrag = true
		print("开始拖动", id)
	else:
		if isDrag:
			isDrag = false
			print("结束拖动", id)

#func _on_Area2D_input_event(viewport, event, shape_idx):
#	if isDrag:
#			if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
#				if not event.is_pressed():
#					isDrag = false
#					print("内部结束(实例id)", id)

于 2022-01-05 补充
direct_space_state属于物理系统,在input输入事件中使用可能存在时序问题,改为在physics_process回调中使用更加合适
其它安全问题参考:https://docs.godotengine.org/zh_CN/stable/tutorials/physics/ray-casting.html

Node2D.gd:

func _physics_process(delta):
	if Input.is_action_just_pressed("ui_mouse_left"):
		#这里可以应用各种规则来提高效率,比如减少intersect_point检测数量,减少intersect_point触发次数
		var stime = OS.get_ticks_msec()
		var shapes = get_world_2d().direct_space_state.intersect_point(get_global_mouse_position(), 9999, [], 0x7fffffff, false, true)
		var size = shapes.size()
		if size > 0:
			if size > 1:
				shapes.sort_custom(Sorter, "sort")
			var etime = OS.get_ticks_msec() - stime
			print("检测耗时(毫秒)", etime)
			var collider = shapes[0]["collider"]
			if collider.has_method("_on_drag"):
				if collider.get_index() < collider.get_parent().get_child_count() - 1:
					collider.raise()
					print("置顶", collider.get_instance_id())
				prv = collider
				collider._on_drag(true)
		else:
			print("intersect_point zero")
	elif Input.is_action_just_released("ui_mouse_left"):
		if prv:
			prv._on_drag(false)
			prv = null
	if Input.is_action_just_pressed("ui_mouse_right"):
		new(false)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值