1

我想制作一个程序,利用 XBox 360 控制器的输入来提供输出,例如,如果您按下A控制器,则与按下A键盘相同。我计划将其用于游戏开发,并且不希望输出可自定义,但我确实希望有一个可见的窗口,以便可以随时关闭它。我将如何制作这个程序(适用于 Windows)并让它易于使用。

4

1 回答 1

0

我建议使用输入抽象类并转换您需要的输入类型,使用具体类将输入(键盘上的 A 或 Xbox 上的 RTrigger)转换为游戏中的输入动作(按下按钮、按下跳跃按钮、X 方向移动ETC)。

在 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 中,我使用我创建的这个类来进行输入,并将 XBox 控制器转换为InputState上面的类。初始化时,它需要玩家 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
    }
}

希望这可以帮助。

于 2014-01-04T22:54:23.397 回答