我想制作一个利用XBox 360控制器输入来输出的程序,例如,如果你在控制器上按 A ,它就像按 A < / kbd>在键盘上。我计划将它用于游戏开发,并且不希望输出可自定义,但我确实希望窗口可见,以便可以随时关闭它。我将如何制作这个程序(适用于Windows)并使其易于使用。
答案 0 :(得分:1)
我建议使用输入抽象类并使用具体类转换所需的输入类型,将输入(键盘上的A或Xbox上的RTrigger)转换为游戏中的输入操作(按下按钮,按下按钮,按下运动在X方向等)。
在C#中,这可以相对容易地完成。创建一个类/结构作为转换返回的目标。在我的情况下,我做了一个带有摄像头控制的动作和动作的格斗游戏平台,我称之为InputState
:
public class InputState
{
public struct Axis
{
public float X;
public float Y;
public float XNorm
{
get{ return Math.Abs(X); }
}
public float YNorm
{
get{ return Math.Abs(Y); }
}
}
public struct ActionStates
{
public bool Jump;
public bool Punch;
public bool Kick;
public bool Special;
public bool Grab;
public bool Guard;
}
public Axis MovementAxis;
public Axis CameraAxis;
public ActionStates Actions;
}
然后,您可以创建一个抽象InputConverter
类,该类接受某种类型的输入并返回此InputState
类:
public abstract class InputConverter
{
public abstract InputState Convert();
}
然后你可以将这个类扩展到其他类中,例如在Unity3D中我使用我创建的这个类来使用转换为上面InputState
类的XBox控制器进行输入。初始化时,需要玩家ID才能获得正确的控制器。这里最重要的部分是public override InputState Convert
,它会返回您的游戏InputState
对象:
using XInputDotNetPure;
public class XInputConverter : InputConverter
{
bool playerIndexSet = false;
PlayerIndex playerIndex;
GamePadState gamePadState;
GamePadState prevState;
public XInputConverter(int playerSlot)
{
VerifyControllerConnected(playerSlot);
}
private void VerifyControllerConnected(int playerSlot)
{
// Find a PlayerIndex, for a single player game
if (!playerIndexSet || !prevState.IsConnected)
{
PlayerIndex testPlayerIndex = (PlayerIndex)playerSlot - 1;
GamePadState testState = GamePad.GetState(testPlayerIndex);
if (testState.IsConnected)
{
//Debug.Log (string.Format ("GamePad found {0}", testPlayerIndex));
playerIndex = testPlayerIndex;
playerIndexSet = true;
} else
{
throw new Exception(string.Format("GamePad {0} has been unplugged or is not connecting properly", testPlayerIndex));
}
}
}
public override InputState Convert()
{
InputState outputState = new InputState();
gamePadState = GamePad.GetState(playerIndex);
//Actions
outputState.Actions.Jump = gamePadState.Buttons.Y == ButtonState.Pressed;
//Offense
outputState.Actions.Punch = gamePadState.Buttons.X == ButtonState.Pressed;
outputState.Actions.Kick = gamePadState.Buttons.A == ButtonState.Pressed;
outputState.Actions.Special = gamePadState.Buttons.B == ButtonState.Pressed;
//Defense
outputState.Actions.Grab = gamePadState.Buttons.LeftShoulder == ButtonState.Pressed || gamePadState.Buttons.RightShoulder == ButtonState.Pressed;
outputState.Actions.Guard = gamePadState.Triggers.Left > 0 || gamePadState.Triggers.Right > 0;
//Movement from DPad
short xAxis = 0;
short yAxis = 0;
//Determine if Dpad has any input
if (gamePadState.DPad.Right == ButtonState.Pressed)
xAxis += 1;
if (gamePadState.DPad.Left == ButtonState.Pressed)
xAxis -= 1;
if (gamePadState.DPad.Up == ButtonState.Pressed)
yAxis += 1;
if (gamePadState.DPad.Down == ButtonState.Pressed)
yAxis -= 1;
//Set the movement to either the Thumsticks or the DPad
outputState.MovementAxis.X = xAxis == 0 ? gamePadState.ThumbSticks.Left.X : xAxis;
outputState.MovementAxis.Y = yAxis == 0 ? gamePadState.ThumbSticks.Left.Y : yAxis;
//Camera
outputState.CameraAxis.X = gamePadState.ThumbSticks.Right.X;
outputState.CameraAxis.X = gamePadState.ThumbSticks.Right.Y;
return outputState;
}
}
使用此类,您可以专门使用所需的按钮进行所需的操作,并使用您选择的任何输入执行此操作。这是统一键盘转换器:
using UnityEngine;
public class UnityKeyboardInputConverter : InputConverter
{
public override InputState Convert()
{
InputState state = new InputState();
//Actions
state.Actions.Jump = Input.GetKey(KeyCode.Space);
//Offense
state.Actions.Punch = Input.GetKey(KeyCode.J);
state.Actions.Kick = Input.GetKey(KeyCode.K);
state.Actions.Special = Input.GetKey(KeyCode.L);
//Defense
state.Actions.Grab = Input.GetKey(KeyCode.RightShift);
state.Actions.Guard = Input.GetKey(KeyCode.LeftShift);
//Movement
state.MovementAxis.X = Input.GetAxisRaw("Horizontal");
state.MovementAxis.Y = Input.GetAxisRaw("Vertical");
//Camera
state.CameraAxis.X = Input.GetAxisRaw("Mouse X");
state.CameraAxis.X = Input.GetAxisRaw("Mouse Y");
return state;
}
}
<强>最后强>
根据玩家的选择,我可以简单地使用枚举器实例化我选择的输入转换器,并使用InputHandler
类来调用更新并从相应的一个检索输入状态,而无需知道它是哪一个是玩家使用的。这很重要,因为您只想在游戏引擎准备好并使用播放器选择的设置(XBox,键盘+鼠标,PC GamePad等)时调用这些输入:
public class InputHandler
{
//Controller handlers and properties
private int playerNumber;
public enum InputType
{
None = 0,
KeyboardMouse,
XBoxController,
PCGamePad
}
public InputType SelectedInputType = InputType.None;
public InputState CommandState;
//Ambiguous Abstract input converter allows us to assign Xbox or keyboard as input
private InputConverter converter;
public InputHandler(int playerNumber, InputType inputType)
{
SelectedInputType = inputType;
this.playerNumber = playerNumber;
if (playerNumber > 4 || playerNumber < 1)
{
throw new Exception("Player must be set to 1, 2, 3 or 4");
}
//Check type and load converter
switch (SelectedInputType)
{
case InputType.XBoxController:
converter = new XInputConverter(playerNumber);
break;
case InputType.KeyboardMouse
converter = new UnityKeyboardInputConverter();
break;
case InputType.PCGamePad:
converter = new PCGamePadInputConverter(playerNumber);
break;
case InputType.None:
//Do nothing but would be a good idea to handle it in game
}
}
// Update is called once per frame by Unity Update functions
public void InputUpdate()
{
if (converter != null)
{
CommandState = converter.Convert();
}
//Debug if in the Unity editor
#if UNITY_EDITOR
Debug.Log(CommandState.ToString());
#endif
}
}
希望这有帮助。