XBox 360控制器非自定义映射

时间:2014-01-04 20:26:39

标签: controller mapping xbox360 xinput

我想制作一个利用XBox 360控制器输入来输出的程序,例如,如果你在控制器上按 A ,它就像按 A < / kbd>在键盘上。我计划将它用于游戏开发,并且不希望输出可自定义,但我确实希望窗口可见,以便可以随时关闭它。我将如何制作这个程序(适用于Windows)并使其易于使用。

1 个答案:

答案 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
    }
}

希望这有帮助。