UI 자동화를 위해 바인딩 기능 구현
- 유니티 에셋 인증 오류로 meta 재생성
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5a01adef66544c688fb903cd7f37b96
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Custom Binding Composite",
|
||||
"description": "Shows how to implement a custom composite binding."
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine.InputSystem.Editor;
|
||||
using UnityEngine.UIElements;
|
||||
#endif
|
||||
|
||||
// Let's say we want to have a composite that takes an axis and uses
|
||||
// it's value to multiply the length of a vector from a stick. This could
|
||||
// be used, for example, to have the right trigger on the gamepad act as
|
||||
// a strength multiplier on the value of the left stick.
|
||||
//
|
||||
// We start by creating a class that is based on InputBindingComposite<>.
|
||||
// The type we give it is the type of value that we will compute. In this
|
||||
// case, we will consume a Vector2 from the stick so that is the type
|
||||
// of value we return.
|
||||
//
|
||||
// NOTE: By advertising the type of value we return, we also allow the
|
||||
// input system to filter out our composite if it is not applicable
|
||||
// to a specific type of action. For example, if an action is set
|
||||
// to "Value" as its type and its "Control Type" is set to "Axis",
|
||||
// our composite will not be shown as our value type (Vector2) is
|
||||
// incompatible with the value type of Axis (float).
|
||||
//
|
||||
// We can customize the way display strings are formed for our composite by
|
||||
// annotating it with DisplayStringFormatAttribute. The string is simply a
|
||||
// list with elements to be replaced enclosed in curly braces. Everything
|
||||
// outside those will taken verbatim. The fragments inside the curly braces
|
||||
// in this case refer to the binding composite parts by name. Each such
|
||||
// instance is replaced with the display text for the corresponding
|
||||
// part binding.
|
||||
//
|
||||
// NOTE: We don't supply a name for the composite here. The default logic
|
||||
// will take the name of the type ("CustomComposite" in our case)
|
||||
// and snip off "Composite" if used as a suffix (which is the case
|
||||
// for us) and then use that as the name. So in our case, we are
|
||||
// registering a composite called "Custom" here.
|
||||
//
|
||||
// If we were to use our composite with the AddCompositeBinding API,
|
||||
// for example, it would look like this:
|
||||
//
|
||||
// myAction.AddCompositeBinding("Custom")
|
||||
// .With("Stick", "<Gamepad>/leftStick")
|
||||
// .With("Multiplier", "<Gamepad>/rightTrigger");
|
||||
[DisplayStringFormat("{multiplier}*{stick}")]
|
||||
public class CustomComposite : InputBindingComposite<Vector2>
|
||||
{
|
||||
// So, we need two parts for our composite. The part that delivers the stick
|
||||
// value and the part that delivers the axis multiplier. Note that each part
|
||||
// may be bound to multiple controls. The input system handles that for us
|
||||
// by giving us an integer identifier for each part that reads a single value
|
||||
// from however many controls are bound to the part.
|
||||
//
|
||||
// In our case, this could be used, for example, to bind the "multiplier" part
|
||||
// to both the left and the right trigger on the gamepad.
|
||||
|
||||
// To tell the input system of a "part" binding that we need for a composite,
|
||||
// we add a public field with an "int" type and annotated with an [InputControl]
|
||||
// attribute. We set the "layout" property on the attribute to tell the system
|
||||
// what kind of control we expect to be bound to the part.
|
||||
//
|
||||
// NOTE: These part binding need to be *public fields* for the input system
|
||||
// to find them.
|
||||
//
|
||||
// So this is introduces a part to the composite called "multiplier" and
|
||||
// expecting an "Axis" control. The value of the field will be set by the
|
||||
// input system. It will be some internal, unique numeric ID for the part
|
||||
// which we can then use with InputBindingCompositeContext.ReadValue to
|
||||
// read out the value of just that part.
|
||||
[InputControl(layout = "Axis")]
|
||||
public int multiplier;
|
||||
|
||||
// The other part we need is for the stick.
|
||||
//
|
||||
// NOTE: We could use "Stick" here but "Vector2" is a little less restrictive.
|
||||
[InputControl(layout = "Vector2")]
|
||||
public int stick;
|
||||
|
||||
// We may also expose "parameters" on our composite. These can be configured
|
||||
// graphically in the action editor and also through AddCompositeBinding.
|
||||
//
|
||||
// Let's say we want to allow the user to specify an additional scale factor
|
||||
// to apply to the value of "multiplier". We can do so by simply adding a
|
||||
// public field of type float. Any public field that is not annotated with
|
||||
// [InputControl] will be treated as a possible parameter.
|
||||
//
|
||||
// If we added a composite with AddCompositeBinding, we could configure the
|
||||
// parameter like so:
|
||||
//
|
||||
// myAction.AddCompositeBinding("Custom(scaleFactor=0.5)"
|
||||
// .With("Multiplier", "<Gamepad>/rightTrigger")
|
||||
// .With("Stick", "<Gamepad>/leftStick");
|
||||
public float scaleFactor = 1;
|
||||
|
||||
// Ok, so now we have all the configuration in place. The final piece we
|
||||
// need is the actual logic that reads input from "multiplier" and "stick"
|
||||
// and computes a final input value.
|
||||
//
|
||||
// We can do that by defining a ReadValue method which is the actual workhorse
|
||||
// for our composite.
|
||||
public override Vector2 ReadValue(ref InputBindingCompositeContext context)
|
||||
{
|
||||
// We read input from the parts we have by simply
|
||||
// supplying the part IDs that the input system has set up
|
||||
// for us to ReadValue.
|
||||
//
|
||||
// NOTE: Vector2 is a less straightforward than primitive value types
|
||||
// like int and float. If there are multiple controls bound to the
|
||||
// "stick" part, we need to tell the input system which one to pick.
|
||||
// We do so by giving it an IComparer. In this case, we choose
|
||||
// Vector2MagnitudeComparer to return the Vector2 with the greatest
|
||||
// length.
|
||||
var stickValue = context.ReadValue<Vector2, Vector2MagnitudeComparer>(stick);
|
||||
var multiplierValue = context.ReadValue<float>(multiplier);
|
||||
|
||||
// The rest is simple. We just scale the vector we read by the
|
||||
// multiple from the axis and apply our scale factor.
|
||||
return stickValue * (multiplierValue * scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Our custom composite is complete and fully functional. We could stop here and
|
||||
// call it a day. However, for the sake of demonstration, let's say we also want
|
||||
// to customize how the parameters for our composite are edited. We have "scaleFactor"
|
||||
// so let's say we want to replace the default float inspector with a slider.
|
||||
//
|
||||
// We can replace the default UI by simply deriving a custom InputParameterEditor
|
||||
// for our composite.
|
||||
#if UNITY_EDITOR
|
||||
public class CustomCompositeEditor : InputParameterEditor<CustomComposite>
|
||||
{
|
||||
public override void OnGUI()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnDrawVisualElements(VisualElement root, Action onChangedCallback)
|
||||
{
|
||||
var slider = new Slider(m_ScaleFactorLabel.text, 0, 2)
|
||||
{
|
||||
value = target.scaleFactor,
|
||||
showInputField = true
|
||||
};
|
||||
|
||||
// Note: For UIToolkit sliders, as of Feb 2022, we can't register for the mouse up event directly
|
||||
// on the slider because an element inside the slider captures the event. The workaround is to
|
||||
// register for the event on the slider container. This will be fixed in a future version of
|
||||
// UIToolkit.
|
||||
slider.Q("unity-drag-container").RegisterCallback<MouseUpEvent>(evt =>
|
||||
{
|
||||
target.scaleFactor = slider.value;
|
||||
onChangedCallback?.Invoke();
|
||||
});
|
||||
|
||||
root.Add(slider);
|
||||
}
|
||||
|
||||
private GUIContent m_ScaleFactorLabel = new GUIContent("Scale Factor");
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af7a21cd3a00840cfb1bcdab751adde7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
This sample shows how to implement and register a custom InputBindingComposite.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc5a49c66f7a54b89887a931c5ca4d86
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e6bd783c06264b3eba95763870116e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Custom Device",
|
||||
"description": "Shows how to implement a custom input device."
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
// The input system stores a chunk of memory for each device. What that
|
||||
// memory looks like we can determine ourselves. The easiest way is to just describe
|
||||
// it as a struct.
|
||||
//
|
||||
// Each chunk of memory is tagged with a "format" identifier in the form
|
||||
// of a "FourCC" (a 32-bit code comprised of four characters). Using
|
||||
// IInputStateTypeInfo we allow the system to get to the FourCC specific
|
||||
// to our struct.
|
||||
public struct CustomDeviceState : IInputStateTypeInfo
|
||||
{
|
||||
// We use "CUST" here as our custom format code. It can be anything really.
|
||||
// Should be sufficiently unique to identify our memory format, though.
|
||||
public FourCC format => new FourCC('C', 'U', 'S', 'T');
|
||||
|
||||
// Next we just define fields that store the state for our input device.
|
||||
// The only thing really interesting here is the [InputControl] attributes.
|
||||
// These automatically attach InputControls to the various memory bits that
|
||||
// we define.
|
||||
//
|
||||
// To get started, let's say that our device has a bitfield of buttons. Each
|
||||
// bit indicates whether a certain button is pressed or not. For the sake of
|
||||
// demonstration, let's say our device has 16 possible buttons. So, we define
|
||||
// a ushort field that contains the state of each possible button on the
|
||||
// device.
|
||||
//
|
||||
// On top of that, we need to tell the input system about each button. Both
|
||||
// what to call it and where to find it. The "name" property tells the input system
|
||||
// what to call the control; the "layout" property tells it what type of control
|
||||
// to create ("Button" in our case); and the "bit" property tells it which bit
|
||||
// in the bitfield corresponds to the button.
|
||||
//
|
||||
// We also tell the input system about "display names" here. These are names
|
||||
// that get displayed in the UI and such.
|
||||
[InputControl(name = "firstButton", layout = "Button", bit = 0, displayName = "First Button")]
|
||||
[InputControl(name = "secondButton", layout = "Button", bit = 1, displayName = "Second Button")]
|
||||
[InputControl(name = "thirdButton", layout = "Button", bit = 2, displayName = "Third Button")]
|
||||
public ushort buttons;
|
||||
|
||||
// Let's say our device also has a stick. However, the stick isn't stored
|
||||
// simply as two floats but as two unsigned bytes with the midpoint of each
|
||||
// axis located at value 127. We can simply define two consecutive byte
|
||||
// fields to represent the stick and annotate them like so.
|
||||
//
|
||||
// First, let's introduce stick control itself. This one is simple. We don't
|
||||
// yet worry about X and Y individually as the stick as whole will itself read the
|
||||
// component values from those controls.
|
||||
//
|
||||
// We need to set "format" here too as InputControlLayout will otherwise try to
|
||||
// infer the memory format from the field. As we put this attribute on "X", that
|
||||
// would come out as "BYTE" -- which we don't want. So we set it to "VC2B" (a Vector2
|
||||
// of bytes).
|
||||
[InputControl(name = "stick", format = "VC2B", layout = "Stick", displayName = "Main Stick")]
|
||||
// So that's what we need next. By default, both X and Y on "Stick" are floating-point
|
||||
// controls so here we need to individually configure them the way they work for our
|
||||
// stick.
|
||||
//
|
||||
// NOTE: We don't mention things as "layout" and such here. The reason is that we are
|
||||
// modifying a control already defined by "Stick". This means that we only need
|
||||
// to set the values that are different from what "Stick" stick itself already
|
||||
// configures. And since "Stick" configures both "X" and "Y" to be "Axis" controls,
|
||||
// we don't need to worry about that here.
|
||||
//
|
||||
// Using "format", we tell the controls how their data is stored. As bytes in our case
|
||||
// so we use "BYTE" (check the documentation for InputStateBlock for details on that).
|
||||
//
|
||||
// NOTE: We don't use "SBYT" (signed byte) here. Our values are not signed. They are
|
||||
// unsigned. It's just that our "resting" (i.e. mid) point is at 127 and not at 0.
|
||||
//
|
||||
// Also, we use "defaultState" to tell the system that in our case, setting the
|
||||
// memory to all zeroes will *NOT* result in a default value. Instead, if both x and y
|
||||
// are set to zero, the result will be Vector2(-1,-1).
|
||||
//
|
||||
// And then, using the various "normalize" parameters, we tell the input system how to
|
||||
// deal with the fact that our midpoint is located smack in the middle of our value range.
|
||||
// Using "normalize" (which is equivalent to "normalize=true") we instruct the control
|
||||
// to normalize values. Using "normalizeZero=0.5", we tell it that our midpoint is located
|
||||
// at 0.5 (AxisControl will convert the BYTE value to a [0..1] floating-point value with
|
||||
// 0=0 and 255=1) and that our lower limit is "normalizeMin=0" and our upper limit is
|
||||
// "normalizeMax=1". Put another way, it will map [0..1] to [-1..1].
|
||||
//
|
||||
// Finally, we also set "offset" here as this is already set by StickControl.X and
|
||||
// StickControl.Y -- which we inherit. Note that because we're looking at child controls
|
||||
// of the stick, the offset is relative to the stick, not relative to the beginning
|
||||
// of the state struct.
|
||||
[InputControl(name = "stick/x", defaultState = 127, format = "BYTE",
|
||||
offset = 0,
|
||||
parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")]
|
||||
public byte x;
|
||||
[InputControl(name = "stick/y", defaultState = 127, format = "BYTE",
|
||||
offset = 1,
|
||||
parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")]
|
||||
// The stick up/down/left/right buttons automatically use the state set up for X
|
||||
// and Y but they have their own parameters. Thus we need to also sync them to
|
||||
// the parameter settings we need for our BYTE setup.
|
||||
// NOTE: This is a shortcoming in the current layout system that cannot yet correctly
|
||||
// merge parameters. Will be fixed in a future version.
|
||||
[InputControl(name = "stick/up", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=2,clampMin=0,clampMax=1")]
|
||||
[InputControl(name = "stick/down", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=2,clampMin=-1,clampMax=0,invert")]
|
||||
[InputControl(name = "stick/left", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=2,clampMin=-1,clampMax=0,invert")]
|
||||
[InputControl(name = "stick/right", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=2,clampMin=0,clampMax=1")]
|
||||
public byte y;
|
||||
}
|
||||
|
||||
// Now that we have the state struct all sorted out, we have a way to lay out the memory
|
||||
// for our device and we have a way to map InputControls to pieces of that memory. What
|
||||
// we're still missing, however, is a way to represent our device as a whole within the
|
||||
// input system.
|
||||
//
|
||||
// For that, we start with a class derived from InputDevice. We could also base this
|
||||
// on something like Mouse or Gamepad in case our device is an instance of one of those
|
||||
// specific types but for this demonstration, let's assume our device is nothing like
|
||||
// those devices (if we base our devices on those layouts, we have to correctly map the
|
||||
// controls we inherit from those devices).
|
||||
//
|
||||
// Other than deriving from InputDevice, there are two other noteworthy things here.
|
||||
//
|
||||
// For one, we want to ensure that the call to InputSystem.RegisterLayout happens as
|
||||
// part of startup. Doing so ensures that the layout is known to the input system and
|
||||
// thus appears in the control picker. So we use [InitializeOnLoad] and [RuntimeInitializeOnLoadMethod]
|
||||
// here to ensure initialization in both the editor and the player.
|
||||
//
|
||||
// Also, we use the [InputControlLayout] attribute here. This attribute is optional on
|
||||
// types that are used as layouts in the input system. In our case, we have to use it
|
||||
// to tell the input system about the state struct we are using to define the memory
|
||||
// layout we are using and the controls tied to it.
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoad] // Call static class constructor in editor.
|
||||
#endif
|
||||
[InputControlLayout(stateType = typeof(CustomDeviceState))]
|
||||
public class CustomDevice : InputDevice, IInputUpdateCallbackReceiver
|
||||
{
|
||||
// [InitializeOnLoad] will ensure this gets called on every domain (re)load
|
||||
// in the editor.
|
||||
#if UNITY_EDITOR
|
||||
static CustomDevice()
|
||||
{
|
||||
// Trigger our RegisterLayout code in the editor.
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// In the player, [RuntimeInitializeOnLoadMethod] will make sure our
|
||||
// initialization code gets called during startup.
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Initialize()
|
||||
{
|
||||
// Register our device with the input system. We also register
|
||||
// a "device matcher" here. These are used when a device is discovered
|
||||
// by the input system. Each device is described by an InputDeviceDescription
|
||||
// and an InputDeviceMatcher can be used to match specific properties of such
|
||||
// a description. See the documentation of InputDeviceMatcher for more
|
||||
// details.
|
||||
//
|
||||
// NOTE: In case your device is more dynamic in nature and cannot have a single
|
||||
// static layout, there is also the possibility to build layouts on the fly.
|
||||
// Check out the API documentation for InputSystem.onFindLayoutForDevice and
|
||||
// for InputSystem.RegisterLayoutBuilder.
|
||||
InputSystem.RegisterLayout<CustomDevice>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface("Custom"));
|
||||
}
|
||||
|
||||
// While our device is fully functional at this point, we can refine the API
|
||||
// for it a little bit. One thing we can do is expose the controls for our
|
||||
// device directly. While anyone can look up our controls using strings, exposing
|
||||
// the controls as properties makes it simpler to work with the device in script.
|
||||
public ButtonControl firstButton { get; protected set; }
|
||||
public ButtonControl secondButton { get; protected set; }
|
||||
public ButtonControl thirdButton { get; protected set; }
|
||||
public StickControl stick { get; protected set; }
|
||||
|
||||
// FinishSetup is where our device setup is finalized. Here we can look up
|
||||
// the controls that have been created.
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
firstButton = GetChildControl<ButtonControl>("firstButton");
|
||||
secondButton = GetChildControl<ButtonControl>("secondButton");
|
||||
thirdButton = GetChildControl<ButtonControl>("thirdButton");
|
||||
stick = GetChildControl<StickControl>("stick");
|
||||
}
|
||||
|
||||
// We can also expose a '.current' getter equivalent to 'Gamepad.current'.
|
||||
// Whenever our device receives input, MakeCurrent() is called. So we can
|
||||
// simply update a '.current' getter based on that.
|
||||
public static CustomDevice current { get; private set; }
|
||||
public override void MakeCurrent()
|
||||
{
|
||||
base.MakeCurrent();
|
||||
current = this;
|
||||
}
|
||||
|
||||
// When one of our custom devices is removed, we want to make sure that if
|
||||
// it is the '.current' device, we null out '.current'.
|
||||
protected override void OnRemoved()
|
||||
{
|
||||
base.OnRemoved();
|
||||
if (current == this)
|
||||
current = null;
|
||||
}
|
||||
|
||||
// So, this is all great and nice. But we have one problem. No one is actually
|
||||
// creating an instance of our device yet. Which means that while we can bind
|
||||
// to controls on the device from actions all we want, at runtime we will never
|
||||
// actually receive input from our custom device. For that to happen, we need
|
||||
// to make sure that an instance of the device is created at some point.
|
||||
//
|
||||
// This one's a bit tricky. Because it really depends on how the device is
|
||||
// actually discovered in practice. In most real-world scenarios, there will be
|
||||
// some external API that notifies us when a device under its domain is added or
|
||||
// removed. In response, we would report a device being added (using
|
||||
// InputSystem.AddDevice(new InputDeviceDescription { ... }) or removed
|
||||
// (using DeviceRemoveEvent).
|
||||
//
|
||||
// In this demonstration, we don't have an external API to query. And we don't
|
||||
// really have another criteria by which to determine when a device of our custom
|
||||
// type should be added.
|
||||
//
|
||||
// So, let's fake it here. First, to create the device, we simply add a menu entry
|
||||
// in the editor. Means that in the player, this device will never be functional
|
||||
// but this serves as a demonstration only anyway.
|
||||
//
|
||||
// NOTE: Nothing of the following is necessary if you have a device that is
|
||||
// detected and sent input for by the Unity runtime itself, i.e. that is
|
||||
// picked up from the underlying platform APIs by Unity itself. In this
|
||||
// case, when your device is connected, Unity will automatically report an
|
||||
// InputDeviceDescription and all you have to do is make sure that the
|
||||
// InputDeviceMatcher you supply to RegisterLayout matches that description.
|
||||
//
|
||||
// Also, IInputUpdateCallbackReceiver and any other manual queuing of input
|
||||
// is unnecessary in that case as Unity will queue input for the device.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Tools/Custom Device Sample/Create Device")]
|
||||
private static void CreateDevice()
|
||||
{
|
||||
// This is the code that you would normally run at the point where
|
||||
// you discover devices of your custom type.
|
||||
InputSystem.AddDevice(new InputDeviceDescription
|
||||
{
|
||||
interfaceName = "Custom",
|
||||
product = "Sample Product"
|
||||
});
|
||||
}
|
||||
|
||||
// For completeness sake, let's also add code to remove one instance of our
|
||||
// custom device. Note that you can also manually remove the device from
|
||||
// the input debugger by right-clicking in and selecting "Remove Device".
|
||||
[MenuItem("Tools/Custom Device Sample/Remove Device")]
|
||||
private static void RemoveDevice()
|
||||
{
|
||||
var customDevice = InputSystem.devices.FirstOrDefault(x => x is CustomDevice);
|
||||
if (customDevice != null)
|
||||
InputSystem.RemoveDevice(customDevice);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// So the other part we need is to actually feed input for the device. Notice
|
||||
// that we already have the IInputUpdateCallbackReceiver interface on our class.
|
||||
// What this does is to add an OnUpdate method that will automatically be called
|
||||
// by the input system whenever it updates (actually, it will be called *before*
|
||||
// it updates, i.e. from the same point that InputSystem.onBeforeUpdate triggers).
|
||||
//
|
||||
// Here, we can feed input to our devices.
|
||||
//
|
||||
// NOTE: We don't have to do this here. InputSystem.QueueEvent can be called from
|
||||
// anywhere, including from threads. So if, for example, you have a background
|
||||
// thread polling input from your device, that's where you can also queue
|
||||
// its input events.
|
||||
//
|
||||
// Again, we don't have actual input to read here. So we just make up some stuff
|
||||
// here for the sake of demonstration. We just poll the keyboard
|
||||
//
|
||||
// NOTE: We poll the keyboard here as part of our OnUpdate. Remember, however,
|
||||
// that we run our OnUpdate from onBeforeUpdate, i.e. from where keyboard
|
||||
// input has not yet been processed. This means that our input will always
|
||||
// be one frame late. Plus, because we are polling the keyboard state here
|
||||
// on a frame-to-frame basis, we may miss inputs on the keyboard.
|
||||
//
|
||||
// NOTE: One thing we could instead is to actually use OnScreenControls that
|
||||
// represent the controls of our device and then use that to generate
|
||||
// input from actual human interaction.
|
||||
public void OnUpdate()
|
||||
{
|
||||
var keyboard = Keyboard.current;
|
||||
if (keyboard == null)
|
||||
return;
|
||||
|
||||
var state = new CustomDeviceState();
|
||||
|
||||
state.x = 127;
|
||||
state.y = 127;
|
||||
|
||||
// WARNING: It may be tempting to simply store some state related to updates
|
||||
// directly on the device. For example, let's say we want scale the
|
||||
// vector from WASD to a certain length which can be adjusted with
|
||||
// the scroll wheel of the mouse. It seems natural to just store the
|
||||
// current strength as a private field on CustomDevice.
|
||||
//
|
||||
// This will *NOT* work correctly. *All* input state must be stored
|
||||
// under the domain of the input system. InputDevices themselves
|
||||
// cannot private store their own separate state.
|
||||
//
|
||||
// What you *can* do however, is simply add fields your state struct
|
||||
// (CustomDeviceState in our case) that contain the state you want
|
||||
// to keep. It is not necessary to expose these as InputControls if
|
||||
// you don't want to.
|
||||
|
||||
// Map WASD to stick.
|
||||
var wPressed = keyboard.wKey.isPressed;
|
||||
var aPressed = keyboard.aKey.isPressed;
|
||||
var sPressed = keyboard.sKey.isPressed;
|
||||
var dPressed = keyboard.dKey.isPressed;
|
||||
|
||||
if (aPressed)
|
||||
state.x -= 127;
|
||||
if (dPressed)
|
||||
state.x += 127;
|
||||
if (wPressed)
|
||||
state.y += 127;
|
||||
if (sPressed)
|
||||
state.y -= 127;
|
||||
|
||||
// Map buttons to 1, 2, and 3.
|
||||
if (keyboard.digit1Key.isPressed)
|
||||
state.buttons |= 1 << 0;
|
||||
if (keyboard.digit2Key.isPressed)
|
||||
state.buttons |= 1 << 1;
|
||||
if (keyboard.digit3Key.isPressed)
|
||||
state.buttons |= 1 << 2;
|
||||
|
||||
// Finally, queue the event.
|
||||
// NOTE: We are replacing the current device state wholesale here. An alternative
|
||||
// would be to use QueueDeltaStateEvent to replace only select memory contents.
|
||||
InputSystem.QueueStateEvent(this, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c625211b3160b43799de4bd3f6ff4a54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
This sample demonstrates how to add author a custom device that plugs into the input system.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c783a24fcae4266ae1b3430c0dc4433
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ecbdcf62208440deb241b027d13487d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Custom Device Usages",
|
||||
"description": "Shows how to tag devices with custom usage strings that can be used, for example, to distinguish multiple instances of the same type of device (e.g. 'Gamepad') based on how the device is used (e.g. 'Player1' vs 'Player2' or 'LeftHand' vs 'RightHand')."
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
// Say you want to distinguish a device not only by its type (e.g. "PS4 Controller")
|
||||
// but also by the way it is used. This is a common scenario for VR controllers, for
|
||||
// example, where the same type of controller may be used once in the left hand and
|
||||
// once in the right hand. However, the need for distinguishing devices in a similar
|
||||
// manner can pop up in a variety of situations. For example, on Switch it is used
|
||||
// to distinguish the current orientation of the Joy-Con controller ("Horizontal" vs.
|
||||
// "Vertical") allowing you to take orientation into account when binding actions.
|
||||
//
|
||||
// The input system allows you to distinguish devices based on the "usages" assigned
|
||||
// to them. This is a generic mechanism that can be used to tag devices with arbitrary
|
||||
// custom usages.
|
||||
//
|
||||
// To make this more concrete, let's say we have a game where two players control
|
||||
// the game together each one using a gamepad but each receiving control over half
|
||||
// the actions in the game.
|
||||
//
|
||||
// NOTE: What we do here is only one way to achieve this kind of setup. We could
|
||||
// alternatively go and just create one control scheme for the first player
|
||||
// and one control scheme for the second one and then have two PlayerInputs
|
||||
// each using one of the two.
|
||||
//
|
||||
// So, what we'd like to do is tag one gamepad with "Player1" and one gamepad with
|
||||
// with "Player2". Then, in the actions we can set up a binding scheme specifically
|
||||
// for this style of play and bind actions such that are driven either from the
|
||||
// first player's gamepad or from the second player's gamepad (or from either).
|
||||
//
|
||||
// The first bit we need for this is to tell the input system that "Player1" and
|
||||
// "Player2" are usages that we intend to apply to gamepads. For this, we need
|
||||
// to modify the "Gamepad" layout. We do so by applying what's called a "layout
|
||||
// override". This needs to happen during initialization so here we go:
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoad]
|
||||
#endif
|
||||
public static class InitCustomDeviceUsages
|
||||
{
|
||||
static InitCustomDeviceUsages()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Initialize()
|
||||
{
|
||||
// Here we register the layout override with the system.
|
||||
//
|
||||
// The layout override is just a fragment of layout information
|
||||
// in JSON format.
|
||||
//
|
||||
// The key property here is "commonUsages" which tells the system
|
||||
// that "Player1" and "Player2" are possible usages applied to devices
|
||||
// using the given layout ("Gamepad" in our case).
|
||||
InputSystem.RegisterLayoutOverride(@"
|
||||
{
|
||||
""name"" : ""GamepadPlayerUsageTags"",
|
||||
""extend"" : ""Gamepad"",
|
||||
""commonUsages"" : [
|
||||
""Player1"", ""Player2""
|
||||
]
|
||||
}
|
||||
");
|
||||
|
||||
// Now that we have done this, you will see that when using the
|
||||
// control picker in the action editor, that there is now a
|
||||
// "Gamepad (Player1)" and "Gamepad (Player2)" entry underneath
|
||||
// "Gamepad". When you select those, you can bind specifically
|
||||
// to a gamepad with the respective device usage.
|
||||
//
|
||||
// Also, you will now be able to *require* a device with the
|
||||
// given usage in a control scheme. So, when creating a control
|
||||
// scheme representing the shared Player1+Player2 controls,
|
||||
// you can add one "Gamepad (Player1)" and one "Gamepad (Player2)"
|
||||
// requirement.
|
||||
//
|
||||
// You can see an example setup for how this would look in an
|
||||
// .inputactions file in the TwoPlayerControls.inputactions file
|
||||
// that is part of this sample.
|
||||
}
|
||||
}
|
||||
|
||||
// However, we are still missing a piece. At runtime, no gamepad will
|
||||
// receive either the "Player1" or the "Player2" usage assignment yet.
|
||||
// So none of the bindings will work yet.
|
||||
//
|
||||
// To assign the usage tags to the devices, we need to call
|
||||
// InputSystem.AddDeviceUsage or SetDeviceUsage.
|
||||
//
|
||||
// We could set this up any which way. As a demonstration, let's create
|
||||
// a MonoBehaviour here that simply associates a specific tag with a
|
||||
// specific gamepad index.
|
||||
//
|
||||
// In practice, you would probably want to do the assignment in a place
|
||||
// where you handle your player setup/joining.
|
||||
public class CustomDeviceUsages : MonoBehaviour
|
||||
{
|
||||
public int gamepadIndex;
|
||||
public string usageTag;
|
||||
|
||||
private Gamepad m_Gamepad;
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
if (gamepadIndex >= 0 && gamepadIndex < Gamepad.all.Count)
|
||||
{
|
||||
m_Gamepad = Gamepad.all[gamepadIndex];
|
||||
InputSystem.AddDeviceUsage(m_Gamepad, usageTag);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
// If we grabbed a gamepad and it's still added to the system,
|
||||
// remove the usage tag we added.
|
||||
if (m_Gamepad != null && m_Gamepad.added)
|
||||
InputSystem.RemoveDeviceUsage(m_Gamepad, usageTag);
|
||||
m_Gamepad = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f868c1ef5d55458da41f3690c690329
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
This sample shows how to tag devices with custom "usages" and how to bind actions specifically to devices with only those usages.
|
||||
|
||||
This is useful if you have the same type of device that appears in multiple different roles that you want to distinguish when binding to the device. For example, when a device may appear in both the left and the right hand or may appear held in different orientations (say, horizontal vs vertical).
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef23f8f685c7b463e89b764da9062d6a
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "TwoPlayerControls",
|
||||
"maps": [
|
||||
{
|
||||
"name": "TwoPlayers",
|
||||
"id": "0e22eb1c-8c6e-4cec-8364-2a9f0e3ef769",
|
||||
"actions": [
|
||||
{
|
||||
"name": "Move",
|
||||
"type": "Button",
|
||||
"id": "d35725fa-073a-4e1c-9052-2c45b8ef0b4c",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "Look",
|
||||
"type": "Button",
|
||||
"id": "249187b5-59c4-459f-84d0-731cb510c536",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"name": "",
|
||||
"id": "3e67c7ae-ca6c-4345-8f61-8df16fb87fec",
|
||||
"path": "<Gamepad>{Player1}/leftStick",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "TwoPlayers",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "46cadfba-140f-4895-8d9b-184da46b6010",
|
||||
"path": "<Gamepad>{Player2}/rightStick",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "TwoPlayers",
|
||||
"action": "Look",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controlSchemes": [
|
||||
{
|
||||
"name": "TwoPlayers",
|
||||
"bindingGroup": "TwoPlayers",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<Gamepad>{Player1}",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
},
|
||||
{
|
||||
"devicePath": "<Gamepad>{Player2}",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 917391a0a5f934196bf2608e2d195466
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
|
||||
generateWrapperCode: 0
|
||||
wrapperCodePath:
|
||||
wrapperClassName:
|
||||
wrapperCodeNamespace:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61dcbd3f75b1f4245adc2c94569f63c3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Gamepad Mouse Cursor",
|
||||
"description": "An example that shows how to use the gamepad for driving a mouse cursor for use with UIs."
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 237744bb87a5d144cb97babf7faefa00
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!850595691 &4890085278179872738
|
||||
LightingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: GamepadMouseCursorSampleSettings
|
||||
serializedVersion: 6
|
||||
m_GIWorkflowMode: 1
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_RealtimeEnvironmentLighting: 1
|
||||
m_BounceScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_UsingShadowmask: 1
|
||||
m_BakeBackend: 1
|
||||
m_LightmapMaxSize: 1024
|
||||
m_BakeResolution: 40
|
||||
m_Padding: 2
|
||||
m_LightmapCompression: 3
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAO: 0
|
||||
m_MixedBakeMode: 2
|
||||
m_LightmapsBakeMode: 1
|
||||
m_FilterMode: 1
|
||||
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_RealtimeResolution: 2
|
||||
m_ForceWhiteAlbedo: 0
|
||||
m_ForceUpdates: 0
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherRayCount: 256
|
||||
m_FinalGatherFiltering: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_PVRBounces: 2
|
||||
m_PVRMinBounces: 2
|
||||
m_PVREnvironmentImportanceSampling: 1
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_PVRTiledBaking: 0
|
||||
m_NumRaysToShootPerTexel: -1
|
||||
m_RespectSceneVisibilityWhenBakingGI: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52763d186c2eb48e696ae6ffb838dcc0
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 4890085278179872738
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "GamepadMouseCursorUIActions",
|
||||
"maps": [
|
||||
{
|
||||
"name": "UI",
|
||||
"id": "038d8f59-db9c-4389-83cd-7d41373518d5",
|
||||
"actions": [
|
||||
{
|
||||
"name": "Point",
|
||||
"type": "PassThrough",
|
||||
"id": "81d2dc29-f5a6-47c1-a543-ad954fda9fa6",
|
||||
"expectedControlType": "Vector2",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "Click",
|
||||
"type": "PassThrough",
|
||||
"id": "e5db52ef-8fc1-40c9-9799-57f91a7d7ade",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "Scroll",
|
||||
"type": "PassThrough",
|
||||
"id": "48228e6f-8fda-4ba2-b461-fdae78c58090",
|
||||
"expectedControlType": "Vector2",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"name": "",
|
||||
"id": "39af39e2-c75c-421e-84bf-1e4ff9793ab4",
|
||||
"path": "<VirtualMouse>/position",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "Point",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "f9d5a98e-68a3-44c8-a096-a1a30237ca81",
|
||||
"path": "<VirtualMouse>/leftButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "Click",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "7ffd960c-11ef-4fc0-b91b-4cbd02eba1b8",
|
||||
"path": "<VirtualMouse>/scroll",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "Scroll",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controlSchemes": []
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2da68a33934478429331becc93eca32
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
|
||||
generateWrapperCode: 0
|
||||
wrapperCodePath:
|
||||
wrapperClassName:
|
||||
wrapperCodeNamespace:
|
||||
@@ -0,0 +1,17 @@
|
||||
Rather than adapting UIs for gamepad navigation/use, an oft-used alternative is to instead keep having UIs operated by pointer input but to drive the pointer from gamepad input.
|
||||
|
||||
This sample demonstrates how to set this up with the input system.
|
||||
|
||||

|
||||
|
||||
1) It uses a custom [actions file](./GamepadMouseCursorUIActions.inputactions) for feeding input to the UI as the default actions are set up for gamepad navigation – something we don't want here as it would conflict with gamepad input being used for virtual cursor navigation.
|
||||
2) Note how `InputSystemUIInputModule` on the `EventSystem` GameObject is set up to reference actions from that file.
|
||||
3) The key component to take a look at is `VirtualMouseInput` on `Canvas >> Cursor`. The component is set up to receive input from the gamepad and translates it into motion on the `RectTransform` it is given. When going into play mode, you should also see a `Virtual Mouse` being added to the devices by the component.
|
||||
4) Note how the anchor position on the `RectTransform` is set to bottom left. This way the coordinate system responds to how mouse screen space operates.
|
||||
5) Note how `Cursor` is the last child of `Canvas` so that it draws on top of everything else.
|
||||
6) Note that `Raycast Target` on the `Image` component of the cursor is turned off to avoid raycasts from the mouse cursor hitting the cursor itself.
|
||||
7) Note that `Cursor Mode` on the `VirtualMouseInput` component is set to `Hardware Cursor If Available`. This will cause the component to look for a system mouse. If present, the system mouse is disabled and the system mouse cursor is warped to the virtual mouse position using `Mouse.WarpCursorPosition`. If no system mouse is present, `Cursor Graphic` will be used as a software mouse cursor.
|
||||
|
||||
# Licenses
|
||||
|
||||
The [cursor](./crosshair.png) used in the example is from [game-icons.net](https://game-icons.net/1x1/delapouite/crosshair.html) and made by [Delapuite](https://delapouite.com/) and released under the [CC BY 3.0 license](https://creativecommons.org/licenses/by/3.0/). It is used without modifications.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12394b570bf2e894890bf79b26b84620
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,114 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 137530feef62723499ce9521b344bc38
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 240 KiB |
@@ -0,0 +1,114 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c08500e75c1581d4daacd1a363ff46f6
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 1
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 1
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.unity.inputsystem/Samples~/IMEInput.meta
Normal file
8
Packages/com.unity.inputsystem/Samples~/IMEInput.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bb007822c994c64ab31f2a271cdfc23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,136 @@
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.IMEInput
|
||||
{
|
||||
/// <summary>
|
||||
/// An example IME Input Handler showing how IME input can be handled using
|
||||
/// input system provided events.
|
||||
/// </summary>
|
||||
/// <seealso cref="Keyboard.OnIMECompositionChanged"/>
|
||||
public class IMEInputHandler : MonoBehaviour
|
||||
{
|
||||
// Handles text passed via Keyboard.onTextInput event
|
||||
private void OnTextInput(char character)
|
||||
{
|
||||
AssertReferencesAreValid();
|
||||
|
||||
// Assumes the current IME composition text has been submitted
|
||||
if (m_ComposingViaIME)
|
||||
{
|
||||
m_CompositionField.text = string.Empty;
|
||||
m_ComposingViaIME = false;
|
||||
}
|
||||
|
||||
m_CurrentInput += character;
|
||||
m_TextField.text = m_CurrentInput;
|
||||
m_CombinedField.text = m_CurrentInput;
|
||||
}
|
||||
|
||||
// Handles text passed via Keyboard.onIMECompositionChange event
|
||||
private void OnIMECompositionChange(IMECompositionString text)
|
||||
{
|
||||
AssertReferencesAreValid();
|
||||
|
||||
// IME composition strings without length can also mean
|
||||
// the composition has been submitted
|
||||
if (text.Count == 0)
|
||||
{
|
||||
m_ComposingViaIME = false;
|
||||
m_CompositionField.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
var compositionText = text.ToString();
|
||||
m_ComposingViaIME = true;
|
||||
m_CompositionField.text = compositionText;
|
||||
|
||||
// The combined text contains both the current input and the current status of the composition
|
||||
m_CombinedField.text = string.Format("{0}{1}", m_CurrentInput, compositionText);
|
||||
}
|
||||
|
||||
// Adds keyboard and input field listeners
|
||||
private void OnEnable()
|
||||
{
|
||||
if (m_EventListenersAdded)
|
||||
return;
|
||||
|
||||
var keyboard = InputSystem.GetDevice<Keyboard>();
|
||||
if (keyboard is null)
|
||||
return;
|
||||
|
||||
keyboard.onTextInput += OnTextInput;
|
||||
keyboard.onIMECompositionChange += OnIMECompositionChange;
|
||||
m_InputField.onValueChanged.AddListener(OnValueChanged);
|
||||
|
||||
m_EventListenersAdded = true;
|
||||
}
|
||||
|
||||
// Removes keyboard and input field listeners
|
||||
private void OnDisable()
|
||||
{
|
||||
if (!m_EventListenersAdded)
|
||||
return;
|
||||
|
||||
var keyboard = InputSystem.GetDevice<Keyboard>();
|
||||
if (keyboard is null)
|
||||
return;
|
||||
|
||||
keyboard.onTextInput -= OnTextInput;
|
||||
keyboard.onIMECompositionChange -= OnIMECompositionChange;
|
||||
m_InputField.onValueChanged.RemoveListener(OnValueChanged);
|
||||
|
||||
Clear();
|
||||
|
||||
m_EventListenersAdded = false;
|
||||
}
|
||||
|
||||
// Called when the input field's text is changed
|
||||
private void OnValueChanged(string value)
|
||||
{
|
||||
AssertReferencesAreValid();
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
return;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Clears the text from all of the fields
|
||||
private void Clear()
|
||||
{
|
||||
m_CompositionField.text = string.Empty;
|
||||
m_TextField.text = string.Empty;
|
||||
m_CombinedField.text = string.Empty;
|
||||
|
||||
m_CurrentInput = string.Empty;
|
||||
m_ComposingViaIME = false;
|
||||
}
|
||||
|
||||
// Ensures all fields are correctly referenced
|
||||
private void AssertReferencesAreValid()
|
||||
{
|
||||
Debug.Assert(m_CompositionField != null, "Composition field cannot be null");
|
||||
Debug.Assert(m_TextField != null, "Text field field cannot be null");
|
||||
Debug.Assert(m_CombinedField != null, "Combined field field cannot be null");
|
||||
Debug.Assert(m_InputField != null, "Input field field cannot be null");
|
||||
}
|
||||
|
||||
[Tooltip("Text field intended to display the string received via OnIMECompositionChanged")]
|
||||
[SerializeField] private InputField m_CompositionField;
|
||||
|
||||
[Tooltip("Text field intended to display characters received via OnTextInput")]
|
||||
[SerializeField] private InputField m_TextField;
|
||||
|
||||
[Tooltip("Text field intended to display a combination of characters received by "
|
||||
+ "both the OnIMECompositionChanged & OnTextInput events")]
|
||||
[SerializeField] private InputField m_CombinedField;
|
||||
|
||||
[Tooltip("Text field intended for user input")]
|
||||
[SerializeField] private InputField m_InputField;
|
||||
|
||||
private bool m_EventListenersAdded = false;
|
||||
private bool m_ComposingViaIME = false;
|
||||
private string m_CurrentInput;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d6911df4ad59ac4fa65f35ceabfeb06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2829
Packages/com.unity.inputsystem/Samples~/IMEInput/IMEInputScene.unity
Normal file
2829
Packages/com.unity.inputsystem/Samples~/IMEInput/IMEInputScene.unity
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82c13dd0eb11e0d44adf707fdc51a350
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.unity.inputsystem/Samples~/InGameHints.meta
Normal file
8
Packages/com.unity.inputsystem/Samples~/InGameHints.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a91a0dc3ff86dc64890b3eafb9713d46
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "In-Game Hints",
|
||||
"description": "Demonstrates how to create in-game hints in the UI which reflect current bindings and active control schemes."
|
||||
}
|
||||
@@ -0,0 +1,624 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was auto-generated by com.unity.inputsystem:InputActionCodeGenerator
|
||||
// version 1.17.0
|
||||
// from Assets/Samples/InGameHints/InGameHintsActions.inputactions
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.InGameHints
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides programmatic access to <see cref="InputActionAsset" />, <see cref="InputActionMap" />, <see cref="InputAction" /> and <see cref="InputControlScheme" /> instances defined in asset "Assets/Samples/InGameHints/InGameHintsActions.inputactions".
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is source generated and any manual edits will be discarded if the associated asset is reimported or modified.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using namespace UnityEngine;
|
||||
/// using UnityEngine.InputSystem;
|
||||
///
|
||||
/// // Example of using an InputActionMap named "Player" from a UnityEngine.MonoBehaviour implementing callback interface.
|
||||
/// public class Example : MonoBehaviour, MyActions.IPlayerActions
|
||||
/// {
|
||||
/// private MyActions_Actions m_Actions; // Source code representation of asset.
|
||||
/// private MyActions_Actions.PlayerActions m_Player; // Source code representation of action map.
|
||||
///
|
||||
/// void Awake()
|
||||
/// {
|
||||
/// m_Actions = new MyActions_Actions(); // Create asset object.
|
||||
/// m_Player = m_Actions.Player; // Extract action map object.
|
||||
/// m_Player.AddCallbacks(this); // Register callback interface IPlayerActions.
|
||||
/// }
|
||||
///
|
||||
/// void OnDestroy()
|
||||
/// {
|
||||
/// m_Actions.Dispose(); // Destroy asset object.
|
||||
/// }
|
||||
///
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// m_Player.Enable(); // Enable all actions within map.
|
||||
/// }
|
||||
///
|
||||
/// void OnDisable()
|
||||
/// {
|
||||
/// m_Player.Disable(); // Disable all actions within map.
|
||||
/// }
|
||||
///
|
||||
/// #region Interface implementation of MyActions.IPlayerActions
|
||||
///
|
||||
/// // Invoked when "Move" action is either started, performed or canceled.
|
||||
/// public void OnMove(InputAction.CallbackContext context)
|
||||
/// {
|
||||
/// Debug.Log($"OnMove: {context.ReadValue<Vector2>()}");
|
||||
/// }
|
||||
///
|
||||
/// // Invoked when "Attack" action is either started, performed or canceled.
|
||||
/// public void OnAttack(InputAction.CallbackContext context)
|
||||
/// {
|
||||
/// Debug.Log($"OnAttack: {context.ReadValue<float>()}");
|
||||
/// }
|
||||
///
|
||||
/// #endregion
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public partial class @InGameHintsActions: IInputActionCollection2, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the underlying asset instance.
|
||||
/// </summary>
|
||||
public InputActionAsset asset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance.
|
||||
/// </summary>
|
||||
public @InGameHintsActions()
|
||||
{
|
||||
asset = InputActionAsset.FromJson(@"{
|
||||
""version"": 1,
|
||||
""name"": ""InGameHintsActions"",
|
||||
""maps"": [
|
||||
{
|
||||
""name"": ""Gameplay"",
|
||||
""id"": ""9af2d1b0-cc47-4300-854c-838acb4b168b"",
|
||||
""actions"": [
|
||||
{
|
||||
""name"": ""Move"",
|
||||
""type"": ""Value"",
|
||||
""id"": ""7e7492e7-1329-48bb-9fdc-279fd15473b4"",
|
||||
""expectedControlType"": ""Vector2"",
|
||||
""processors"": """",
|
||||
""interactions"": """",
|
||||
""initialStateCheck"": true
|
||||
},
|
||||
{
|
||||
""name"": ""Look"",
|
||||
""type"": ""Value"",
|
||||
""id"": ""981fecc2-2e7a-4d6a-b041-00b47626e0a1"",
|
||||
""expectedControlType"": ""Vector2"",
|
||||
""processors"": """",
|
||||
""interactions"": """",
|
||||
""initialStateCheck"": true
|
||||
},
|
||||
{
|
||||
""name"": ""PickUp"",
|
||||
""type"": ""Button"",
|
||||
""id"": ""5a59bbc2-a3d4-4cbd-88bb-01120d97dc69"",
|
||||
""expectedControlType"": """",
|
||||
""processors"": """",
|
||||
""interactions"": """",
|
||||
""initialStateCheck"": false
|
||||
},
|
||||
{
|
||||
""name"": ""Drop"",
|
||||
""type"": ""Button"",
|
||||
""id"": ""f37bbe7e-e241-443f-b868-c784e1219f25"",
|
||||
""expectedControlType"": """",
|
||||
""processors"": """",
|
||||
""interactions"": """",
|
||||
""initialStateCheck"": false
|
||||
},
|
||||
{
|
||||
""name"": ""Throw"",
|
||||
""type"": ""Button"",
|
||||
""id"": ""e450d71c-7cc5-4879-afb5-f3ed682d9824"",
|
||||
""expectedControlType"": """",
|
||||
""processors"": """",
|
||||
""interactions"": """",
|
||||
""initialStateCheck"": false
|
||||
}
|
||||
],
|
||||
""bindings"": [
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""5abc4d20-74bd-4f14-902f-2bd2cf59cc28"",
|
||||
""path"": ""<Gamepad>/leftStick"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Gamepad"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": ""WASD"",
|
||||
""id"": ""b16141b1-1611-44db-9576-5a004eb451f2"",
|
||||
""path"": ""2DVector"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": true,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": ""up"",
|
||||
""id"": ""2b20de3f-1ad8-4b42-b591-595edf60dced"",
|
||||
""path"": ""<Keyboard>/w"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": true
|
||||
},
|
||||
{
|
||||
""name"": ""down"",
|
||||
""id"": ""2f92eaa9-7f1f-4f42-9682-d105f7c2fc22"",
|
||||
""path"": ""<Keyboard>/s"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": true
|
||||
},
|
||||
{
|
||||
""name"": ""left"",
|
||||
""id"": ""3ba79a56-c5f8-4999-8203-bef8471f4bd8"",
|
||||
""path"": ""<Keyboard>/a"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": true
|
||||
},
|
||||
{
|
||||
""name"": ""right"",
|
||||
""id"": ""8d9acfe6-d844-4860-a151-01d6eb0dfb48"",
|
||||
""path"": ""<Keyboard>/d"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Move"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": true
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""b69cbeb7-a5bf-4df1-8965-17d944634cef"",
|
||||
""path"": ""<Gamepad>/rightStick"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Gamepad"",
|
||||
""action"": ""Look"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""b2ddefc9-49da-485d-be28-58e3ec3f8080"",
|
||||
""path"": ""<Mouse>/delta"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Look"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""92182492-7b62-47e0-94ad-53d9937d9905"",
|
||||
""path"": ""<Gamepad>/buttonSouth"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Gamepad"",
|
||||
""action"": ""PickUp"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""e20635aa-ffe7-4ed9-8802-96c039d26a8f"",
|
||||
""path"": ""<Keyboard>/q"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""PickUp"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""f5571cd9-1166-4ddc-9071-37dc597b1d4e"",
|
||||
""path"": ""<Gamepad>/buttonEast"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Gamepad"",
|
||||
""action"": ""Drop"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""950f549e-ec9c-4d03-aeff-f09ec4031d01"",
|
||||
""path"": ""<Keyboard>/e"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Drop"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""47d1952d-797b-4f5b-986c-654b8e479deb"",
|
||||
""path"": ""<Gamepad>/buttonSouth"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Gamepad"",
|
||||
""action"": ""Throw"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
},
|
||||
{
|
||||
""name"": """",
|
||||
""id"": ""02e2493d-1eb3-4334-9d25-92f2b5e21399"",
|
||||
""path"": ""<Keyboard>/space"",
|
||||
""interactions"": """",
|
||||
""processors"": """",
|
||||
""groups"": ""Keyboard&Mouse"",
|
||||
""action"": ""Throw"",
|
||||
""isComposite"": false,
|
||||
""isPartOfComposite"": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
""controlSchemes"": [
|
||||
{
|
||||
""name"": ""Gamepad"",
|
||||
""bindingGroup"": ""Gamepad"",
|
||||
""devices"": [
|
||||
{
|
||||
""devicePath"": ""<Gamepad>"",
|
||||
""isOptional"": false,
|
||||
""isOR"": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""name"": ""Keyboard&Mouse"",
|
||||
""bindingGroup"": ""Keyboard&Mouse"",
|
||||
""devices"": [
|
||||
{
|
||||
""devicePath"": ""<Keyboard>"",
|
||||
""isOptional"": false,
|
||||
""isOR"": false
|
||||
},
|
||||
{
|
||||
""devicePath"": ""<Mouse>"",
|
||||
""isOptional"": false,
|
||||
""isOR"": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}");
|
||||
// Gameplay
|
||||
m_Gameplay = asset.FindActionMap("Gameplay", throwIfNotFound: true);
|
||||
m_Gameplay_Move = m_Gameplay.FindAction("Move", throwIfNotFound: true);
|
||||
m_Gameplay_Look = m_Gameplay.FindAction("Look", throwIfNotFound: true);
|
||||
m_Gameplay_PickUp = m_Gameplay.FindAction("PickUp", throwIfNotFound: true);
|
||||
m_Gameplay_Drop = m_Gameplay.FindAction("Drop", throwIfNotFound: true);
|
||||
m_Gameplay_Throw = m_Gameplay.FindAction("Throw", throwIfNotFound: true);
|
||||
}
|
||||
|
||||
~@InGameHintsActions()
|
||||
{
|
||||
UnityEngine.Debug.Assert(!m_Gameplay.enabled, "This will cause a leak and performance issues, InGameHintsActions.Gameplay.Disable() has not been called.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys this asset and all associated <see cref="InputAction"/> instances.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
UnityEngine.Object.Destroy(asset);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.bindingMask" />
|
||||
public InputBinding? bindingMask
|
||||
{
|
||||
get => asset.bindingMask;
|
||||
set => asset.bindingMask = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.devices" />
|
||||
public ReadOnlyArray<InputDevice>? devices
|
||||
{
|
||||
get => asset.devices;
|
||||
set => asset.devices = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.controlSchemes" />
|
||||
public ReadOnlyArray<InputControlScheme> controlSchemes => asset.controlSchemes;
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.Contains(InputAction)" />
|
||||
public bool Contains(InputAction action)
|
||||
{
|
||||
return asset.Contains(action);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.GetEnumerator()" />
|
||||
public IEnumerator<InputAction> GetEnumerator()
|
||||
{
|
||||
return asset.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator()" />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.Enable()" />
|
||||
public void Enable()
|
||||
{
|
||||
asset.Enable();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.Disable()" />
|
||||
public void Disable()
|
||||
{
|
||||
asset.Disable();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.bindings" />
|
||||
public IEnumerable<InputBinding> bindings => asset.bindings;
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.FindAction(string, bool)" />
|
||||
public InputAction FindAction(string actionNameOrId, bool throwIfNotFound = false)
|
||||
{
|
||||
return asset.FindAction(actionNameOrId, throwIfNotFound);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionAsset.FindBinding(InputBinding, out InputAction)" />
|
||||
public int FindBinding(InputBinding bindingMask, out InputAction action)
|
||||
{
|
||||
return asset.FindBinding(bindingMask, out action);
|
||||
}
|
||||
|
||||
// Gameplay
|
||||
private readonly InputActionMap m_Gameplay;
|
||||
private List<IGameplayActions> m_GameplayActionsCallbackInterfaces = new List<IGameplayActions>();
|
||||
private readonly InputAction m_Gameplay_Move;
|
||||
private readonly InputAction m_Gameplay_Look;
|
||||
private readonly InputAction m_Gameplay_PickUp;
|
||||
private readonly InputAction m_Gameplay_Drop;
|
||||
private readonly InputAction m_Gameplay_Throw;
|
||||
/// <summary>
|
||||
/// Provides access to input actions defined in input action map "Gameplay".
|
||||
/// </summary>
|
||||
public struct GameplayActions
|
||||
{
|
||||
private @InGameHintsActions m_Wrapper;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new instance of the input action map wrapper class.
|
||||
/// </summary>
|
||||
public GameplayActions(@InGameHintsActions wrapper) { m_Wrapper = wrapper; }
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action "Gameplay/Move".
|
||||
/// </summary>
|
||||
public InputAction @Move => m_Wrapper.m_Gameplay_Move;
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action "Gameplay/Look".
|
||||
/// </summary>
|
||||
public InputAction @Look => m_Wrapper.m_Gameplay_Look;
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action "Gameplay/PickUp".
|
||||
/// </summary>
|
||||
public InputAction @PickUp => m_Wrapper.m_Gameplay_PickUp;
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action "Gameplay/Drop".
|
||||
/// </summary>
|
||||
public InputAction @Drop => m_Wrapper.m_Gameplay_Drop;
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action "Gameplay/Throw".
|
||||
/// </summary>
|
||||
public InputAction @Throw => m_Wrapper.m_Gameplay_Throw;
|
||||
/// <summary>
|
||||
/// Provides access to the underlying input action map instance.
|
||||
/// </summary>
|
||||
public InputActionMap Get() { return m_Wrapper.m_Gameplay; }
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionMap.Enable()" />
|
||||
public void Enable() { Get().Enable(); }
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionMap.Disable()" />
|
||||
public void Disable() { Get().Disable(); }
|
||||
/// <inheritdoc cref="UnityEngine.InputSystem.InputActionMap.enabled" />
|
||||
public bool enabled => Get().enabled;
|
||||
/// <summary>
|
||||
/// Implicitly converts an <see ref="GameplayActions" /> to an <see ref="InputActionMap" /> instance.
|
||||
/// </summary>
|
||||
public static implicit operator InputActionMap(GameplayActions set) { return set.Get(); }
|
||||
/// <summary>
|
||||
/// Adds <see cref="InputAction.started"/>, <see cref="InputAction.performed"/> and <see cref="InputAction.canceled"/> callbacks provided via <param cref="instance" /> on all input actions contained in this map.
|
||||
/// </summary>
|
||||
/// <param name="instance">Callback instance.</param>
|
||||
/// <remarks>
|
||||
/// If <paramref name="instance" /> is <c>null</c> or <paramref name="instance"/> have already been added this method does nothing.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GameplayActions" />
|
||||
public void AddCallbacks(IGameplayActions instance)
|
||||
{
|
||||
if (instance == null || m_Wrapper.m_GameplayActionsCallbackInterfaces.Contains(instance)) return;
|
||||
m_Wrapper.m_GameplayActionsCallbackInterfaces.Add(instance);
|
||||
@Move.started += instance.OnMove;
|
||||
@Move.performed += instance.OnMove;
|
||||
@Move.canceled += instance.OnMove;
|
||||
@Look.started += instance.OnLook;
|
||||
@Look.performed += instance.OnLook;
|
||||
@Look.canceled += instance.OnLook;
|
||||
@PickUp.started += instance.OnPickUp;
|
||||
@PickUp.performed += instance.OnPickUp;
|
||||
@PickUp.canceled += instance.OnPickUp;
|
||||
@Drop.started += instance.OnDrop;
|
||||
@Drop.performed += instance.OnDrop;
|
||||
@Drop.canceled += instance.OnDrop;
|
||||
@Throw.started += instance.OnThrow;
|
||||
@Throw.performed += instance.OnThrow;
|
||||
@Throw.canceled += instance.OnThrow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes <see cref="InputAction.started"/>, <see cref="InputAction.performed"/> and <see cref="InputAction.canceled"/> callbacks provided via <param cref="instance" /> on all input actions contained in this map.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Calling this method when <paramref name="instance" /> have not previously been registered has no side-effects.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GameplayActions" />
|
||||
private void UnregisterCallbacks(IGameplayActions instance)
|
||||
{
|
||||
@Move.started -= instance.OnMove;
|
||||
@Move.performed -= instance.OnMove;
|
||||
@Move.canceled -= instance.OnMove;
|
||||
@Look.started -= instance.OnLook;
|
||||
@Look.performed -= instance.OnLook;
|
||||
@Look.canceled -= instance.OnLook;
|
||||
@PickUp.started -= instance.OnPickUp;
|
||||
@PickUp.performed -= instance.OnPickUp;
|
||||
@PickUp.canceled -= instance.OnPickUp;
|
||||
@Drop.started -= instance.OnDrop;
|
||||
@Drop.performed -= instance.OnDrop;
|
||||
@Drop.canceled -= instance.OnDrop;
|
||||
@Throw.started -= instance.OnThrow;
|
||||
@Throw.performed -= instance.OnThrow;
|
||||
@Throw.canceled -= instance.OnThrow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters <param cref="instance" /> and unregisters all input action callbacks via <see cref="GameplayActions.UnregisterCallbacks(IGameplayActions)" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameplayActions.UnregisterCallbacks(IGameplayActions)" />
|
||||
public void RemoveCallbacks(IGameplayActions instance)
|
||||
{
|
||||
if (m_Wrapper.m_GameplayActionsCallbackInterfaces.Remove(instance))
|
||||
UnregisterCallbacks(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all existing callback instances and previously registered input action callbacks associated with them with callbacks provided via <param cref="instance" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <paramref name="instance" /> is <c>null</c>, calling this method will only unregister all existing callbacks but not register any new callbacks.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GameplayActions.AddCallbacks(IGameplayActions)" />
|
||||
/// <seealso cref="GameplayActions.RemoveCallbacks(IGameplayActions)" />
|
||||
/// <seealso cref="GameplayActions.UnregisterCallbacks(IGameplayActions)" />
|
||||
public void SetCallbacks(IGameplayActions instance)
|
||||
{
|
||||
foreach (var item in m_Wrapper.m_GameplayActionsCallbackInterfaces)
|
||||
UnregisterCallbacks(item);
|
||||
m_Wrapper.m_GameplayActionsCallbackInterfaces.Clear();
|
||||
AddCallbacks(instance);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides a new <see cref="GameplayActions" /> instance referencing this action map.
|
||||
/// </summary>
|
||||
public GameplayActions @Gameplay => new GameplayActions(this);
|
||||
private int m_GamepadSchemeIndex = -1;
|
||||
/// <summary>
|
||||
/// Provides access to the input control scheme.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputControlScheme" />
|
||||
public InputControlScheme GamepadScheme
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_GamepadSchemeIndex == -1) m_GamepadSchemeIndex = asset.FindControlSchemeIndex("Gamepad");
|
||||
return asset.controlSchemes[m_GamepadSchemeIndex];
|
||||
}
|
||||
}
|
||||
private int m_KeyboardMouseSchemeIndex = -1;
|
||||
/// <summary>
|
||||
/// Provides access to the input control scheme.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputControlScheme" />
|
||||
public InputControlScheme KeyboardMouseScheme
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_KeyboardMouseSchemeIndex == -1) m_KeyboardMouseSchemeIndex = asset.FindControlSchemeIndex("Keyboard&Mouse");
|
||||
return asset.controlSchemes[m_KeyboardMouseSchemeIndex];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Interface to implement callback methods for all input action callbacks associated with input actions defined by "Gameplay" which allows adding and removing callbacks.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameplayActions.AddCallbacks(IGameplayActions)" />
|
||||
/// <seealso cref="GameplayActions.RemoveCallbacks(IGameplayActions)" />
|
||||
public interface IGameplayActions
|
||||
{
|
||||
/// <summary>
|
||||
/// Method invoked when associated input action "Move" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
|
||||
void OnMove(InputAction.CallbackContext context);
|
||||
/// <summary>
|
||||
/// Method invoked when associated input action "Look" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
|
||||
void OnLook(InputAction.CallbackContext context);
|
||||
/// <summary>
|
||||
/// Method invoked when associated input action "PickUp" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
|
||||
void OnPickUp(InputAction.CallbackContext context);
|
||||
/// <summary>
|
||||
/// Method invoked when associated input action "Drop" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
|
||||
void OnDrop(InputAction.CallbackContext context);
|
||||
/// <summary>
|
||||
/// Method invoked when associated input action "Throw" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
|
||||
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
|
||||
void OnThrow(InputAction.CallbackContext context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30718f5974310d148a77ab1e420b1b83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"name": "InGameHintsActions",
|
||||
"maps": [
|
||||
{
|
||||
"name": "Gameplay",
|
||||
"id": "9af2d1b0-cc47-4300-854c-838acb4b168b",
|
||||
"actions": [
|
||||
{
|
||||
"name": "Move",
|
||||
"type": "Value",
|
||||
"id": "7e7492e7-1329-48bb-9fdc-279fd15473b4",
|
||||
"expectedControlType": "Vector2",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": true
|
||||
},
|
||||
{
|
||||
"name": "Look",
|
||||
"type": "Value",
|
||||
"id": "981fecc2-2e7a-4d6a-b041-00b47626e0a1",
|
||||
"expectedControlType": "Vector2",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": true
|
||||
},
|
||||
{
|
||||
"name": "PickUp",
|
||||
"type": "Button",
|
||||
"id": "5a59bbc2-a3d4-4cbd-88bb-01120d97dc69",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
},
|
||||
{
|
||||
"name": "Drop",
|
||||
"type": "Button",
|
||||
"id": "f37bbe7e-e241-443f-b868-c784e1219f25",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
},
|
||||
{
|
||||
"name": "Throw",
|
||||
"type": "Button",
|
||||
"id": "e450d71c-7cc5-4879-afb5-f3ed682d9824",
|
||||
"expectedControlType": "",
|
||||
"processors": "",
|
||||
"interactions": "",
|
||||
"initialStateCheck": false
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"name": "",
|
||||
"id": "5abc4d20-74bd-4f14-902f-2bd2cf59cc28",
|
||||
"path": "<Gamepad>/leftStick",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "WASD",
|
||||
"id": "b16141b1-1611-44db-9576-5a004eb451f2",
|
||||
"path": "2DVector",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Move",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "up",
|
||||
"id": "2b20de3f-1ad8-4b42-b591-595edf60dced",
|
||||
"path": "<Keyboard>/w",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "down",
|
||||
"id": "2f92eaa9-7f1f-4f42-9682-d105f7c2fc22",
|
||||
"path": "<Keyboard>/s",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "left",
|
||||
"id": "3ba79a56-c5f8-4999-8203-bef8471f4bd8",
|
||||
"path": "<Keyboard>/a",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "right",
|
||||
"id": "8d9acfe6-d844-4860-a151-01d6eb0dfb48",
|
||||
"path": "<Keyboard>/d",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Move",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "b69cbeb7-a5bf-4df1-8965-17d944634cef",
|
||||
"path": "<Gamepad>/rightStick",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "Look",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "b2ddefc9-49da-485d-be28-58e3ec3f8080",
|
||||
"path": "<Mouse>/delta",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Look",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "92182492-7b62-47e0-94ad-53d9937d9905",
|
||||
"path": "<Gamepad>/buttonSouth",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickUp",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "e20635aa-ffe7-4ed9-8802-96c039d26a8f",
|
||||
"path": "<Keyboard>/q",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "PickUp",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "f5571cd9-1166-4ddc-9071-37dc597b1d4e",
|
||||
"path": "<Gamepad>/buttonEast",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "Drop",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "950f549e-ec9c-4d03-aeff-f09ec4031d01",
|
||||
"path": "<Keyboard>/e",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Drop",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "47d1952d-797b-4f5b-986c-654b8e479deb",
|
||||
"path": "<Gamepad>/buttonSouth",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "Throw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "02e2493d-1eb3-4334-9d25-92f2b5e21399",
|
||||
"path": "<Keyboard>/space",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Keyboard&Mouse",
|
||||
"action": "Throw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controlSchemes": [
|
||||
{
|
||||
"name": "Gamepad",
|
||||
"bindingGroup": "Gamepad",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<Gamepad>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Keyboard&Mouse",
|
||||
"bindingGroup": "Keyboard&Mouse",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<Keyboard>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
},
|
||||
{
|
||||
"devicePath": "<Mouse>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bb4ca8e0c27ed041910c04f94cf6c7e
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
|
||||
generateWrapperCode: 1
|
||||
wrapperCodePath:
|
||||
wrapperClassName:
|
||||
wrapperCodeNamespace: UnityEngine.InputSystem.Samples.InGameHints
|
||||
@@ -0,0 +1,235 @@
|
||||
// This example demonstrates how to display text in the UI that involves action bindings.
|
||||
// When the player switches control schemes or customizes controls (the latter is not set up
|
||||
// in this example but if supported, would work with the existing code as is), text that
|
||||
// is shown to the user may be affected.
|
||||
//
|
||||
// In the example, the player is able to move around the world and look at objects (simple
|
||||
// cubes). When an object is in sight, the player can pick the object with a button. While
|
||||
// having an object picked up, the player can then either throw the object or drop it back
|
||||
// on the ground.
|
||||
//
|
||||
// Depending on the current context, we display hints in the UI that reflect the currently
|
||||
// active bindings.
|
||||
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.InGameHints
|
||||
{
|
||||
public class InGameHintsExample : MonoBehaviour
|
||||
{
|
||||
public Text helpText;
|
||||
public float moveSpeed;
|
||||
public float rotateSpeed;
|
||||
public float throwForce;
|
||||
public float pickupDistance;
|
||||
public float holdDistance;
|
||||
|
||||
private Vector2 m_Rotation;
|
||||
|
||||
private enum State
|
||||
{
|
||||
Wandering,
|
||||
ObjectInSights,
|
||||
ObjectPickedUp
|
||||
}
|
||||
|
||||
private PlayerInput m_PlayerInput;
|
||||
private State m_CurrentState;
|
||||
private Transform m_CurrentObject;
|
||||
private MaterialPropertyBlock m_PropertyBlock;
|
||||
|
||||
// Cached help texts so that we don't generate garbage all the time. Could even cache them by control
|
||||
// scheme to not create garbage during control scheme switching but we consider control scheme switches
|
||||
// rare so not worth the extra cost in complexity and memory.
|
||||
private string m_LookAtObjectHelpText;
|
||||
private string m_ThrowObjectHelpText;
|
||||
|
||||
private const string kDefaultHelpTextFormat = "Move close to one of the cubes and look at it to pick up";
|
||||
private const string kLookAtObjectHelpTextFormat = "Press {pickup} to pick object up";
|
||||
private const string kThrowObjectHelpTextFormat = "Press {throw} to throw object; press {drop} to drop object";
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
m_PlayerInput = GetComponent<PlayerInput>();
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
ChangeState(State.Wandering);
|
||||
}
|
||||
|
||||
// This is invoked by PlayerInput when the controls on the player change. If the player switches control
|
||||
// schemes or keyboard layouts, we end up here and re-generate our hints.
|
||||
public void OnControlsChanged()
|
||||
{
|
||||
UpdateUIHints(regenerate: true); // Force re-generation of our cached text strings to pick up new bindings.
|
||||
}
|
||||
|
||||
private int m_UpdateCount;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var move = m_PlayerInput.actions["move"].ReadValue<Vector2>();
|
||||
var look = m_PlayerInput.actions["look"].ReadValue<Vector2>();
|
||||
|
||||
Move(move);
|
||||
Look(look);
|
||||
|
||||
switch (m_CurrentState)
|
||||
{
|
||||
case State.Wandering:
|
||||
case State.ObjectInSights:
|
||||
// While looking around for an object to pick up, we constantly raycast into the world.
|
||||
if (Physics.Raycast(transform.position, transform.forward, out var hitInfo,
|
||||
pickupDistance) && !hitInfo.collider.gameObject.isStatic)
|
||||
{
|
||||
if (m_CurrentState != State.ObjectInSights)
|
||||
ChangeState(State.ObjectInSights);
|
||||
m_CurrentObject = hitInfo.transform;
|
||||
|
||||
// Set a custom color override on the object by installing our property block.
|
||||
if (m_PropertyBlock == null)
|
||||
{
|
||||
m_PropertyBlock = new MaterialPropertyBlock();
|
||||
m_PropertyBlock.SetColor("_Color", new Color(0.75f, 0, 0));
|
||||
}
|
||||
m_CurrentObject.GetComponent<MeshRenderer>().SetPropertyBlock(m_PropertyBlock);
|
||||
}
|
||||
else if (m_CurrentState != State.Wandering)
|
||||
{
|
||||
// No longer have object in sight.
|
||||
ChangeState(State.Wandering);
|
||||
|
||||
if (m_CurrentObject != null)
|
||||
{
|
||||
// Clear property block on renderer to get rid of our custom color override.
|
||||
m_CurrentObject.GetComponent<Renderer>().SetPropertyBlock(null);
|
||||
m_CurrentObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_PlayerInput.actions["pickup"].triggered && m_CurrentObject != null)
|
||||
{
|
||||
PickUp();
|
||||
ChangeState(State.ObjectPickedUp);
|
||||
}
|
||||
break;
|
||||
|
||||
case State.ObjectPickedUp:
|
||||
// If the player hits the throw button, throw the currently carried object.
|
||||
// For this example, let's call this good enough. In a real game, we'd want to avoid the raycast
|
||||
if (m_PlayerInput.actions["throw"].triggered)
|
||||
{
|
||||
Throw();
|
||||
ChangeState(State.Wandering);
|
||||
}
|
||||
else if (m_PlayerInput.actions["drop"].triggered)
|
||||
{
|
||||
Throw(drop: true);
|
||||
ChangeState(State.Wandering);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeState(State newState)
|
||||
{
|
||||
switch (newState)
|
||||
{
|
||||
case State.Wandering:
|
||||
break;
|
||||
case State.ObjectInSights:
|
||||
break;
|
||||
case State.ObjectPickedUp:
|
||||
break;
|
||||
}
|
||||
|
||||
m_CurrentState = newState;
|
||||
UpdateUIHints();
|
||||
}
|
||||
|
||||
private void UpdateUIHints(bool regenerate = false)
|
||||
{
|
||||
if (regenerate)
|
||||
{
|
||||
m_ThrowObjectHelpText = default;
|
||||
m_LookAtObjectHelpText = default;
|
||||
}
|
||||
|
||||
switch (m_CurrentState)
|
||||
{
|
||||
case State.ObjectInSights:
|
||||
if (m_LookAtObjectHelpText == null)
|
||||
m_LookAtObjectHelpText = kLookAtObjectHelpTextFormat.Replace("{pickup}",
|
||||
m_PlayerInput.actions["pickup"].GetBindingDisplayString());
|
||||
helpText.text = m_LookAtObjectHelpText;
|
||||
break;
|
||||
|
||||
case State.ObjectPickedUp:
|
||||
if (m_ThrowObjectHelpText == null)
|
||||
m_ThrowObjectHelpText = kThrowObjectHelpTextFormat
|
||||
.Replace("{throw}", m_PlayerInput.actions["throw"].GetBindingDisplayString())
|
||||
.Replace("{drop}", m_PlayerInput.actions["drop"].GetBindingDisplayString());
|
||||
helpText.text = m_ThrowObjectHelpText;
|
||||
break;
|
||||
|
||||
default:
|
||||
helpText.text = kDefaultHelpTextFormat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw or drop currently picked up object.
|
||||
private void Throw(bool drop = false)
|
||||
{
|
||||
// Unmount it.
|
||||
m_CurrentObject.parent = null;
|
||||
|
||||
// Turn physics back on.
|
||||
var rigidBody = m_CurrentObject.GetComponent<Rigidbody>();
|
||||
rigidBody.isKinematic = false;
|
||||
|
||||
// Apply force.
|
||||
if (!drop)
|
||||
rigidBody.AddForce(transform.forward * throwForce, ForceMode.Impulse);
|
||||
|
||||
m_CurrentObject = null;
|
||||
}
|
||||
|
||||
private void PickUp()
|
||||
{
|
||||
// Mount to our transform.
|
||||
m_CurrentObject.position = default;
|
||||
m_CurrentObject.SetParent(transform, worldPositionStays: false);
|
||||
m_CurrentObject.localPosition += new Vector3(0, 0, holdDistance);
|
||||
|
||||
// Remove color override.
|
||||
m_CurrentObject.GetComponent<Renderer>().SetPropertyBlock(null);
|
||||
|
||||
// We don't want the object to be governed by physics while we hold it so turn it into a
|
||||
// kinematics body.
|
||||
m_CurrentObject.GetComponent<Rigidbody>().isKinematic = true;
|
||||
}
|
||||
|
||||
private void Move(Vector2 direction)
|
||||
{
|
||||
if (direction.sqrMagnitude < 0.01)
|
||||
return;
|
||||
var scaledMoveSpeed = moveSpeed * Time.deltaTime;
|
||||
// For simplicity's sake, we just keep movement in a single plane here. Rotate
|
||||
// direction according to world Y rotation of player.
|
||||
var move = Quaternion.Euler(0, transform.eulerAngles.y, 0) * new Vector3(direction.x, 0, direction.y);
|
||||
transform.position += move * scaledMoveSpeed;
|
||||
}
|
||||
|
||||
private void Look(Vector2 rotate)
|
||||
{
|
||||
if (rotate.sqrMagnitude < 0.01)
|
||||
return;
|
||||
var scaledRotateSpeed = rotateSpeed * Time.deltaTime;
|
||||
m_Rotation.y += rotate.x * scaledRotateSpeed;
|
||||
m_Rotation.x = Mathf.Clamp(m_Rotation.x - rotate.y * scaledRotateSpeed, -89, 89);
|
||||
transform.localEulerAngles = m_Rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7157678e0953b24eb3ce108d2e34e37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be0c3658cdfdbf84f8cd833d30749454
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!850595691 &4890085278179872738
|
||||
LightingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: InGameHintsSampleSceneSettings
|
||||
serializedVersion: 6
|
||||
m_GIWorkflowMode: 1
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_RealtimeEnvironmentLighting: 1
|
||||
m_BounceScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_UsingShadowmask: 1
|
||||
m_BakeBackend: 1
|
||||
m_LightmapMaxSize: 1024
|
||||
m_BakeResolution: 40
|
||||
m_Padding: 2
|
||||
m_LightmapCompression: 3
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAO: 0
|
||||
m_MixedBakeMode: 2
|
||||
m_LightmapsBakeMode: 1
|
||||
m_FilterMode: 1
|
||||
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_RealtimeResolution: 2
|
||||
m_ForceWhiteAlbedo: 0
|
||||
m_ForceUpdates: 0
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherRayCount: 256
|
||||
m_FinalGatherFiltering: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_PVRBounces: 2
|
||||
m_PVRMinBounces: 2
|
||||
m_PVREnvironmentImportanceSampling: 1
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_PVRTiledBaking: 0
|
||||
m_NumRaysToShootPerTexel: -1
|
||||
m_RespectSceneVisibilityWhenBakingGI: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f70d6d5a2c3274240a20cfcec84e2bfe
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 4890085278179872738
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Unity.InputSystem.InGameHints",
|
||||
"references": [
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c",
|
||||
"GUID:2bafac87e7f4b9b418d9448d219b01ab"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 043547d79c83ab74e9bcfef914059964
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4bee43ed77c3411b8020daede403ff4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "InputDeviceTester",
|
||||
"description": "A scene containing UI to visualize the controls on various supported input devices."
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9858d4c8055fd45539a2e86388f7c5ba, type: 3}
|
||||
m_Name: InputDeviceTester
|
||||
m_EditorClassIdentifier:
|
||||
url: https://github.com/Unity-Technologies/InputSystem/releases/download/%VERSION%/InputDeviceTester-%VERSION%.unitypackage
|
||||
packageDeps:
|
||||
- com.unity.inputsystem
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c4222eac5d064f888b070a9269a9150
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e525c84b5e2457409c7226f6fa7b62b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Input Recorder",
|
||||
"description": "Shows how to capture and replay input events. Also useful by itself to debug input event sequences."
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
using System;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
////TODO: allow multiple device paths
|
||||
|
||||
////TODO: streaming support
|
||||
|
||||
////REVIEW: consider this for inclusion directly in the input system
|
||||
|
||||
namespace UnityEngine.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper component around <see cref="InputEventTrace"/> that provides an easy interface for recording input
|
||||
/// from a GameObject.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This component comes with a custom inspector that provides an easy recording and playback interface and also
|
||||
/// gives feedback about what has been recorded in the trace. The interface also allows saving and loading event
|
||||
/// traces.
|
||||
///
|
||||
/// Capturing can either be constrained by a <see cref="devicePath"/> or capture all input occuring in the system.
|
||||
///
|
||||
/// Replay by default will happen frame by frame (see <see cref="InputEventTrace.ReplayController.PlayAllFramesOneByOne"/>).
|
||||
/// If frame markers are disabled (see <see cref="recordFrames"/>), all events are queued right away in the first
|
||||
/// frame and replay completes immediately.
|
||||
///
|
||||
/// Other than frame-by-frame, replay can be made to happen in a way that tries to simulate the original input
|
||||
/// timing. To do so, enable <see cref="simulateOriginalTimingOnReplay"/>. This will make use of <see
|
||||
/// cref="InputEventTrace.ReplayController.PlayAllEventsAccordingToTimestamps"/>
|
||||
/// </remarks>
|
||||
public class InputRecorder : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether a capture is currently in progress.
|
||||
/// </summary>
|
||||
/// <value>True if a capture is in progress.</value>
|
||||
public bool captureIsRunning => m_EventTrace != null && m_EventTrace.enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a replay is currently being run by the component.
|
||||
/// </summary>
|
||||
/// <value>True if replay is running.</value>
|
||||
/// <seealso cref="replay"/>
|
||||
/// <seealso cref="StartReplay"/>
|
||||
/// <seealso cref="StopReplay"/>
|
||||
public bool replayIsRunning => m_ReplayController != null && !m_ReplayController.finished;
|
||||
|
||||
/// <summary>
|
||||
/// If true, input recording is started immediately when the component is enabled. Disabled by default.
|
||||
/// Call <see cref="StartCapture"/> to manually start capturing.
|
||||
/// </summary>
|
||||
/// <value>True if component will start recording automatically in <see cref="OnEnable"/>.</value>
|
||||
/// <seealso cref="StartCapture"/>
|
||||
public bool startRecordingWhenEnabled
|
||||
{
|
||||
get => m_StartRecordingWhenEnabled;
|
||||
set
|
||||
{
|
||||
m_StartRecordingWhenEnabled = value;
|
||||
if (value && enabled && !captureIsRunning)
|
||||
StartCapture();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total number of events captured.
|
||||
/// </summary>
|
||||
/// <value>Number of captured events.</value>
|
||||
public long eventCount => m_EventTrace?.eventCount ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of captured events.
|
||||
/// </summary>
|
||||
/// <value>Size of captured events in bytes.</value>
|
||||
public long totalEventSizeInBytes => m_EventTrace?.totalEventSizeInBytes ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of capture memory currently allocated.
|
||||
/// </summary>
|
||||
/// <value>Size of memory allocated for capture.</value>
|
||||
public long allocatedSizeInBytes => m_EventTrace?.allocatedSizeInBytes ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to record frame marker events when capturing input. Enabled by default.
|
||||
/// </summary>
|
||||
/// <value>True if frame marker events will be recorded.</value>
|
||||
/// <seealso cref="InputEventTrace.recordFrameMarkers"/>
|
||||
public bool recordFrames
|
||||
{
|
||||
get => m_RecordFrames;
|
||||
set
|
||||
{
|
||||
if (m_RecordFrames == value)
|
||||
return;
|
||||
m_RecordFrames = value;
|
||||
if (m_EventTrace != null)
|
||||
m_EventTrace.recordFrameMarkers = m_RecordFrames;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to record only <see cref="StateEvent"/>s and <see cref="DeltaStateEvent"/>s. Disabled by
|
||||
/// default.
|
||||
/// </summary>
|
||||
/// <value>True if anything but state events should be ignored.</value>
|
||||
public bool recordStateEventsOnly
|
||||
{
|
||||
get => m_RecordStateEventsOnly;
|
||||
set => m_RecordStateEventsOnly = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path that constrains the devices to record from.
|
||||
/// </summary>
|
||||
/// <value>Input control path to match devices or null/empty.</value>
|
||||
/// <remarks>
|
||||
/// By default, this is not set. Meaning that input will be recorded from all devices. By setting this property
|
||||
/// to a path, only events for devices that match the given path (as dictated by <see cref="InputControlPath.Matches"/>)
|
||||
/// will be recorded from.
|
||||
///
|
||||
/// By setting this property to the exact path of a device at runtime, recording can be restricted to just that
|
||||
/// device.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlPath"/>
|
||||
/// <seealso cref="InputControlPath.Matches"/>
|
||||
public string devicePath
|
||||
{
|
||||
get => m_DevicePath;
|
||||
set => m_DevicePath = value;
|
||||
}
|
||||
|
||||
public string recordButtonPath
|
||||
{
|
||||
get => m_RecordButtonPath;
|
||||
set
|
||||
{
|
||||
m_RecordButtonPath = value;
|
||||
HookOnInputEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public string playButtonPath
|
||||
{
|
||||
get => m_PlayButtonPath;
|
||||
set
|
||||
{
|
||||
m_PlayButtonPath = value;
|
||||
HookOnInputEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The underlying event trace that contains the captured input events.
|
||||
/// </summary>
|
||||
/// <value>Underlying event trace.</value>
|
||||
/// <remarks>
|
||||
/// This will be null if no capture is currently associated with the recorder.
|
||||
/// </remarks>
|
||||
public InputEventTrace capture => m_EventTrace;
|
||||
|
||||
/// <summary>
|
||||
/// The replay controller for when a replay is running.
|
||||
/// </summary>
|
||||
/// <value>Replay controller for the event trace while replay is running.</value>
|
||||
/// <seealso cref="replayIsRunning"/>
|
||||
/// <seealso cref="StartReplay"/>
|
||||
public InputEventTrace.ReplayController replay => m_ReplayController;
|
||||
|
||||
public int replayPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ReplayController != null)
|
||||
return m_ReplayController.position;
|
||||
return 0;
|
||||
}
|
||||
////TODO: allow setting replay position
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a replay should create new devices or replay recorded events as is. Disabled by default.
|
||||
/// </summary>
|
||||
/// <value>True if replay should temporary create new devices.</value>
|
||||
/// <seealso cref="InputEventTrace.ReplayController.WithAllDevicesMappedToNewInstances"/>
|
||||
public bool replayOnNewDevices
|
||||
{
|
||||
get => m_ReplayOnNewDevices;
|
||||
set => m_ReplayOnNewDevices = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to attempt to re-create the original event timing when replaying events. Disabled by default.
|
||||
/// </summary>
|
||||
/// <value>If true, events are queued based on their timestamp rather than based on their recorded frames (if any).</value>
|
||||
/// <seealso cref="InputEventTrace.ReplayController.PlayAllEventsAccordingToTimestamps"/>
|
||||
public bool simulateOriginalTimingOnReplay
|
||||
{
|
||||
get => m_SimulateOriginalTimingOnReplay;
|
||||
set => m_SimulateOriginalTimingOnReplay = value;
|
||||
}
|
||||
|
||||
public ChangeEvent changeEvent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ChangeEvent == null)
|
||||
m_ChangeEvent = new ChangeEvent();
|
||||
return m_ChangeEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartCapture()
|
||||
{
|
||||
if (m_EventTrace != null && m_EventTrace.enabled)
|
||||
return;
|
||||
|
||||
CreateEventTrace();
|
||||
m_EventTrace.Enable();
|
||||
m_ChangeEvent?.Invoke(Change.CaptureStarted);
|
||||
}
|
||||
|
||||
public void StopCapture()
|
||||
{
|
||||
if (m_EventTrace != null && m_EventTrace.enabled)
|
||||
{
|
||||
m_EventTrace.Disable();
|
||||
m_ChangeEvent?.Invoke(Change.CaptureStopped);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartReplay()
|
||||
{
|
||||
if (m_EventTrace == null)
|
||||
return;
|
||||
|
||||
if (replayIsRunning && replay.paused)
|
||||
{
|
||||
replay.paused = false;
|
||||
return;
|
||||
}
|
||||
|
||||
StopCapture();
|
||||
|
||||
// Configure replay controller.
|
||||
m_ReplayController = m_EventTrace.Replay()
|
||||
.OnFinished(StopReplay)
|
||||
.OnEvent(_ => m_ChangeEvent?.Invoke(Change.EventPlayed));
|
||||
if (m_ReplayOnNewDevices)
|
||||
m_ReplayController.WithAllDevicesMappedToNewInstances();
|
||||
|
||||
// Start replay.
|
||||
if (m_SimulateOriginalTimingOnReplay)
|
||||
m_ReplayController.PlayAllEventsAccordingToTimestamps();
|
||||
else
|
||||
m_ReplayController.PlayAllFramesOneByOne();
|
||||
|
||||
m_ChangeEvent?.Invoke(Change.ReplayStarted);
|
||||
}
|
||||
|
||||
public void StopReplay()
|
||||
{
|
||||
if (m_ReplayController != null)
|
||||
{
|
||||
m_ReplayController.Dispose();
|
||||
m_ReplayController = null;
|
||||
m_ChangeEvent?.Invoke(Change.ReplayStopped);
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseReplay()
|
||||
{
|
||||
if (m_ReplayController != null)
|
||||
m_ReplayController.paused = true;
|
||||
}
|
||||
|
||||
public void ClearCapture()
|
||||
{
|
||||
m_EventTrace?.Clear();
|
||||
}
|
||||
|
||||
public void LoadCaptureFromFile(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
throw new ArgumentNullException(nameof(fileName));
|
||||
|
||||
CreateEventTrace();
|
||||
m_EventTrace.ReadFrom(fileName);
|
||||
}
|
||||
|
||||
public void SaveCaptureToFile(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
throw new ArgumentNullException(nameof(fileName));
|
||||
m_EventTrace?.WriteTo(fileName);
|
||||
}
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
// Hook InputSystem.onEvent before the event trace does.
|
||||
HookOnInputEvent();
|
||||
|
||||
if (m_StartRecordingWhenEnabled)
|
||||
StartCapture();
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
StopCapture();
|
||||
StopReplay();
|
||||
UnhookOnInputEvent();
|
||||
}
|
||||
|
||||
protected void OnDestroy()
|
||||
{
|
||||
m_ReplayController?.Dispose();
|
||||
m_ReplayController = null;
|
||||
m_EventTrace?.Dispose();
|
||||
m_EventTrace = null;
|
||||
}
|
||||
|
||||
private bool OnFilterInputEvent(InputEventPtr eventPtr, InputDevice device)
|
||||
{
|
||||
// Filter out non-state events, if enabled.
|
||||
if (m_RecordStateEventsOnly && !eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>())
|
||||
return false;
|
||||
|
||||
// Match device path, if set.
|
||||
if (string.IsNullOrEmpty(m_DevicePath) || device == null)
|
||||
return true;
|
||||
return InputControlPath.MatchesPrefix(m_DevicePath, device);
|
||||
}
|
||||
|
||||
private void OnEventRecorded(InputEventPtr eventPtr)
|
||||
{
|
||||
m_ChangeEvent?.Invoke(Change.EventCaptured);
|
||||
}
|
||||
|
||||
private void OnInputEvent(InputEventPtr eventPtr, InputDevice device)
|
||||
{
|
||||
if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>())
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(m_PlayButtonPath))
|
||||
{
|
||||
var playControl = InputControlPath.TryFindControl(device, m_PlayButtonPath) as InputControl<float>;
|
||||
if (playControl != null && playControl.ReadValueFromEvent(eventPtr) >= InputSystem.settings.defaultButtonPressPoint)
|
||||
{
|
||||
if (replayIsRunning)
|
||||
StopReplay();
|
||||
else
|
||||
StartReplay();
|
||||
|
||||
eventPtr.handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(m_RecordButtonPath))
|
||||
{
|
||||
var recordControl = InputControlPath.TryFindControl(device, m_RecordButtonPath) as InputControl<float>;
|
||||
if (recordControl != null && recordControl.ReadValueFromEvent(eventPtr) >= InputSystem.settings.defaultButtonPressPoint)
|
||||
{
|
||||
if (captureIsRunning)
|
||||
StopCapture();
|
||||
else
|
||||
StartCapture();
|
||||
|
||||
eventPtr.handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected void OnValidate()
|
||||
{
|
||||
if (m_EventTrace != null)
|
||||
m_EventTrace.recordFrameMarkers = m_RecordFrames;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[SerializeField] private bool m_StartRecordingWhenEnabled = false;
|
||||
|
||||
[Tooltip("If enabled, additional events will be recorded that demarcate frame boundaries. When replaying, this allows "
|
||||
+ "spacing out input events across frames corresponding to the original distribution across frames when input was "
|
||||
+ "recorded. If this is turned off, all input events will be queued in one block when replaying the trace.")]
|
||||
[SerializeField] private bool m_RecordFrames = true;
|
||||
|
||||
[Tooltip("If enabled, new devices will be created for captured events when replaying them. If disabled (default), "
|
||||
+ "events will be queued as is and thus keep their original device ID.")]
|
||||
[SerializeField] private bool m_ReplayOnNewDevices;
|
||||
|
||||
[Tooltip("If enabled, the system will try to simulate the original event timing on replay. This differs from replaying frame "
|
||||
+ "by frame in that replay will try to compensate for differences in frame timings and redistribute events to frames that "
|
||||
+ "more closely match the original timing. Note that this is not perfect and will not necessarily create a 1:1 match.")]
|
||||
[SerializeField] private bool m_SimulateOriginalTimingOnReplay;
|
||||
|
||||
[Tooltip("If enabled, only StateEvents and DeltaStateEvents will be captured.")]
|
||||
[SerializeField] private bool m_RecordStateEventsOnly;
|
||||
|
||||
[SerializeField] private int m_CaptureMemoryDefaultSize = 2 * 1024 * 1024;
|
||||
[SerializeField] private int m_CaptureMemoryMaxSize = 10 * 1024 * 1024;
|
||||
|
||||
[SerializeField]
|
||||
[InputControl(layout = "InputDevice")]
|
||||
private string m_DevicePath;
|
||||
|
||||
[SerializeField]
|
||||
[InputControl(layout = "Button")]
|
||||
private string m_RecordButtonPath;
|
||||
|
||||
[SerializeField]
|
||||
[InputControl(layout = "Button")]
|
||||
private string m_PlayButtonPath;
|
||||
|
||||
[SerializeField] private ChangeEvent m_ChangeEvent;
|
||||
|
||||
private Action<InputEventPtr, InputDevice> m_OnInputEventDelegate;
|
||||
private InputEventTrace m_EventTrace;
|
||||
private InputEventTrace.ReplayController m_ReplayController;
|
||||
|
||||
private void CreateEventTrace()
|
||||
{
|
||||
////FIXME: remaining configuration should come through, too, if changed after the fact
|
||||
if (m_EventTrace == null || m_EventTrace.maxSizeInBytes == 0)
|
||||
{
|
||||
m_EventTrace?.Dispose();
|
||||
m_EventTrace = new InputEventTrace(m_CaptureMemoryDefaultSize, growBuffer: true, maxBufferSizeInBytes: m_CaptureMemoryMaxSize);
|
||||
}
|
||||
|
||||
m_EventTrace.recordFrameMarkers = m_RecordFrames;
|
||||
m_EventTrace.onFilterEvent += OnFilterInputEvent;
|
||||
m_EventTrace.onEvent += OnEventRecorded;
|
||||
}
|
||||
|
||||
private void HookOnInputEvent()
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_PlayButtonPath) && string.IsNullOrEmpty(m_RecordButtonPath))
|
||||
{
|
||||
UnhookOnInputEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_OnInputEventDelegate == null)
|
||||
m_OnInputEventDelegate = OnInputEvent;
|
||||
InputSystem.onEvent += m_OnInputEventDelegate;
|
||||
}
|
||||
|
||||
private void UnhookOnInputEvent()
|
||||
{
|
||||
if (m_OnInputEventDelegate != null)
|
||||
InputSystem.onEvent -= m_OnInputEventDelegate;
|
||||
}
|
||||
|
||||
public enum Change
|
||||
{
|
||||
None,
|
||||
EventCaptured,
|
||||
EventPlayed,
|
||||
CaptureStarted,
|
||||
CaptureStopped,
|
||||
ReplayStarted,
|
||||
ReplayStopped,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ChangeEvent : UnityEvent<Change>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d35d5308cbb1fcd479dbf0c516db2aa7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,227 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine.Events;
|
||||
|
||||
////TODO: add ability to inspect contents of event traces in a separate window
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom inspector for <see cref="InputRecorder"/>. Adds UI elements to store captures in files, to load them from
|
||||
/// there, and to initiate replays from within the editor. It also shows information for when captures or replays are
|
||||
/// in progress.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(InputRecorder))]
|
||||
internal class InputRecorderInspector : UnityEditor.Editor
|
||||
{
|
||||
protected void OnEnable()
|
||||
{
|
||||
m_DevicePathProperty = serializedObject.FindProperty("m_DevicePath");
|
||||
m_RecordButtonPath = serializedObject.FindProperty("m_RecordButtonPath");
|
||||
m_PlayButtonPathProperty = serializedObject.FindProperty("m_PlayButtonPath");
|
||||
m_RecordFramesProperty = serializedObject.FindProperty("m_RecordFrames");
|
||||
m_RecordStateEventsOnlyProperty = serializedObject.FindProperty("m_RecordStateEventsOnly");
|
||||
m_ReplayOnNewDevicesProperty = serializedObject.FindProperty("m_ReplayOnNewDevices");
|
||||
m_SimulateTimingOnReplayProperty = serializedObject.FindProperty("m_SimulateOriginalTimingOnReplay");
|
||||
m_CaptureMemoryDefaultSizeProperty = serializedObject.FindProperty("m_CaptureMemoryDefaultSize");
|
||||
m_CaptureMemoryMaxSizeProperty = serializedObject.FindProperty("m_CaptureMemoryMaxSize");
|
||||
m_StartRecordingWhenEnabledProperty = serializedObject.FindProperty("m_StartRecordingWhenEnabled");
|
||||
|
||||
m_AllInput = string.IsNullOrEmpty(m_DevicePathProperty.stringValue);
|
||||
|
||||
m_PlayText = EditorGUIUtility.TrIconContent("PlayButton", "Play the current input capture.");
|
||||
m_PauseText = EditorGUIUtility.TrIconContent("PauseButton", "Pause the current input playback.");
|
||||
m_ResumeText = EditorGUIUtility.TrIconContent("PauseButton On", "Resume the current input playback.");
|
||||
m_StepForwardText = EditorGUIUtility.TrIconContent("d_StepButton", "Play the next input event.");
|
||||
m_StepBackwardText = EditorGUIUtility.TrIconContent("d_StepLeftButton", "Play the previous input event.");
|
||||
m_StopText = EditorGUIUtility.TrIconContent("PlayButton On", "Stop the current input playback.");
|
||||
m_RecordText = EditorGUIUtility.TrIconContent("Animation.Record", "Start recording input.");
|
||||
|
||||
var recorder = (InputRecorder)serializedObject.targetObject;
|
||||
m_OnRecordEvent = _ => Repaint();
|
||||
recorder.changeEvent.AddListener(m_OnRecordEvent);
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
var recorder = (InputRecorder)serializedObject.targetObject;
|
||||
recorder.changeEvent.RemoveListener(m_OnRecordEvent);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var recorder = (InputRecorder)serializedObject.targetObject;
|
||||
|
||||
using (var scope = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var newAllInput = EditorGUILayout.Toggle(m_AllInputText, m_AllInput);
|
||||
if (!newAllInput)
|
||||
{
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_DevicePathProperty, m_DeviceText);
|
||||
}
|
||||
}
|
||||
else if (newAllInput != m_AllInput)
|
||||
{
|
||||
m_DevicePathProperty.stringValue = string.Empty;
|
||||
}
|
||||
m_AllInput = newAllInput;
|
||||
|
||||
EditorGUILayout.PropertyField(m_RecordFramesProperty);
|
||||
EditorGUILayout.PropertyField(m_RecordStateEventsOnlyProperty);
|
||||
EditorGUILayout.PropertyField(m_ReplayOnNewDevicesProperty);
|
||||
EditorGUILayout.PropertyField(m_SimulateTimingOnReplayProperty);
|
||||
EditorGUILayout.PropertyField(m_StartRecordingWhenEnabledProperty, m_RecordWhenEnabledText);
|
||||
|
||||
var defaultSizeInMB = m_CaptureMemoryDefaultSizeProperty.intValue / (1024 * 1024);
|
||||
var newDefaultSizeInMB = EditorGUILayout.IntSlider(m_DefaultSizeText, defaultSizeInMB, 1, 100);
|
||||
if (newDefaultSizeInMB != defaultSizeInMB)
|
||||
m_CaptureMemoryDefaultSizeProperty.intValue = newDefaultSizeInMB * 1024 * 1024;
|
||||
|
||||
var maxSizeInMB = m_CaptureMemoryMaxSizeProperty.intValue / (1024 * 1024);
|
||||
var newMaxSizeInMB = maxSizeInMB < newDefaultSizeInMB
|
||||
? newDefaultSizeInMB
|
||||
: EditorGUILayout.IntSlider(m_MaxSizeText, maxSizeInMB, 1, 100);
|
||||
if (newMaxSizeInMB != maxSizeInMB)
|
||||
m_CaptureMemoryMaxSizeProperty.intValue = newMaxSizeInMB * 1024 * 1024;
|
||||
|
||||
EditorGUILayout.PropertyField(m_RecordButtonPath, m_RecordButtonText);
|
||||
EditorGUILayout.PropertyField(m_PlayButtonPathProperty, m_PlayButtonText);
|
||||
|
||||
if (scope.changed)
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
////TODO: go-to-next and go-to-previous button
|
||||
// Play and pause buttons.
|
||||
EditorGUI.BeginDisabledGroup(recorder.eventCount == 0 || recorder.captureIsRunning);
|
||||
var oldIsPlaying = recorder.replayIsRunning;
|
||||
var newIsPlaying = GUILayout.Toggle(oldIsPlaying, !oldIsPlaying ? m_PlayText : m_StopText, EditorStyles.miniButton,
|
||||
GUILayout.Width(50));
|
||||
if (oldIsPlaying != newIsPlaying)
|
||||
{
|
||||
if (newIsPlaying)
|
||||
recorder.StartReplay();
|
||||
else
|
||||
recorder.StopReplay();
|
||||
}
|
||||
if (newIsPlaying && recorder.replay != null && GUILayout.Button(recorder.replay.paused ? m_ResumeText : m_PauseText, EditorStyles.miniButton,
|
||||
GUILayout.Width(50)))
|
||||
{
|
||||
if (recorder.replay.paused)
|
||||
recorder.StartReplay();
|
||||
else
|
||||
recorder.PauseReplay();
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// Record button.
|
||||
EditorGUI.BeginDisabledGroup(recorder.replayIsRunning);
|
||||
var oldIsRecording = recorder.captureIsRunning;
|
||||
var newIsRecording = GUILayout.Toggle(oldIsRecording, m_RecordText, EditorStyles.miniButton, GUILayout.Width(50));
|
||||
if (oldIsRecording != newIsRecording)
|
||||
{
|
||||
if (newIsRecording)
|
||||
recorder.StartCapture();
|
||||
else
|
||||
recorder.StopCapture();
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// Load button.
|
||||
EditorGUI.BeginDisabledGroup(recorder.replayIsRunning);
|
||||
if (GUILayout.Button("Load"))
|
||||
{
|
||||
var filePath = EditorUtility.OpenFilePanel("Choose Input Event Trace to Load", string.Empty, "inputtrace");
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
recorder.LoadCaptureFromFile(filePath);
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// Save button.
|
||||
EditorGUI.BeginDisabledGroup(recorder.eventCount == 0 || recorder.replayIsRunning);
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
var filePath = EditorUtility.SaveFilePanel("Choose Where to Save Input Event Trace", string.Empty, $"{recorder.gameObject.name}.inputtrace", "inputtrace");
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
recorder.SaveCaptureToFile(filePath);
|
||||
}
|
||||
|
||||
// Clear button.
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
recorder.ClearCapture();
|
||||
Repaint();
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
////TODO: allow hotscrubbing
|
||||
// Play bar.
|
||||
EditorGUILayout.IntSlider(recorder.replayPosition, 0, (int)recorder.eventCount);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUI.DisabledScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(m_InfoText, EditorStyles.miniBoldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.LabelField($"{recorder.eventCount} events", EditorStyles.miniLabel);
|
||||
EditorGUILayout.LabelField($"{recorder.totalEventSizeInBytes / 1024} kb captured", EditorStyles.miniLabel);
|
||||
EditorGUILayout.LabelField($"{recorder.allocatedSizeInBytes / 1024} kb allocated", EditorStyles.miniLabel);
|
||||
|
||||
if (recorder.capture != null)
|
||||
{
|
||||
var devices = recorder.capture.deviceInfos;
|
||||
if (devices.Count > 0)
|
||||
{
|
||||
EditorGUILayout.LabelField(m_DevicesText, EditorStyles.miniBoldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
foreach (var device in devices)
|
||||
{
|
||||
EditorGUILayout.LabelField(device.layout, EditorStyles.miniLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_AllInput;
|
||||
private SerializedProperty m_DevicePathProperty;
|
||||
private SerializedProperty m_RecordButtonPath;
|
||||
private SerializedProperty m_PlayButtonPathProperty;
|
||||
private SerializedProperty m_RecordFramesProperty;
|
||||
private SerializedProperty m_RecordStateEventsOnlyProperty;
|
||||
private SerializedProperty m_ReplayOnNewDevicesProperty;
|
||||
private SerializedProperty m_SimulateTimingOnReplayProperty;
|
||||
private SerializedProperty m_CaptureMemoryDefaultSizeProperty;
|
||||
private SerializedProperty m_CaptureMemoryMaxSizeProperty;
|
||||
private SerializedProperty m_StartRecordingWhenEnabledProperty;
|
||||
private UnityAction<InputRecorder.Change> m_OnRecordEvent;
|
||||
|
||||
private GUIContent m_RecordButtonText = new GUIContent("Record Button", "If set, this button will start and stop capture in play mode.");
|
||||
private GUIContent m_PlayButtonText = new GUIContent("Play Button", "If set, this button will start and stop replay of the current capture in play mode.");
|
||||
private GUIContent m_RecordWhenEnabledText = new GUIContent("Capture When Enabled", "If true, recording will start immediately when the component is enabled in play mode.");
|
||||
private GUIContent m_DevicesText = new GUIContent("Devices");
|
||||
private GUIContent m_AllInputText = new GUIContent("All Input", "Whether to record input from all devices or from just specific devices.");
|
||||
private GUIContent m_DeviceText = new GUIContent("Device", "Type of device to record input from.");
|
||||
private GUIContent m_InfoText = new GUIContent("Info:");
|
||||
private GUIContent m_DefaultSizeText = new GUIContent("Default Size (MB)", "Memory allocate for capture by default. Will automatically grow up to max memory.");
|
||||
private GUIContent m_MaxSizeText = new GUIContent("Max Size (MB)", "Maximum memory allocated for capture. Once a capture reaches this limit, new events will start overwriting old ones.");
|
||||
private GUIContent m_PlayText;
|
||||
private GUIContent m_PauseText;
|
||||
private GUIContent m_ResumeText;
|
||||
private GUIContent m_StepForwardText;
|
||||
private GUIContent m_StepBackwardText;
|
||||
private GUIContent m_StopText;
|
||||
private GUIContent m_RecordText;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bb726b4db024f738c493b8132730571
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da1a360c18546f34fac39b2c305ac2c9
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!850595691 &4890085278179872738
|
||||
LightingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: InputRecorderSampleSettings
|
||||
serializedVersion: 6
|
||||
m_GIWorkflowMode: 1
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_RealtimeEnvironmentLighting: 1
|
||||
m_BounceScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_UsingShadowmask: 1
|
||||
m_BakeBackend: 1
|
||||
m_LightmapMaxSize: 1024
|
||||
m_BakeResolution: 40
|
||||
m_Padding: 2
|
||||
m_LightmapCompression: 3
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAO: 0
|
||||
m_MixedBakeMode: 2
|
||||
m_LightmapsBakeMode: 1
|
||||
m_FilterMode: 1
|
||||
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_RealtimeResolution: 2
|
||||
m_ForceWhiteAlbedo: 0
|
||||
m_ForceUpdates: 0
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherRayCount: 256
|
||||
m_FinalGatherFiltering: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_PVRBounces: 2
|
||||
m_PVRMinBounces: 2
|
||||
m_PVREnvironmentImportanceSampling: 1
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_PVRTiledBaking: 0
|
||||
m_NumRaysToShootPerTexel: -1
|
||||
m_RespectSceneVisibilityWhenBakingGI: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c991725f36f864f7c9ab0c75730ba9c3
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 4890085278179872738
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
This sample is both a demonstration for how to use [`InputEventTrace`](https://docs.unity3d.com/Packages/com.unity.inputsystem@latest/index.html?subfolder=/api/UnityEngine.InputSystem.LowLevel.InputEventTrace.html) as well as a useful tool by itself in the form of the [`InputRecorder`](./InputRecorder.cs) reusable `MonoBehaviour` component.
|
||||
|
||||
One possible way in which you can use this facility, for example, is to record input, save it to disk, and then replay the same input in automation (e.g. in tests or when recording short video snippets of preset gameplay sequences for manual proofing).
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7efc8d27cb74c05a04933d66f7f8062
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "Unity.InputSystem.Recorder",
|
||||
"references": [
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 157556569ac93a94fb6a763f50476339
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d4b28c8112edcc429dd51b4061a4618
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22f5d28791afa30448b52589b9213066
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.DualShock;
|
||||
|
||||
public class LightbarSettings : MonoBehaviour
|
||||
{
|
||||
public Color SetColor;
|
||||
|
||||
public void ChangeColor()
|
||||
{
|
||||
var gamepad = DualShockGamepad.current;
|
||||
if (gamepad != null)
|
||||
{
|
||||
Debug.Log("Current gamepad: " + gamepad);
|
||||
gamepad.SetLightBarColor(SetColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f16c760d1d497144a1927cbb27caad8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.DualShock;
|
||||
|
||||
public class MotorSettings : MonoBehaviour
|
||||
{
|
||||
[Range(0, 1)] public float lowFrequencyMotorSpeed;
|
||||
[Range(0, 1)] public float highFrequencyMotorSpeed;
|
||||
|
||||
public void SetMotorSpeeds()
|
||||
{
|
||||
var gamepad = Gamepad.current;
|
||||
if (gamepad != null)
|
||||
{
|
||||
Debug.Log("Current gamepad: " + gamepad);
|
||||
gamepad.SetMotorSpeeds(lowFrequencyMotorSpeed, highFrequencyMotorSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
var gamepad = Gamepad.current;
|
||||
if (gamepad != null)
|
||||
{
|
||||
gamepad.SetMotorSpeeds(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbd4cc500f118d740a1342b2168f32e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 267a495be84ccf2489ca25f14b60c603
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "On-Screen Controls",
|
||||
"description": "Demonstrates a simple setup for an on-screen joystick."
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1728513650105062
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224771122883764374}
|
||||
- component: {fileID: 222401134047137570}
|
||||
- component: {fileID: 114826362001716654}
|
||||
- component: {fileID: 114204224268582166}
|
||||
- component: {fileID: 114344768413473294}
|
||||
m_Layer: 5
|
||||
m_Name: Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224771122883764374
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1728513650105062}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 224750732080817856}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222401134047137570
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1728513650105062}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114826362001716654
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1728513650105062}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &114204224268582166
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1728513650105062}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Highlighted
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 114826362001716654}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls:
|
||||
- m_Target: {fileID: 0}
|
||||
m_TargetAssemblyTypeName:
|
||||
m_MethodName:
|
||||
m_Mode: 1
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName:
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
--- !u!114 &114344768413473294
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1728513650105062}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6d54531977ecb194c95e2d3aa7a5d72a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_ControlPath: /<Keyboard>/a
|
||||
--- !u!1 &1977925927173892
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224750732080817856}
|
||||
- component: {fileID: 222878083001498966}
|
||||
- component: {fileID: 114547973042304788}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224750732080817856
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1977925927173892}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 224771122883764374}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222878083001498966
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1977925927173892}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114547973042304788
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1977925927173892}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Keyboard 'A' Key
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05f32eddd3e41fd4597ada617b785928
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 011b162d4daa13c4ab03e94ad47b8258
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,193 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1080311573403324
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224063307367997780}
|
||||
- component: {fileID: 222676770552705204}
|
||||
- component: {fileID: 114017654419583406}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224063307367997780
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1080311573403324}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 224091927000801720}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 2, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222676770552705204
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1080311573403324}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114017654419583406
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1080311573403324}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Left Stick
|
||||
--- !u!1 &1613174875475300
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224091927000801720}
|
||||
- component: {fileID: 222418917327610168}
|
||||
- component: {fileID: 114144114248384442}
|
||||
- component: {fileID: 114480945186419424}
|
||||
m_Layer: 5
|
||||
m_Name: Stick
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224091927000801720
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1613174875475300}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 224063307367997780}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -199, y: -120}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222418917327610168
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1613174875475300}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114144114248384442
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1613174875475300}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300002, guid: e97a8ef01555d4941bdbc5eb5b056469, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &114480945186419424
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1613174875475300}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e9d677f1681015749b15c436eec6d880, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_MovementRange: 50
|
||||
m_DynamicOriginRange: 100
|
||||
m_ControlPath: /<GamePad>/LeftStick
|
||||
m_Behaviour: 0
|
||||
m_UseIsolatedInputActions: 0
|
||||
m_PointerDownAction:
|
||||
m_Name:
|
||||
m_Type: 0
|
||||
m_ExpectedControlType:
|
||||
m_Id: 144900f0-7f38-444f-99b2-ce57f2d7cba8
|
||||
m_Processors:
|
||||
m_Interactions:
|
||||
m_SingletonActionBindings: []
|
||||
m_Flags: 0
|
||||
m_PointerMoveAction:
|
||||
m_Name:
|
||||
m_Type: 0
|
||||
m_ExpectedControlType:
|
||||
m_Id: f86297a0-55be-40e6-8e33-04e2b1efc8e1
|
||||
m_Processors:
|
||||
m_Interactions:
|
||||
m_SingletonActionBindings: []
|
||||
m_Flags: 0
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f77f88b14a477764bb65a49d28c02d33
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd9dcc5a3e3502b42b13e8ad113ab8f1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "ProjectWideActions",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 472aaae9fe1ef1f478743ae4c5ef7592
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
namespace UnityEngine.InputSystem.Samples.ProjectWideActions
|
||||
{
|
||||
public class ProjectWideActionsExample : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public GameObject cube;
|
||||
|
||||
InputAction move;
|
||||
InputAction look;
|
||||
InputAction attack;
|
||||
InputAction jump;
|
||||
InputAction interact;
|
||||
InputAction next;
|
||||
InputAction previous;
|
||||
InputAction sprint;
|
||||
InputAction crouch;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
// Project-Wide Actions
|
||||
if (InputSystem.actions)
|
||||
{
|
||||
move = InputSystem.actions.FindAction("Player/Move");
|
||||
look = InputSystem.actions.FindAction("Player/Look");
|
||||
attack = InputSystem.actions.FindAction("Player/Attack");
|
||||
jump = InputSystem.actions.FindAction("Player/Jump");
|
||||
interact = InputSystem.actions.FindAction("Player/Interact");
|
||||
next = InputSystem.actions.FindAction("Player/Next");
|
||||
previous = InputSystem.actions.FindAction("Player/Previous");
|
||||
sprint = InputSystem.actions.FindAction("Player/Sprint");
|
||||
crouch = InputSystem.actions.FindAction("Player/Crouch");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("Setup Project Wide Input Actions in the Player Settings, Input System section");
|
||||
}
|
||||
|
||||
// Handle input by responding to callbacks
|
||||
if (attack != null)
|
||||
{
|
||||
attack.performed += OnAttack;
|
||||
attack.canceled += OnCancel;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttack(InputAction.CallbackContext ctx)
|
||||
{
|
||||
cube.GetComponent<Renderer>().material.color = Color.red;
|
||||
}
|
||||
|
||||
private void OnCancel(InputAction.CallbackContext ctx)
|
||||
{
|
||||
cube.GetComponent<Renderer>().material.color = Color.green;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (attack != null)
|
||||
{
|
||||
attack.performed -= OnAttack;
|
||||
attack.canceled -= OnCancel;
|
||||
}
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
// Handle input by polling each frame
|
||||
if (move != null)
|
||||
{
|
||||
var moveVal = move.ReadValue<Vector2>() * 10.0f * Time.deltaTime;
|
||||
cube.transform.Translate(new Vector3(moveVal.x, moveVal.y, 0));
|
||||
}
|
||||
}
|
||||
} // class ProjectWideActionsExample
|
||||
} // namespace UnityEngine.InputSystem.Samples.ProjectWideActions
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f28fc6350a3a50a46a9e2448b66b7ab7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,468 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_LightingSettings: {fileID: 0}
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &1227919034
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1227919037}
|
||||
- component: {fileID: 1227919036}
|
||||
- component: {fileID: 1227919035}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1227919035
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227919034}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1227919036
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227919034}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1227919037
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1227919034}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1239474184
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1239474186}
|
||||
- component: {fileID: 1239474185}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!108 &1239474185
|
||||
Light:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1239474184}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||
m_Intensity: 1
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
m_CookieSize: 10
|
||||
m_Shadows:
|
||||
m_Type: 2
|
||||
m_Resolution: -1
|
||||
m_CustomResolution: -1
|
||||
m_Strength: 1
|
||||
m_Bias: 0.05
|
||||
m_NormalBias: 0.4
|
||||
m_NearPlane: 0.2
|
||||
m_CullingMatrixOverride:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_UseCullingMatrixOverride: 0
|
||||
m_Cookie: {fileID: 0}
|
||||
m_DrawHalo: 0
|
||||
m_Flare: {fileID: 0}
|
||||
m_RenderMode: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingLayerMask: 1
|
||||
m_Lightmapping: 4
|
||||
m_LightShadowCasterMode: 0
|
||||
m_AreaSize: {x: 1, y: 1}
|
||||
m_BounceIntensity: 1
|
||||
m_ColorTemperature: 6570
|
||||
m_UseColorTemperature: 0
|
||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
--- !u!4 &1239474186
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1239474184}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||
--- !u!1 &1517955871
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1517955873}
|
||||
m_Layer: 0
|
||||
m_Name: Player
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1517955873
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1517955871}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1522618675
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1522618680}
|
||||
- component: {fileID: 1522618679}
|
||||
- component: {fileID: 1522618678}
|
||||
- component: {fileID: 1522618677}
|
||||
- component: {fileID: 1522618676}
|
||||
m_Layer: 0
|
||||
m_Name: Cube
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1522618676
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1522618675}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f28fc6350a3a50a46a9e2448b66b7ab7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
cube: {fileID: 1522618675}
|
||||
--- !u!65 &1522618677
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1522618675}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 0
|
||||
serializedVersion: 3
|
||||
m_Size: {x: 1, y: 1, z: 1}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &1522618678
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1522618675}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &1522618679
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1522618675}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!4 &1522618680
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1522618675}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 1227919037}
|
||||
- {fileID: 1239474186}
|
||||
- {fileID: 1517955873}
|
||||
- {fileID: 1522618680}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9a118a06bb79c0428c11bb701b6756e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.unity.inputsystem/Samples~/RebindingUI.meta
Normal file
8
Packages/com.unity.inputsystem/Samples~/RebindingUI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5592ad2abca6d134fa5ce518cf79b347
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"displayName": "Rebinding UI",
|
||||
"description": "An example UI component that demonstrates how to create UI for rebinding actions."
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.RebindUI
|
||||
{
|
||||
public class ActionLabel : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Reference to action that is to be rebound from the UI.")]
|
||||
[SerializeField]
|
||||
private InputActionReference m_Action;
|
||||
|
||||
[SerializeField]
|
||||
private string m_BindingId;
|
||||
|
||||
[SerializeField]
|
||||
private InputBinding.DisplayStringOptions m_DisplayStringOptions;
|
||||
|
||||
[Tooltip("Text label that will receive the current, formatted binding string.")]
|
||||
[SerializeField]
|
||||
private Text m_BindingText;
|
||||
|
||||
[Tooltip("Event that is triggered when the way the binding is display should be updated. This allows displaying "
|
||||
+ "bindings in custom ways, e.g. using images instead of text.")]
|
||||
[SerializeField]
|
||||
private UpdateBindingUIEvent m_UpdateBindingUIEvent;
|
||||
|
||||
private static List<ActionLabel> s_InputActionUIs;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the action that is to be rebound.
|
||||
/// </summary>
|
||||
public InputActionReference actionReference
|
||||
{
|
||||
get => m_Action;
|
||||
set
|
||||
{
|
||||
m_Action = value;
|
||||
UpdateBindingDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ID (in string form) of the binding that is to be rebound on the action.
|
||||
/// </summary>
|
||||
/// <seealso cref="InputBinding.id"/>
|
||||
public string bindingId
|
||||
{
|
||||
get => m_BindingId;
|
||||
set
|
||||
{
|
||||
m_BindingId = value;
|
||||
UpdateBindingDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text component that receives the display string of the binding. Can be <c>null</c> in which
|
||||
/// case the component entirely relies on <see cref="updateBindingUIEvent"/>.
|
||||
/// </summary>
|
||||
public Text bindingText
|
||||
{
|
||||
get => m_BindingText;
|
||||
set
|
||||
{
|
||||
m_BindingText = value;
|
||||
UpdateBindingDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display options for the binding.
|
||||
/// </summary>
|
||||
public InputBinding.DisplayStringOptions displayStringOptions
|
||||
{
|
||||
get => m_DisplayStringOptions;
|
||||
set
|
||||
{
|
||||
m_DisplayStringOptions = value;
|
||||
UpdateBindingDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trigger a refresh of the currently displayed binding.
|
||||
/// </summary>
|
||||
public void UpdateBindingDisplay()
|
||||
{
|
||||
var displayString = string.Empty;
|
||||
var deviceLayoutName = default(string);
|
||||
var controlPath = default(string);
|
||||
|
||||
// Get display string from action.
|
||||
var action = m_Action?.action;
|
||||
if (action != null)
|
||||
{
|
||||
var bindingIndex = action.bindings.IndexOf(x => x.id.ToString() == m_BindingId);
|
||||
if (bindingIndex != -1)
|
||||
displayString = action.GetBindingDisplayString(bindingIndex, out deviceLayoutName, out controlPath, displayStringOptions);
|
||||
}
|
||||
|
||||
// Set on label (if any).
|
||||
if (m_BindingText != null)
|
||||
m_BindingText.text = displayString;
|
||||
|
||||
// Give listeners a chance to configure UI in response.
|
||||
m_UpdateBindingUIEvent?.Invoke(this, displayString, deviceLayoutName, controlPath);
|
||||
}
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
if (s_InputActionUIs == null)
|
||||
s_InputActionUIs = new List<ActionLabel>();
|
||||
s_InputActionUIs.Add(this);
|
||||
if (s_InputActionUIs.Count == 1)
|
||||
InputSystem.onActionChange += OnActionChange;
|
||||
UpdateBindingDisplay();
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
s_InputActionUIs.Remove(this);
|
||||
if (s_InputActionUIs.Count == 0)
|
||||
{
|
||||
s_InputActionUIs = null;
|
||||
InputSystem.onActionChange -= OnActionChange;
|
||||
}
|
||||
}
|
||||
|
||||
// When the action system re-resolves bindings, we want to update our UI in response
|
||||
// to show the currently relevant binding.
|
||||
private static void OnActionChange(object obj, InputActionChange change)
|
||||
{
|
||||
if (change != InputActionChange.BoundControlsChanged)
|
||||
return;
|
||||
|
||||
var action = obj as InputAction;
|
||||
var actionMap = action?.actionMap ?? obj as InputActionMap;
|
||||
var actionAsset = actionMap?.asset ?? obj as InputActionAsset;
|
||||
|
||||
for (var i = 0; i < s_InputActionUIs.Count; ++i)
|
||||
{
|
||||
var component = s_InputActionUIs[i];
|
||||
var referencedAction = component.actionReference?.action;
|
||||
if (referencedAction == null)
|
||||
continue;
|
||||
|
||||
if (referencedAction == action ||
|
||||
referencedAction.actionMap == actionMap ||
|
||||
referencedAction.actionMap?.asset == actionAsset)
|
||||
component.UpdateBindingDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UpdateBindingUIEvent : UnityEvent<ActionLabel, string, string, string>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e486f50f3398f47b5a0a6b8f3270fc7e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
////TODO: support multi-object editing
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.RebindUI
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom inspector for <see cref="RebindActionUI"/> which provides a more convenient way for
|
||||
/// picking the binding which to rebind.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(ActionLabel))]
|
||||
public class ActionLabelEditor : UnityEditor.Editor
|
||||
{
|
||||
protected void OnEnable()
|
||||
{
|
||||
m_BindingTextProperty = serializedObject.FindProperty("m_BindingText");
|
||||
m_UpdateBindingUIEventProperty = serializedObject.FindProperty("m_UpdateBindingUIEvent");
|
||||
m_BindingUI = new BindingUI(serializedObject);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
// Binding section.
|
||||
m_BindingUI.Draw();
|
||||
|
||||
// UI section.
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField(m_UILabel, Styles.boldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_BindingTextProperty);
|
||||
}
|
||||
|
||||
// Events section.
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField(m_EventsLabel, Styles.boldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_UpdateBindingUIEventProperty);
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
m_BindingUI.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedProperty m_BindingTextProperty;
|
||||
private SerializedProperty m_UpdateBindingUIEventProperty;
|
||||
|
||||
private GUIContent m_UILabel = new GUIContent("UI");
|
||||
private GUIContent m_EventsLabel = new GUIContent("Events");
|
||||
private BindingUI m_BindingUI;
|
||||
|
||||
private static class Styles
|
||||
{
|
||||
public static GUIStyle boldLabel = new GUIStyle("MiniBoldLabel");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00bbef538999c4fd182f7ebad42ea0f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
146
Packages/com.unity.inputsystem/Samples~/RebindingUI/BindingUI.cs
Normal file
146
Packages/com.unity.inputsystem/Samples~/RebindingUI/BindingUI.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEngine.InputSystem.Samples.RebindUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Common binding UI helper to allow editor composition.
|
||||
/// </summary>
|
||||
internal class BindingUI
|
||||
{
|
||||
private readonly SerializedProperty m_ActionProperty;
|
||||
private readonly SerializedProperty m_BindingIdProperty;
|
||||
private readonly SerializedProperty m_DisplayStringOptionsProperty;
|
||||
|
||||
public BindingUI(SerializedObject serializedObject)
|
||||
: this(serializedObject.FindProperty("m_Action"), serializedObject.FindProperty("m_BindingId"),
|
||||
serializedObject.FindProperty("m_DisplayStringOptions"))
|
||||
{}
|
||||
|
||||
public BindingUI(SerializedProperty actionProperty, SerializedProperty bindingIdProperty,
|
||||
SerializedProperty displayStringOptionsProperty = null)
|
||||
{
|
||||
m_ActionProperty = actionProperty;
|
||||
m_BindingIdProperty = bindingIdProperty;
|
||||
m_DisplayStringOptionsProperty = displayStringOptionsProperty;
|
||||
|
||||
Reset();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
bindingOptions = Array.Empty<GUIContent>();
|
||||
bindingOptionValues = Array.Empty<string>();
|
||||
selectedBindingIndex = -1;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
// Binding section.
|
||||
EditorGUILayout.LabelField(m_BindingLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_ActionProperty);
|
||||
|
||||
var newSelectedBinding = EditorGUILayout.Popup(m_BindingLabel, selectedBindingIndex, bindingOptions);
|
||||
if (newSelectedBinding != selectedBindingIndex)
|
||||
{
|
||||
var id = bindingOptionValues[newSelectedBinding];
|
||||
m_BindingIdProperty.stringValue = id;
|
||||
selectedBindingIndex = newSelectedBinding;
|
||||
}
|
||||
|
||||
if (m_DisplayStringOptionsProperty != null)
|
||||
{
|
||||
var optionsOld = (InputBinding.DisplayStringOptions)m_DisplayStringOptionsProperty.intValue;
|
||||
var optionsNew = (InputBinding.DisplayStringOptions)EditorGUILayout.EnumFlagsField(m_DisplayOptionsLabel, optionsOld);
|
||||
if (optionsOld != optionsNew)
|
||||
m_DisplayStringOptionsProperty.intValue = (int)optionsNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Refresh()
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
var bindings = action.bindings;
|
||||
var bindingCount = bindings.Count;
|
||||
|
||||
bindingOptions = new GUIContent[bindingCount];
|
||||
bindingOptionValues = new string[bindingCount];
|
||||
selectedBindingIndex = -1;
|
||||
|
||||
var currentBindingId = m_BindingIdProperty.stringValue;
|
||||
for (var i = 0; i < bindingCount; ++i)
|
||||
{
|
||||
var binding = bindings[i];
|
||||
var id = binding.id.ToString();
|
||||
var haveBindingGroups = !string.IsNullOrEmpty(binding.groups);
|
||||
|
||||
// If we don't have a binding groups (control schemes), show the device that if there are, for example,
|
||||
// there are two bindings with the display string "A", the user can see that one is for the keyboard
|
||||
// and the other for the gamepad.
|
||||
var displayOptions =
|
||||
InputBinding.DisplayStringOptions.DontUseShortDisplayNames | InputBinding.DisplayStringOptions.IgnoreBindingOverrides;
|
||||
if (!haveBindingGroups)
|
||||
displayOptions |= InputBinding.DisplayStringOptions.DontOmitDevice;
|
||||
|
||||
// Create display string.
|
||||
var displayString = action.GetBindingDisplayString(i, displayOptions);
|
||||
|
||||
// If binding is part of a composite, include the part name.
|
||||
if (binding.isPartOfComposite)
|
||||
displayString = $"{ObjectNames.NicifyVariableName(binding.name)}: {displayString}";
|
||||
|
||||
// Some composites use '/' as a separator. When used in popup, this will lead to to submenus. Prevent
|
||||
// by instead using a backlash.
|
||||
displayString = displayString.Replace('/', '\\');
|
||||
|
||||
// If the binding is part of control schemes, mention them.
|
||||
if (haveBindingGroups)
|
||||
{
|
||||
var asset = action.actionMap?.asset;
|
||||
if (asset != null)
|
||||
{
|
||||
var controlSchemes = string.Join(", ",
|
||||
binding.groups.Split(InputBinding.Separator)
|
||||
.Select(x => asset.controlSchemes.FirstOrDefault(c => c.bindingGroup == x).name));
|
||||
|
||||
displayString = $"{displayString} ({controlSchemes})";
|
||||
}
|
||||
}
|
||||
|
||||
bindingOptions[i] = new GUIContent(displayString);
|
||||
bindingOptionValues[i] = id;
|
||||
|
||||
if (currentBindingId == id)
|
||||
selectedBindingIndex = i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string bindingId => m_BindingIdProperty.stringValue;
|
||||
public int bindingIndex => action.FindBindingById(m_BindingIdProperty.stringValue);
|
||||
|
||||
public InputAction action => ((InputActionReference)m_ActionProperty.objectReferenceValue)?.action;
|
||||
|
||||
private GUIContent[] bindingOptions { get; set; }
|
||||
private string[] bindingOptionValues { get; set; }
|
||||
private int selectedBindingIndex { get; set; }
|
||||
|
||||
private readonly GUIContent m_BindingLabel = new GUIContent("Binding");
|
||||
private readonly GUIContent m_DisplayOptionsLabel = new GUIContent("Display Options");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user