unity做游戏常用功能实现(一)多方向同时输入也能让物体正常移动

时间:2024-01-22 18:46:31

-------小基原创,转载请给我一个面子

网上有很多讲输入控制如何移动,但是多数都是讲单一按下,对于同时按下2个或2个以上按键并没有说明怎么解决,这里小基研究了一下方便大家

(如果你直接写input.GetKey去读输入,直接执行物体移动的话,判断格个方向时逻辑时,如果使用if-elseif这种的话,多按键输入时候,必定只能执行其中一个方向。
如果用if判断各个方向,那么当“上”方向和“右”方向同时按下时,物理轨迹是“右上”方向,而你单个方向速度如果都是v的话,合速度方向为√2,相当于斜着走速度会变快,这两个方式都不能接受)

所以解决思路是当按键按下时,记录状态,抬起时重置状态,根据当前所有输入的按键状态,统一处理得出一个合方向,并且对合速度处理
  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 public class MyInput : MonoBehaviour {
  6     //移动方向枚举
  7     enum MoveDir
  8     {
  9         None,   //不动
 10         Up,     //上8
 11         Down,   //下2
 12         Left,   //左4
 13         Right,  //右6
 14         UL,     //左上7
 15         UR,     //右上9
 16         DL,     //左下1
 17         DR,     //右下3
 18     }
 19 
 20     //输入按键常量(之后走配置)
 21     const KeyCode INPUT_UP = KeyCode.W;
 22     const KeyCode INPUT_DOWN = KeyCode.S;
 23     const KeyCode INPUT_LEFT = KeyCode.A;
 24     const KeyCode INPUT_RIGHT = KeyCode.D;
 25 
 26     //默认移动方向
 27     private MoveDir moveDir = MoveDir.None;
 28     //按压记录
 29     private bool isUpPress = false;
 30     private bool isDownPress = false;
 31     private bool isLeftPress = false;
 32     private bool isRightPress = false;
 33 
 34     //是否可以移动
 35     private bool canMove = true;
 36     //右移动
 37     private Vector3 MOVE_RIGHT = new Vector3(1, 0, 0);
 38     //上移动
 39     private Vector3 MOVE_UP = new Vector3(0, 1, 0);
 40 
 41     //外部调控速度
 42     public float speed = 2f;
 43     //移动速度向量
 44     private Vector3 move_speed_dir = Vector3.zero;
 45     //移动距离
 46     private Vector3 move_dis = Vector3.zero;
 47 
 48     //控制目标
 49     public Transform target;
 50 
 51     // Use this for initialization
 52     void Start () {
 53         
 54     }
 55     
 56     // Update is called once per frame
 57     void Update () {
 58         CheckInputKey();
 59         CheckMoveDir();
 60     }
 61 
 62     void FixedUpdate()
 63     {
 64         CheckMove();
 65     }
 66 
 67     //检测输入按键
 68     void CheckInputKey()
 69     {
 70         //检测单一输入
 71         foreach (KeyCode kcode in System.Enum.GetValues(typeof(KeyCode)))
 72         {
 73             if (Input.GetKeyDown(kcode))
 74             {
 75                 //Debug.Log("Single KeyCode: " + kcode);
 76                 ChangeKeyPressState(kcode, true);
 77             }
 78 
 79             if (Input.GetKeyUp(kcode))
 80             {
 81                 //Debug.Log("Single KeyCode: " + kcode);
 82                 ChangeKeyPressState(kcode, false);
 83             }
 84         }
 85     }
 86 
 87     //记录按键的按压状态
 88     void ChangeKeyPressState(KeyCode keyCode, bool isPress)
 89     {
 90         switch(keyCode)
 91         {
 92             case INPUT_UP:
 93                 isUpPress = isPress;
 94                 break;
 95             case INPUT_DOWN:
 96                 isDownPress = isPress;
 97                 break;
 98             case INPUT_LEFT:
 99                 isLeftPress = isPress;
100                 break;
101             case INPUT_RIGHT:
102                 isRightPress = isPress;
103                 break;
104         }
105     }
106 
107     //确定移动方向
108     void CheckMoveDir()
109     {
110         //确定方向
111         if(isUpPress && isLeftPress)
112         {
113             moveDir = MoveDir.UL;
114         }
115         else if(isUpPress && isRightPress)
116         {
117             moveDir = MoveDir.UR;
118         }
119         else if (isDownPress && isLeftPress)
120         {
121             moveDir = MoveDir.DL;
122         }
123         else if (isDownPress && isRightPress)
124         {
125             moveDir = MoveDir.DR;
126         }
127         else if(isUpPress)
128         {
129             moveDir = MoveDir.Up;
130         }
131         else if (isDownPress)
132         {
133             moveDir = MoveDir.Down;
134         }
135         else if (isLeftPress)
136         {
137             moveDir = MoveDir.Left;
138         }
139         else if (isRightPress)
140         {
141             moveDir = MoveDir.Right;
142         }
143         else
144         {
145             moveDir = MoveDir.None;
146         }
147     }
148 
149     //检测是否可以移动
150     void CheckMove()
151     {
152         //某些情况下可能禁止移动,例如暂停,播放CG等
153         if(canMove && moveDir != MoveDir.None)
154         {
155             PlayerMove(target, speed);
156         }
157     }
158 
159     //移动
160     void PlayerMove(Transform target, float speed)
161     {
162         move_dis = speed * Time.deltaTime * GetSpeedDir();
163         target.position += move_dis;
164     }
165 
166     //速度向量
167     Vector3 GetSpeedDir()
168     {
169         switch(moveDir)
170         {
171             case MoveDir.Up:
172                 move_speed_dir = MOVE_UP;
173                 break;
174             case MoveDir.Down:
175                 move_speed_dir = -MOVE_UP;
176                 break;
177             case MoveDir.Left:
178                 move_speed_dir = -MOVE_RIGHT;
179                 break;
180             case MoveDir.Right:
181                 move_speed_dir = MOVE_RIGHT;
182                 break;
183             case MoveDir.UL:
184                 move_speed_dir = MOVE_UP - MOVE_RIGHT;
185                 break;
186             case MoveDir.UR:
187                 move_speed_dir = MOVE_UP + MOVE_RIGHT;
188                 break;
189             case MoveDir.DL:
190                 move_speed_dir = -MOVE_UP - MOVE_RIGHT;
191                 break;
192             case MoveDir.DR:
193                 move_speed_dir = -MOVE_UP + MOVE_RIGHT;
194                 break;
195         }
196         return move_speed_dir.normalized;
197     }
198 }
update()里面每帧检测CheckInputKey(),是否有按键按下或者抬起,ChangeKeyPressState()这个方法里面记下来当前有哪些按键输入。
CheckMoveDir()这个方法就是专门为了根据按下的按键的值来判断,合方向是枚举中的哪一种
CheckMove(),PlayerMove()这两个方法就是检测当前能不能移动,能移动的话就移动
GetSpeedDir()这个方法里面就是根据方向枚举,确定移动的方向向量,确定完合方向后,记得要用.normalized取单位长度,这样就能保证斜方向速度与正交方向速度相同。


