Jump to content
  • entries
    51
  • comments
    106
  • views
    28,346

Input with Action Sets!


reepblue

1,176 views

 Share

As you may have known, I've been dabbling with input methods for a while now using SDL2. Since then, I've learned how to do similar functions using the Leadwerks API. The goal was to make a inout system that's easily re-bindable, and allows for controllers to "just work". My first research of a goof system comes from a talk at Steam DevDays 2016 as they discuss how to allow integration with the Steam Controller. 

 

My thought was: "If I can create my own Action System, I can bind any controller with any API I want". The SDL experiments was a result of this, but they ended up being sloppy when you tried to merge the window polling from SDL into Leadwerks.

The next goal was to remove SDL2 out of the picture. I've created functions to allow reading and simulations of button presses with the Leadwerks Window class.

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool InputSystem::KeyHit(const int keycode)
{
	auto window = GetActiveEngineWindow();
	if (keycode < 7) return window->MouseHit(keycode);
	return window->KeyHit(keycode);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool InputSystem::KeyDown(const int keycode)
{
	auto window = GetActiveEngineWindow();
	if (window != NULL)
	{
		if (keycode < 7) return window->MouseDown(keycode);
		return window->KeyDown(keycode);
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void InputSystem::SimulateKeyHit(const char keycode)
{
	auto window = GetActiveEngineWindow();
	if (window != NULL)
	{
		if (keycode < 7)  window->mousehitstate[keycode] = true;
		window->keyhitstate[keycode] = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void InputSystem::SimulateKeyDown(const char keycode)
{
	auto window = GetActiveEngineWindow();
	if (window != NULL)
	{
		if (keycode < 7)  window->mousedownstate[keycode] = true;
		window->keydownstate[keycode] = true;
	}
}

The simulate keys are very important for controllers. for this case, we would trick the window class thinking a key was pressed on the keyboard. The only direct input we would need from the controller is the value analog sticks which I haven't touch as of yet.

 Using JSON, we can load and save our bindings in multiple Action Sets!

{
    "keyBindings": {
        "actionStates": {
            "Menu": {
                "selectActive": 1,
                "selectDown": 40,
                "selectLeft": 37,
                "selectRight": 39,
                "selectUp": 38
            },
            "Walking": {
                "crouch": 17,
                "firePrimary": 1,
                "fireSecondary": 2,
                "flashLight": 70,
                "interact": 69,
                "jump": 32,
                "moveBackward": 83,
                "moveForward": 87,
                "moveLeft": 65,
                "moveRight": 68,
                "reloadWeapon": 82
            }
        }
    }
}

You may want a key to do something different when your game is in a certain state. For this example, when the Active Action Set is set to "Menu", Only KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, and KEY_LBUTTON will work. You can still hover over your buttons with the mouse, but when it comes time to implement the controller for example, you'd just call GetActionHit(L"selectActive") to select the highlighted/active button. If the state is set to walking, then all those keys for Menu gets ignored in-favor of the walking commands. All keys/buttons are flushed between switching states!

Here's example code of this working. "Interact" gets ignored when "Menu" is set as the default action and vise-versa.

	while (window->KeyDown(KEY_END) == false and window->Closed() == false)
	{
		if (window->KeyHit(KEY_TILDE))
		{
			if (InputSystem::GetActiveActionSet() == L"Menu")
			{
				SetActionSet(L"Walking");
			}
			else
			{
				SetActionSet(L"Menu");
			}
		}

		// Under "Menu"
		if (GetActionHit(L"selectUp"))
		{
			DMsg("selectUp!");
		}

		// Under "Walking"
		if (GetActionHit(L"interact"))
		{
			DMsg("interact!");
		}
}

Only things I didn't implement as of yet is actual controller support and saving changes to the json file which might need to be game specific. I also want to wait until the UI is done before I decide how to do this.

As for controllers, we can use SteamInput, but what if your game isn't on Steam? You can try to implement XInput yourself if you want. I tried to add Controller support with SDL2, but people reported issues. And then, what about VR controllers? What matters right now is that we have room to add these features later on. All I need to do is use the GetActionHit/Down Commands and the rest doesn't matter.

  • Like 1
 Share

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...