diff --git a/ReadMe.md b/ReadMe.md index d98a21c..22814a4 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -5,21 +5,10 @@ This is a helper plugin library for [Unreal Engine 4](https://www.unrealengine.com) which makes a bunch of things better: -* UI Improvements - * FocusableButton: button which uses Hover style to highlight when it has focus (keyboard / gamepad) - * FocusablePanel: which ensure a widget is focussed when gamepad is activated so navigation is reliable - * Also remembers last focussed widget so it can be restored when used in context stacks - * FocusableUserWidget: A hack to allow UserWidgets to delegate their focus requests to a child item (required to make focus work reliably with compound widgets) - * InputImage: Image which will change itself to an image representing a button / key based on an input action - * (It changes dynamically when the input method changes e.g. when player moves a gamepad stick) - * Includes use of a UiTheme data asset which maps FKeys to Sprite images of buttons - * MenuStack/MenuBase: a context stack of widgets so you can easily create menu sequences, implement "back" navigation - * OptionWidgetBase: a widget which implements the "choose an item" concept but adapts between mouse and keyboard/gamepad - style navigation depending on what the currently used input method is -* Input Improvements - * Tracks last used input method (keyboard / mouse / gamepad) per player - * Events raised whenever a player uses a different input method (in game, and in UI) - (Actually reliable and not dependent on vagaries of input mappings / differences between UI and game input) +* [New Widgets](doc/Widgets.md) + * Focusable buttons, menu stacks, control prompts and more +* [Input events](doc/Input.md) + * Reliable notification when the player changes input method :heart: **[Support my work on Patreon!](https://www.patreon.com/stevestreeting)** @@ -103,112 +92,6 @@ if (GS) ``` -## Widgets - -Several custom widgets are supplied to assist with some common challenges: - -* [OptionWidgetBase](docs/OptionWidget.md) - - This widget base class adds "option switch" functionality, allowing a user to - select one of a number of options by moving through them in a linear list. - It handles both mouse and gamepad by automatically switching styles between - separate clickable arrows for mouse, and a unified left/right rocker style - for gamepads. Styleable in Blueprint subclasses. - -* [InputImage](docs/InputImage.md) - - This custom Image widget takes an Action or Axis name and will automatically - display the image for an associated bound control, based on the currently - active input method. Dynamically switches as input method changes. - -* [FocusableButton](docs/FocusableButton.md) - - A refined Button widget which raises focus events you can listen to, and - which can apply the "Hovered" style to itself when focused (very important - for gamepad navigation). - -* [FocusablePanel](docs/FocusablePanel.md) - - A Panel widget which can make sure that something is selected when a - gamepad is in use, and resists loss of focus. Has a default focus widget, - and also remembers the last focus widget if you switch away & back - without destroying it. - -* [MenuBase](docs/MenuBase.md) - - A specialised [FocusablePanel](docs/FocusablePanel.md) which adds the ability - to be part of a contextual [MenuStack](docs/FocusablePanel.md), and which - as it becomes the top of the stack can automatically grab focus, change game - pause state, alter input modes, and change the mouse pointer visibility - (all individually optional). - -* [MenuStack](docs/MenuStack.md) - - A container for and stack of [MenuBase](docs/MenuBase.md) instances, making it - easy to create multi-level on-screen menus with a simple "back" navigation. - - -# Additional Configuration - -## UiTheme - -Some features of this plugin such as InputImage need a `UUiTheme` asset, which -is just a Data Asset based on the `UUiTheme` class which references other -resources like button images. There is one in the Examples project as reference. - -### Create a UiTheme: - - -1. Click Add New > Miscellaneous > Data Asset -1. Select "UiTheme" as the class -1. Save the new asset with your chosen name - -### Create a Primary Asset Label - -UiThemes are a new kind of primary asset, loaded at runtime. To ensure this -asset is included when packaging, create a Primary Asset Label in the same folder: - -1. Click Add New > Miscellaneous > Data Asset -1. Select "Primary Asset Label" as the class -1. Name it however you like -1. Double-click to edit -1. Under "Explicit Assets", add an entry and pick the UiTheme you created above -1. Save the changes - -This just ensures that the packaging system knows to include your UiTheme, since -it won't be directly referenced by any other primary asset. - -### Create button sprite data - -The UiTheme wants to reference DataTables which contain links between the input -keys and button sprites. So the first job is to create the button sprites. - -The Example project includes some button sprites already; contained in a packed -sprite sheet. I created these using TexturePacker and imported into UE which created -the sprites, but you can create them however you like. However, we do require sprites -rather than plain textures. - -This means you must have the Paper2D plugin enabled in your project. - -### Linking input keys to button sprites -Once you have a set of button sprites, you need to create DataTables which map -input FKeys (which can be keys, or mouse buttons, or gamepad buttons / sticks) -to these sprites, so that for example InputImage can be told to display the action -"Fire", and then display either say the left mouse button or a gamepad trigger -depending on what's being used. - -Personally I did this using a CSV file for ease of use, for example: - -```csv -Name,Key,Sprite -Gamepad_LeftX,Gamepad_LeftX,"PaperSprite'/Game/Textures/UI/Sprites/Frames/XboxOne_Left_Stick'" -Gamepad_FaceButton_Bottom,Gamepad_FaceButton_Bottom,"PaperSprite'/Game/Textures/UI/Sprites/Frames/XboxOne_A'" -``` - -You should import this as a DataTable based on the KeySprite type. A separate -one is needed for keyboard / mouse and gamepad. Once you've created them, or -copied the ones from the examples, you should update the UiTheme asset you -created to point at these data tables. # License diff --git a/Resources/lastinput.png b/Resources/lastinput.png new file mode 100644 index 0000000..1760ab8 Binary files /dev/null and b/Resources/lastinput.png differ diff --git a/doc/Input.md b/doc/Input.md new file mode 100644 index 0000000..53b9565 --- /dev/null +++ b/doc/Input.md @@ -0,0 +1,56 @@ +# Input Helpers + +Unreal lacks an in-built way to determine the currently used input method by +a player, and ways to be notified when that changes. So I fixed that 😄 + +All these functions are available on "Steves Game Subsystem", which you can +get on a Blueprint like this: + +![Game Instance Subsystem](../Resources/gameinstance.png) + +Or in C++ like this: + +```c++ +#include "StevesUEHelpers.h" + +... +auto GS = GetStevesGameSubsystem(GetWorld()); +``` + + +## Getting the last input device for a player + +Blueprint: + +![Game Instance Subsystem](../Resources/lastinput.png) + +C++: + +```c++ +EInputMode Mode = GS->GetLastInputModeUsed(PlayerIndex); +``` + +## Listening for when player changes input device + +Blueprint: + +![Game Instance Subsystem](../Resources/bpexample.png) + +C++: + +```c++ +// Subscribe somewhere in your code +void AYourClass::ListenForInputModeChanges() +{ + auto GS = GetStevesGameSubsystem(GetWorld()); + GS->OnInputModeChanged.AddDynamic(this, &AYourClass::InputModeChanged); +} +``` + +```c++ +// This is your method which gets called +void AYourClass::InputModeChanged(int PlayerIndex, EInputMode NewMode) +{ + ... +} +``` diff --git a/doc/Widgets.md b/doc/Widgets.md new file mode 100644 index 0000000..e17f726 --- /dev/null +++ b/doc/Widgets.md @@ -0,0 +1,107 @@ +# Widgets + + +Several custom widgets are supplied to assist with some common challenges: + +* [OptionWidgetBase](OptionWidget.md) + + This widget base class adds "option switch" functionality, allowing a user to + select one of a number of options by moving through them in a linear list. + It handles both mouse and gamepad by automatically switching styles between + separate clickable arrows for mouse, and a unified left/right rocker style + for gamepads. Styleable in Blueprint subclasses. + +* [InputImage](InputImage.md) + + This custom Image widget takes an Action or Axis name and will automatically + display the image for an associated bound control, based on the currently + active input method. Dynamically switches as input method changes. + +* [FocusableButton](FocusableButton.md) + + A refined Button widget which raises focus events you can listen to, and + which can apply the "Hovered" style to itself when focused (very important + for gamepad navigation). + +* [FocusablePanel](FocusablePanel.md) + + A Panel widget which can make sure that something is selected when a + gamepad is in use, and resists loss of focus. Has a default focus widget, + and also remembers the last focus widget if you switch away & back + without destroying it. + +* [MenuBase](MenuBase.md) + + A specialised [FocusablePanel](FocusablePanel.md) which adds the ability + to be part of a contextual [MenuStack](MenuStack.md), and which + as it becomes the top of the stack can automatically grab focus, change game + pause state, alter input modes, and change the mouse pointer visibility + (all individually optional). + +* [MenuStack](MenuStack.md) + + A container for and stack of [MenuBase](MenuBase.md) instances, making it + easy to create multi-level on-screen menus with a simple "back" navigation. + + +# Additional Configuration + +## UiTheme + +Some features of this plugin such as InputImage need a `UUiTheme` asset, which +is just a Data Asset based on the `UUiTheme` class which references other +resources like button images. There is one in the Examples project as reference. + +### Create a UiTheme: + + +1. Click Add New > Miscellaneous > Data Asset +1. Select "UiTheme" as the class +1. Save the new asset with your chosen name + +### Create a Primary Asset Label + +UiThemes are a new kind of primary asset, loaded at runtime. To ensure this +asset is included when packaging, create a Primary Asset Label in the same folder: + +1. Click Add New > Miscellaneous > Data Asset +1. Select "Primary Asset Label" as the class +1. Name it however you like +1. Double-click to edit +1. Under "Explicit Assets", add an entry and pick the UiTheme you created above +1. Save the changes + +This just ensures that the packaging system knows to include your UiTheme, since +it won't be directly referenced by any other primary asset. + +### Create button sprite data + +The UiTheme wants to reference DataTables which contain links between the input +keys and button sprites. So the first job is to create the button sprites. + +The Example project includes some button sprites already; contained in a packed +sprite sheet. I created these using TexturePacker and imported into UE which created +the sprites, but you can create them however you like. However, we do require sprites +rather than plain textures. + +This means you must have the Paper2D plugin enabled in your project. + +### Linking input keys to button sprites +Once you have a set of button sprites, you need to create DataTables which map +input FKeys (which can be keys, or mouse buttons, or gamepad buttons / sticks) +to these sprites, so that for example InputImage can be told to display the action +"Fire", and then display either say the left mouse button or a gamepad trigger +depending on what's being used. + +Personally I did this using a CSV file for ease of use, for example: + +```csv +Name,Key,Sprite +Gamepad_LeftX,Gamepad_LeftX,"PaperSprite'/Game/Textures/UI/Sprites/Frames/XboxOne_Left_Stick'" +Gamepad_FaceButton_Bottom,Gamepad_FaceButton_Bottom,"PaperSprite'/Game/Textures/UI/Sprites/Frames/XboxOne_A'" +``` + +You should import this as a DataTable based on the KeySprite type. A separate +one is needed for keyboard / mouse and gamepad. Once you've created them, or +copied the ones from the examples, you should update the UiTheme asset you +created to point at these data tables.