【问题标题】:XBox 360 controller non-customisable mappingXbox 360 控制器不可自定义映射
【发布时间】:2014-01-05 18:20:24
【问题描述】:

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

【问题讨论】:

    标签: controller mapping xbox360 xinput


    【解决方案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 中,我使用我创建的这个类将 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
        }
    }
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多