Giter Site home page Giter Site logo

Re-bindable Inputs about cogito HOT 15 OPEN

phazorknight avatar phazorknight commented on August 25, 2024 1
Re-bindable Inputs

from cogito.

Comments (15)

Jealousmango avatar Jealousmango commented on August 25, 2024 4

Another quick update about my progress!

I've filtered out all of the built-in action names and have also implemented the discussed "friendly" names mapping for action names. If no friendly name is added to the map the label text will fall back to the default name.

I also have a simple rebind menu that pops up when the rebind button is clicked with data for the relevant action piped into the rebind menu. I'm listening for input on that menu and rebinding the associated action to the new input. Currently working through the saving dialog and logic.

Once that's done I'll clean up the button labels based on the detected device. For Joypads I'd really love to dynamically change the button label to an icon for the correct device, but that would require importing icons for each type of Joypad I think? I'd welcome any feedback on this!

When I prepare this PR, should I open that against the new tabbed menu design from #55? For testing my current setup is just a Controls button on the main menu but I can migrate what I have into the tabs redesign if that makes sense.

image

from cogito.

Jealousmango avatar Jealousmango commented on August 25, 2024 3

Wanted to drop a quick update on where I'm at on this issue!

I've setup a placeholder Controls menu option within the existing Options menu and I'm populating that menu with the input map. I've also started hooking up the data for things like the button and key input text. Once that's working remapping the input should be straightforward. I'm hoping to have some free time this week to continue making progress.

image

from cogito.

Jealousmango avatar Jealousmango commented on August 25, 2024 2

I wasn't able to find a simple way to exclude the default inputs, but I haven't dug too deeply yet.

I've done some investigating in the past on this. And as far as I could find, there isn't a method available from GDScript that can tell you whether an Input mapping is built-in or not. There is, tantalisingly, in the Godot source code a function called 'get_builtins' https://github.com/godotengine/godot/blob/a586e860e5fc382dec4ad9a0bec72f7c6684f020/core/input/input_map.cpp#L382 I was completely unable to find any reference to this that's accessible via GDScript. If you're sufficiently motivated, you might be able to use GDNative to hook into that directly.

Personally wasn't willing to go that far, so I came up with this hack-y Resource instead (edited slightly to make more sense in context):

@tool
extends Resource
class_name RebindableActions

@export var inputs : Array[String]
static var custom_actions : Array[String]

func _init():
	inputs = get_actions().duplicate()
	ProjectSettings.property_list_changed.connect(_refresh)

static func _refresh():
	custom_actions = []
	var was_input = false
	var loaded_defaults = false
	for setting in ProjectSettings.get_property_list():
		var is_input = setting.name.begins_with('input/')
		if was_input and not is_input:
			loaded_defaults = true
		elif is_input and loaded_defaults:
			custom_actions.push_back(setting.name.split('/')[-1])
		was_input = is_input

func get_actions():
	if custom_actions:
		return custom_actions
	_refresh()
	return custom_actions

func _property_can_revert(property):
	if property == 'inputs':
		return get_actions() != inputs

func _property_get_revert(property):
	if property == 'inputs':
		return get_actions().duplicate()

This works because ProjectSettings will provide you the property list in the order it was loaded. So it loads the built-in project settings first, and then loads any user configured project settings. Even if you add/remove inputs from the built-in actions, all built-in actions will stay bunched together. And of course, you can reverse _refresh()s behaviour to get all builtin actions.

This will work on export as well.

If you would rather just a full list to be updated of the built-in actions manually, you can find them earlier on in that same Godot source code: https://github.com/godotengine/godot/blob/a586e860e5fc382dec4ad9a0bec72f7c6684f020/core/input/input_map.cpp#L292

RebindableActions can then serve as your "whitelist" of inputs. There's nothing stopping a user from adding built-in inputs if that's desireable, or removing custom ones.

You will need to add some behaviour to _refresh() that can detect and add new Inputs on project settings changes to auto-import those, at the very least for any RebindableActions that return false on "can_revert"

When I worked on this I just knew there had to be some way to get those actions from the Godot source code, but being fairly new to Godot myself I thought it would faster to just type them all out manually 😅. This is super helpful info and I'm happy that my hunch was correct! Next time I'll definitely go hunting in the source code for this type of thing.

Currently I'm filtering all of the built-ins with a defined map. I'll probably put a pin in the filtering part for now but I could revisit this before opening the PR if your auto-loading method feels like a better way to handle loading the built-ins.

Thanks for all the help!

from cogito.

Jealousmango avatar Jealousmango commented on August 25, 2024 1

Hi! I'd love to take a shot at implementing rebinding keys if this issue is still valid.

from cogito.

Phazorknight avatar Phazorknight commented on August 25, 2024 1

Yes, this is still valid. Would be awesome if you could take a shot.
Please make sure you pull from the latest /main/ as I've added another input map action on that one: interact2.

from cogito.

Jealousmango avatar Jealousmango commented on August 25, 2024 1

Good job. Can you also add toggle crouch/sprint?

This is an addition for #55 / Gameplay options. Not for rebindable inputs.

DashNothing did a clever remapping algorythm

I can't confirm how @Jealousmango approaches it, but COGITO comes with Nathan Hoad's InputHelper, which already includes functions for input remapping, so I think it's currently just about implementation.

Yeah, that's how I've approached the remapping. I used the methods mentioned on the InputHelper documentation to successfully rebind a key so now it's mostly working out the UI flow and cleaning up the content.

I have wondered about the default input map names. Populating the menu with actions like ui_accept feels clunky, but changing that to a more friendly name might be outside the scope of this issue.

from cogito.

