概述

之前代码中,我们总会去判断按键的输入,然而由于Input又臭又长的函数名和必须赋予的动作名称,代码看起来很不美观。所以这节我们使用Godot的自动加载功能,也就是创建单例的方法来将按键处理封装为一个简单的全局对象,然后再调用其中封装的函数来重构我们的代码。

mInput.gd

image.png image.png
  1. # mInput.gd 加载为单例,全局可用。
  2. extends Node
  3. # 将会使用到的动作名称保存到相应的变量
  4. var left_action = "ui_left"
  5. var right_action = "ui_right"
  6. var up_action = "ui_up"
  7. var down_action = "ui_down"
  8. var jump_action = "ui_accept"
  9. # 封装Input.is_action_just_pressed()
  10. func just_pressed(action:String) -> bool:
  11. return Input.is_action_just_pressed(action)
  12. # 封装Input.is_action_pressed()
  13. func pressed(action:String) -> bool:
  14. return Input.is_action_pressed(action)
  15. # 跳跃
  16. func input_jump() -> bool:
  17. return just_pressed(jump_action)
  18. # 获取水平方向上的方向或按键力度
  19. func get_x():
  20. return Input.get_axis(left_action,right_action)
  21. # 获取垂直方向上的方向或按键力度
  22. func get_y():
  23. return Input.get_axis(left_action,right_action)
  24. # 获取上下左右按键所取得的方向向量。
  25. func get_dir():
  26. return Input.get_vector(left_action,right_action,up_action,down_action)

代码分析

可以看到,首先我们使用变量来存储我们将要用到的动作名称,然后我们封装了Input.is_action_just_pressed和Input.is_action_pressed,最后再封装各种函数来对应我们常用的输入,比如,跳跃、左右移动或上下移动以及在平面移动时获取的方向或力度以及方向向量。

用自动加载创建单例

我们在项目设置、自动加载下添加我们的mInput.gd代码为单例MInput。
image.png

用单例重构代码

此时我们就可以在本项目的任何场景中将MInput作为一个全局对象直接访问了,当然也包括它的各种成员变量和方法。所谓单例就是在整个声明周期中只有一个实例的类,简单的也可以理解为全局对象。
此时,我们再次重构上一节的代码:

代码

image.png image.png image.png

原始代码

  1. extends KinematicBody2D
  2. var speed = 60.0 # 速度 像素/秒
  3. var velocity = Vector2.ZERO # 速度向量
  4. var gravity = 3000 # 重力加速度
  5. var jump_force = 3000.0 # 单次跳跃高度
  6. var is_jumping = false
  7. enum states {
  8. ON_FLOOR, # 在地面上
  9. IN_AIR # 在空中
  10. }
  11. var _state = states.IN_AIR
  12. func _physics_process(delta):
  13. velocity = Vector2.ZERO
  14. match _state:
  15. # 在地面
  16. states.ON_FLOOR:
  17. # 边缘掉落
  18. if not is_on_floor():
  19. change_state_to(states.ON_FLOOR)
  20. is_jumping = false
  21. return
  22. # 左右移动
  23. velocity.x = MInput.get_x() * speed
  24. # 实现下落 -- 用于边缘下落
  25. velocity.y += gravity * delta
  26. # 跳跃
  27. if MInput.input_jump():
  28. velocity.y = -jump_force
  29. change_state_to(states.IN_AIR)
  30. is_jumping = true
  31. velocity = move_and_slide(velocity,Vector2.UP)
  32. # 在空中
  33. states.IN_AIR:
  34. # 掉到地板
  35. if is_on_floor():
  36. change_state_to(states.ON_FLOOR)
  37. is_jumping = false
  38. return
  39. # 左右移动
  40. velocity.x = MInput.get_x() * speed
  41. # 实现下落 -- 用于边缘下落
  42. velocity.y += gravity * delta
  43. # 跳跃 -- 二级跳
  44. if is_jumping and MInput.input_jump():
  45. velocity.y = -jump_force
  46. change_state_to(states.IN_AIR)
  47. is_jumping = false
  48. velocity = move_and_slide(velocity,Vector2.UP)
  49. pass
  50. # 更改状态
  51. func change_state_to(new_state:int):
  52. _state = new_state
  53. # 根据不同的状态,进行一些额外配置
  54. match _state:
  55. states.IN_AIR:
  56. pass
  57. states.ON_FLOOR:
  58. pass

总结

可以看到,通过调用MInput单例(或者你可以叫全局对象),你可以避开以往又臭又长的按键检测代码。
当然,本节的按键处理单例还只是个初步的玩法,你完全可以更进一步的封装来彻底简化Input和InputMap相关的代码。当然,这种模式也是可以跨游戏项目复用的,基本原理有了,具体怎么写怎么实现都无所谓了。