this post was submitted on 12 May 2026
17 points (100.0% liked)

Godot

7613 readers
9 users here now

Welcome to the programming.dev Godot community!

This is a place where you can discuss about anything relating to the Godot game engine. Feel free to ask questions, post tutorials, show off your godot game, etc.

Make sure to follow the Godot CoC while chatting

We have a matrix room that can be used for chatting with other members of the community here

Links

Other Communities

Rules

We have a four strike system in this community where you get warned the first time you break a rule, then given a week ban, then given a year ban, then a permanent ban. Certain actions may bypass this and go straight to permanent ban if severe enough and done with malicious intent

Wormhole

!roguelikedev@programming.dev

Credits

founded 2 years ago
MODERATORS
 

I am working on the input and it feels like its getting out of hand. I wanted to check in with people and see how people structure their input handling.

Currently I have 1 function _unhandled_unput(event) and inside there I have a ton of elif statements trying to handle every possible situation and event. Its manageable at the moment but I only have like 4 events so its going to get very out of hand if I continue.

I need to have 100s of these events based on whats selected and what mouse/keyboard buttons are being pressed and I need some way to resuse the actions.

spoiler

func _unhandled_input(event):
	if event is InputEventMouseButton and event.pressed:
		if event.button_index == MOUSE_BUTTON_RIGHT:
			clear_selection()
			gui.queue_redraw()
			get_viewport().set_input_as_handled()
			return
	if selected_item == "colonist": #broken
		if event is InputEventKey:
			if event.OS.get_keycode_string() == "r":
				for colonist in selected_group:
					colonist.set_state("DRAFT")
					get_viewport().set_input_as_handled()
					gui.queue_redraw()
	#nothing selected dragbox to select things and single click to select things - does not work at the moment
	elif selected_type == "" or selected_type == "basic":
		if is_dragging and event is InputEventMouseMotion:
				drag_end = camera.get_global_mouse_position()
				cam_drag_end= get_viewport().get_mouse_position()
				get_selection(drag_start, drag_end)
				gui.queue_redraw()
				get_viewport().set_input_as_handled()
				return
		elif event is InputEventMouseButton and not event.pressed:
			is_dragging = false
			gui.queue_redraw()
			drag_start = null
			drag_end = null
			get_viewport().set_input_as_handled()
			return
		elif event is InputEventMouseButton and event.pressed:
			if event.button_index == MOUSE_BUTTON_LEFT:
				selected_type = "basic"
				is_dragging = true
				drag_start = camera.get_global_mouse_position()
				cam_drag_start = get_viewport().get_mouse_position()
				gui.queue_redraw()
				get_viewport().set_input_as_handled()
				return
	#command flow for dragging a selection box
	elif selected_type == "command":
		if selected_item == "structure_dict_growing":
			if is_dragging and event is InputEventMouseMotion:
				var grid_pos = tilemap.local_to_map(camera.get_global_mouse_position())
				var local_pos = tilemap.map_to_local(grid_pos)
				drag_end = local_pos + Vector2(32, 32)
				cam_drag_end = get_viewport().get_mouse_position()
				gui.queue_redraw()
				get_viewport().set_input_as_handled()
				return
			elif event is InputEventMouseButton and not event.pressed:
				if event.button_index == MOUSE_BUTTON_LEFT:
					is_dragging = false
					gui.queue_redraw()
					get_viewport().set_input_as_handled()
					MessageBus.rpc_id(1, "request_zone_growing", selected_item ,drag_start, drag_end, multiplayer.get_unique_id())
					drag_start = null
					drag_end = null
					return
			elif event is InputEventMouseButton and event.pressed:
				if event.button_index == MOUSE_BUTTON_LEFT:
					is_dragging = true
					#to snap to grid
					var grid_pos = tilemap.local_to_map(camera.get_global_mouse_position())
					var local_pos = tilemap.map_to_local(grid_pos)
					drag_start = local_pos - Vector2(32, 32)
					cam_drag_start = get_viewport().get_mouse_position() #this is broken cbf fixing maybe one day after selection is working 
					gui.queue_redraw()
					get_viewport().set_input_as_handled()
					return
	elif selected_type == "floor":
		if event is InputEventMouseButton and event.pressed:
			if event.button_index == MOUSE_BUTTON_LEFT:
				var global_mouse_pos = camera.get_global_mouse_position()
				var grid_pos = tilemap.local_to_map(global_mouse_pos)
				if selected_item == "":
					return
				MessageBus.rpc_id(1, "request_build_floor", selected_item, grid_pos, multiplayer.get_unique_id())
				get_viewport().set_input_as_handled()
				return
	elif selected_type == "building":
		if event is InputEventMouseButton and event.pressed:
			if event.button_index == MOUSE_BUTTON_LEFT:
				var global_mouse_pos = camera.get_global_mouse_position()
				var grid_pos = tilemap.local_to_map(global_mouse_pos)
				if selected_item == "":
					return
				MessageBus.rpc_id(1, "request_build_structure", selected_item, grid_pos, multiplayer.get_unique_id())
				get_viewport().set_input_as_handled()
				return

you are viewing a single comment's thread
view the rest of the comments
[–] FooBarrington@lemmy.world 1 points 5 hours ago* (last edited 51 minutes ago)

IMO this is a great case for Finite State Machines. Unfortunately I can't provide a GDScript example since I write in C#, but I think there are some assets for this in the asset library. The basic idea is that you define states, and valid transitions between those states (e.g. for a drag'n'drop system given the states idle, dragging and dropped it makes sense for the user to go idle -> dragging, dragging -> dropped and dropped -> idle, but not from idle -> dropped). Then you can separate the state transition logic from the main handler for each state, which I think is what you want, right?

This pattern can also easily be made reusable, either by having no dedicated logic in the state machine (-> everything is handled through events), or by using an adapter interface that components create and pass into the state machine.

Let me know if you have questions, or would like to see an example - I can at least provide pseudo code :)