Modes de la souris

Les quatre valeurs de Input.mouse_mode derrière quatre boutons. Le point suit event.relative, qui est ce qui continue de marcher une fois le pointeur capturé.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

InputInputEventMouseMotionButtonPanel

Le code

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

Plus d'exemples de Entrées