-------------------另一种思路解决多按键同时按下控制移动-----------------
上面那种方法,
CheckMoveDir()判断按下按键转换方向时,只处理了一个按键按下,和两个按键同时按下,那么如果我同时按下三个按键或者四个按键时候就会出问题
下面是修改
    //移动方向枚举
    enum MoveDir
    {
        None = 0,       //不动
        Up = 1,         //上8
        Down = -1,      //下2
        Left = 10,      //左4
        Right = -10,    //右6
        UL = 11,        //左上7
        UR = -9,        //右上9
        DL = 9,         //左下1
        DR = -11,       //右下3
    }

枚举方向定义了不同的值

//确定移动方向
    void CheckMoveDir()
    {
        moveDirValue = 0;
        //确定方向
        if(isUpPress)
        {
            moveDirValue += (int)MoveDir.Up;
        }
        if (isDownPress)
        {
            moveDirValue += (int)MoveDir.Down;
        }
        if (isLeftPress)
        {
            moveDirValue += (int)MoveDir.Left;
        }
        if (isRightPress)
        {
            moveDirValue += (int)MoveDir.Right;
        }

        target.GetComponent<Player>().TurnDir(moveDirValue);
    }

这样同时按下三个按键的时候,必定有两个方向时一对相反的,那么求“合”速度时候,就可以抵消掉,如果四个方向同时按下,就相当于不动了,问题搞定!