Phazorknight avatar Phazorknight commented on August 25, 2024 1

Is there a simple way to exclude the godot default inputs? AFAIK they're never explicitly used in the scripts besides the default UI navigation and it's pretty rare that someone would want to rebind these.

Alterantively there might be away to replace the input map action names with readable ones with a simple dictionary or something, with falling back to the default string name if no entry is found. 🤔

from cogito.

generrosity avatar generrosity commented on August 25, 2024 1

Dictionary is how I've seen it - use the translation, or skip the key altogether. Or a dictionary of godot default inputs to skip I suppose?

Although equally you could "translate" by swapping underlines for space and camelcasing the text (having a static dictionary you have to update seperately isn't great, unless you are dynamically adding keybinds as part of dis/enable of chunks of movement code for devs - ie out of scope?)

from cogito.

Jealousmango avatar Jealousmango commented on August 25, 2024 1

Is there a simple way to exclude the godot default inputs? AFAIK they're never explicitly used in the scripts besides the default UI navigation and it's pretty rare that someone would want to rebind these.

Alterantively there might be away to replace the input map action names with readable ones with a simple dictionary or something, with falling back to the default string name if no entry is found. 🤔

I wasn't able to find a simple way to exclude the default inputs, but I haven't dug too deeply yet. One possible route would be creating a map of blacklisted actions and including all of the Godot default actions.

I think you're right about defining a dictionary for more readable names and falling back on the default string if one isn't provided. I'll be sure to include that. Thanks for the feedback!

from cogito.

FailSpy avatar FailSpy commented on August 25, 2024 1

I wasn't able to find a simple way to exclude the default inputs, but I haven't dug too deeply yet.

I've done some investigating in the past on this. And as far as I could find, there isn't a method available from GDScript that can tell you whether an Input mapping is built-in or not. There is, tantalisingly, in the Godot source code a function called 'get_builtins'
https://github.com/godotengine/godot/blob/a586e860e5fc382dec4ad9a0bec72f7c6684f020/core/input/input_map.cpp#L382
I was completely unable to find any reference to this that's accessible via GDScript.
If you're sufficiently motivated, you might be able to use GDNative to hook into that directly.

Personally wasn't willing to go that far, so I came up with this hack-y Resource instead (edited slightly to make more sense in context):

@tool
extends Resource
class_name RebindableActions

@export var inputs : Array[String]
static var custom_actions : Array[String]

func _init():
	inputs = get_actions().duplicate()
	ProjectSettings.property_list_changed.connect(_refresh)

static func _refresh():
	custom_actions = []
	var was_input = false
	var loaded_defaults = false
	for setting in ProjectSettings.get_property_list():
		var is_input = setting.name.begins_with('input/')
		if was_input and not is_input:
			loaded_defaults = true
		elif is_input and loaded_defaults:
			custom_actions.push_back(setting.name.split('/')[-1])
		was_input = is_input

func get_actions():
	if custom_actions:
		return custom_actions
	_refresh()
	return custom_actions

func _property_can_revert(property):
	if property == 'inputs':
		return get_actions() != inputs

func _property_get_revert(property):
	if property == 'inputs':
		return get_actions().duplicate()

This works because ProjectSettings will provide you the property list in the order it was loaded.
So it loads the built-in project settings first, and then loads any user configured project settings. Even if you add/remove inputs from the built-in actions, all built-in actions will stay bunched together. And of course, you can reverse _refresh()s behaviour to get all builtin actions.

This will work on export as well.

If you would rather just a full list to be updated of the built-in actions manually, you can find them earlier on in that same Godot source code:
https://github.com/godotengine/godot/blob/a586e860e5fc382dec4ad9a0bec72f7c6684f020/core/input/input_map.cpp#L292

RebindableActions can then serve as your "whitelist" of inputs. There's nothing stopping a user from adding built-in inputs if that's desireable, or removing custom ones.

You will need to add some behaviour to _refresh() that can detect and add new Inputs on project settings changes to auto-import those, at the very least for any RebindableActions that return false on "can_revert"

from cogito.

Phazorknight avatar Phazorknight commented on August 25, 2024 1

Should I open that against the new tabbed menu design from #55?

Yes, ideally. I've prepped a tab in it called "Bindings"

For Joypads I'd really love to dynamically change the button label to an icon for the correct device

There's already a script for this called DynamicInputIcon.gd, which depending on which device is detected, switches the icon accordingly. I'm sure you can easily adapt it to your needs, but be careful when editing it directly, as it's currently used for all UI prompts.
It only differentiates between generic gamepad and keyboard/mouse, but it can be extended to do gamepad-type specific icons.
I was planning to add this later using Kenney's new Input UI icons, once the rebinding is in place.

from cogito.

Phazorknight avatar Phazorknight commented on August 25, 2024

Looks promising! Thanks for the update.

from cogito.

generrosity avatar generrosity commented on August 25, 2024

that looks amazing!

Just incase its useful, DashNothing did a clever remapping algorythm, and they used a dictionary to translate the ui_key elements 👍

I've also just proposed tweaking the Options page to have the title and 'back' buttons always visible 😅 just baby changes from me currently

from cogito.

JouBqa avatar JouBqa commented on August 25, 2024

Good job. Can you also add toggle crouch/sprint?

from cogito.

Phazorknight avatar Phazorknight commented on August 25, 2024

Good job. Can you also add toggle crouch/sprint?

This is an addition for #55 / Gameplay options. Not for rebindable inputs.

DashNothing did a clever remapping algorythm

I can't confirm how @Jealousmango approaches it, but COGITO comes with Nathan Hoad's InputHelper, which already includes functions for input remapping, so I think it's currently just about implementation.

from cogito.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.