Modos del ratón

Los cuatro valores de Input.mouse_mode tras cuatro botones. El punto viaja con event.relative, que es lo que sigue funcionando una vez capturado el puntero.

El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.

Clases de Godot usadas

InputInputEventMouseMotionButtonPanel

El código

scripts/main.gd
extends Node

const ARENA: Vector2 = Vector2(720, 260)
const CURSOR: float = 16.0

var modes: Array[Dictionary] = []
var buttons: Array[Button] = []
var mode_label: Label
var delta_label: Label
var cursor: Panel
var offset: Vector2 = ARENA * 0.5
var last_relative: Vector2 = Vector2.ZERO
var travel: float = 0.0


func _ready() -> void:
	modes = [
		{name = 'Visible', mode = Input.MOUSE_MODE_VISIBLE, key = KEY_1},
		{name = 'Hidden', mode = Input.MOUSE_MODE_HIDDEN, key = KEY_2},
		{name = 'Captured', mode = Input.MOUSE_MODE_CAPTURED, key = KEY_3},
		{name = 'Confined', mode = Input.MOUSE_MODE_CONFINED, key = KEY_4},
	]

	var column: VBoxContainer = _root()

	var title: Label = Label.new()
	title.text = 'Mouse modes'
	title.add_theme_font_size_override('font_size', 28)
	column.add_child(title)

	var hint: Label = Label.new()
	hint.text = 'click a mode or press 1 to 4, escape always goes back to visible'
	hint.add_theme_color_override('font_color', Color('#9aa3b5'))
	column.add_child(hint)

	var row: HBoxContainer = HBoxContainer.new()
	row.add_theme_constant_override('separation', 12)
	column.add_child(row)

	for i in modes.size():
		var button: Button = Button.new()
		button.text = '%s   %s' % [modes[i].name, OS.get_keycode_string(modes[i].key)]
		button.toggle_mode = true
		button.custom_minimum_size = Vector2(170, 44)
		button.pressed.connect(_set_mode.bind(modes[i].mode))
		row.add_child(button)
		buttons.append(button)

	column.add_child(_arena())

	mode_label = Label.new()
	mode_label.add_theme_font_size_override('font_size', 20)
	column.add_child(mode_label)

	delta_label = Label.new()
	delta_label.add_theme_color_override('font_color', Color('#8da5f3'))
	column.add_child(delta_label)

	print('switch the mode and move the mouse, the yellow dot rides on event.relative')


func _input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		var motion: InputEventMouseMotion = event

		last_relative = motion.relative
		travel += motion.relative.length()
		offset = (offset + motion.relative).clamp(Vector2(CURSOR, CURSOR), ARENA - Vector2(CURSOR, CURSOR))
		cursor.position = offset - Vector2(CURSOR, CURSOR)
	elif event is InputEventKey:
		var key: InputEventKey = event

		if not key.pressed or key.echo:
			return

		if key.keycode == KEY_ESCAPE:
			_set_mode(Input.MOUSE_MODE_VISIBLE)

		for entry: Dictionary in modes:
			if key.keycode == entry.key:
				_set_mode(entry.mode)


func _process(_delta: float) -> void:
	# the browser owns the pointer lock and drops it on escape without asking godot first
	var current: int = Input.mouse_mode

	for i in modes.size():
		buttons[i].set_pressed_no_signal(modes[i].mode == current)

	mode_label.text = 'Input.mouse_mode is %s' % _mode_name(current)
	delta_label.text = 'last relative %.0f, %.0f      travelled %.0f px' % [last_relative.x, last_relative.y, travel]


func _set_mode(mode: int) -> void:
	Input.mouse_mode = mode as Input.MouseMode


func _mode_name(mode: int) -> String:
	for entry: Dictionary in modes:
		if entry.mode == mode:
			return entry.name

	return 'unknown'


func _arena() -> Panel:
	var style: StyleBoxFlat = StyleBoxFlat.new()
	style.bg_color = Color('#1a1e28')
	style.border_color = Color('#2a2f3d')
	style.set_border_width_all(2)
	style.set_corner_radius_all(14)

	var panel: Panel = Panel.new()
	panel.custom_minimum_size = ARENA
	panel.size = ARENA
	panel.add_theme_stylebox_override('panel', style)
	panel.mouse_filter = Control.MOUSE_FILTER_IGNORE

	var caption: Label = Label.new()
	caption.text = 'relative motion keeps arriving while the pointer is captured'
	caption.position = Vector2(20, 18)
	caption.add_theme_color_override('font_color', Color('#9aa3b5'))
	caption.mouse_filter = Control.MOUSE_FILTER_IGNORE
	panel.add_child(caption)

	var dot_style: StyleBoxFlat = StyleBoxFlat.new()
	dot_style.bg_color = Color('#f3d48d')
	dot_style.set_corner_radius_all(int(CURSOR))

	cursor = Panel.new()
	cursor.size = Vector2(CURSOR * 2, CURSOR * 2)
	cursor.position = offset - Vector2(CURSOR, CURSOR)
	cursor.add_theme_stylebox_override('panel', dot_style)
	cursor.mouse_filter = Control.MOUSE_FILTER_IGNORE
	panel.add_child(cursor)

	return panel


func _root() -> VBoxContainer:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var center: CenterContainer = CenterContainer.new()
	add_child(center)
	center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var column: VBoxContainer = VBoxContainer.new()
	column.add_theme_constant_override('separation', 18)
	center.add_child(column)

	return column

Más ejemplos de Entrada