目录
零.参考资料
1.视频
基于Unity New Input System实现的类似moba游戏的虚拟摇杆
2.文章
官方文档
新输入系统InputSystem简介(一)
新输入系统InputSystem简介(二)
一.基本步骤
注1:参考资料视频中有比较详细的介绍,以下步骤仅记录简要步骤。
注2:以下步骤以安装InputSystem插件并完成工程配置为前提,关于插件安装,“参考资料” - “文章”中有详细介绍。
1.配置InputAction文件
1.1创建InputAction文件
(Project窗口中)右键 ☛ Create ☛ InputActions
1.2配置InputAction文件
1.3生成InputAction类文件
2.挂载OnSenceSticks脚本
3.绑定事件
截取控制移动关键代码
public class PlayerController : MonoBehaviour
{
//前文通过InputAction生成的类
private MyInputAction inputActions;
void Start()
{
inputActions = new MyInputAction();
inputActions.Enable();
inputActions.Player.Move.performed += Player_Move_Performed;
inputActions.Player.Move.canceled += Player_Move_Canceled;
}
private void FixedUpdate()
{
//弧度转角度
float angle = Mathf.Atan2(aimDir.y, aimDir.x) * 180 / Mathf.PI;
Quaternion targetRot = Quaternion.Euler(new Vector3(0, 0, angle - 90));
playerModel.rotation = Quaternion.Lerp(playerModel.rotation, targetRot, rotationSpeed * Time.deltaTime);
rigidbody2D.AddForce(moveDir.normalized * moveForceSpeed, ForceMode2D.Impulse);
}
private void Player_Move_Performed(InputAction.CallbackContext context)
{
moveDir = context.ReadValue<Vector2>();
}
private void Player_Move_Canceled(InputAction.CallbackContext context)
{
moveDir = Vector2.zero;
}
}
x.效果
二.扩展
基于OnSenceSticks
脚本进行功能扩展。
1.实现的效果:
未接触屏幕时 | 接触屏幕时 | 移动时 |
---|---|---|
隐藏/显示 | 摇杆显示,摇杆背景固定在默认位置 | 摇杆背景固定在默认位置 ,摇杆跟随触摸位置或者触摸方向 |
隐藏/显示 | 摇杆显示,摇杆背景出现在触摸位置 | 摇杆背景固定在触摸位置 ,摇杆跟随触摸位置或者触摸方向 |
隐藏/显示 | 摇杆显示, 摇杆背景出现在触摸位置 | 摇杆背景和摇杆均跟随触摸位置 |
2.思路&概括
1.多根手指触摸屏幕时,将摇杆的控制权分配给在点击区域范围内的第一根手指产生的Touch。
2.不想每一帧都去检测Touch状态,因此通过预先放置点击区域的UI和OnPointerDown
实现只有在触摸屏幕时进行状态检测。
3.代码实现
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.EnhancedTouch;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.Serialization;
[AddComponentMenu("Input/虚拟摇杆 - 新输入系统(InputSystem)")]
public class JoyStick_InputSystem : OnScreenControl, IPointerDownHandler
{
enum JoyStickType
{
[InspectorName("固定在默认位置")]
FixedInDefaultPosition = 0,
[InspectorName("固定在触摸位置")]
FixedInClickPosition = 1,
[InspectorName("跟随触摸移动")]
Flexible = 2
}
[Header("基础设置")]
[Tooltip("摇杆背景")]
[SerializeField]
private RectTransform joyStickBackGround;
[Tooltip("摇杆按钮")]
[SerializeField]
private RectTransform joyStickButton;
[Tooltip("摇杆按钮移动范围(半径)")]
[FormerlySerializedAs("movementRange")]
[SerializeField]
private float movementRange = 50;
[Tooltip("控制设备路径")]
[InputControl(layout = "Vector2")]
[SerializeField]
private new string controlPath;
[Header("类型设置")]
[Tooltip("摇杆类型")]
[SerializeField]
private JoyStickType joyStickType;
[Tooltip("摇杆是否默认隐藏")]
[SerializeField]
private bool isHideWithoutTouch;
//触摸屏(设备)
private Touchscreen currentTouchScreen;
//控制摇杆的触点对象
private TouchControl joyStickTouch;
//摇杆初始位置
private Vector2 joyStickStartPos;
//与屏幕相关的相机(主要用于将屏幕上的位置转换为某UI矩形内的相对位置)
private Camera screenCamera;
//模拟(鼠标或者笔)输入
private TouchSimulation touchSimulation;
//画布渲染模式
private RenderMode renderMode;
//点击区域UI的RectTransform
private RectTransform rectTransform;
protected override string controlPathInternal
{
get => controlPath;
set => controlPath = value;
}
private void Awake()
{
#if UNITY_EDITOR
if (!gameObject.TryGetComponent(out touchSimulation))
{
touchSimulation = gameObject.AddComponent<TouchSimulation>();
}
#endif
}
private void Start()
{
currentTouchScreen = Touchscreen.current;
//记录摇杆初始位置
joyStickStartPos = joyStickBackGround.anchoredPosition;
if (isHideWithoutTouch)
{
joyStickBackGround.gameObject.SetActive(false);
}
//获取画布的渲染模式
var canvas = transform.GetComponentInParent<Canvas>();
renderMode = canvas != null ? canvas.renderMode : RenderMode.ScreenSpaceOverlay;
//获取点击区域UI的RectTransform
rectTransform = transform.GetComponent<RectTransform>();
}
private void Update()
{
UpdateJoyStickUIPos();
}
private void OnDestroy()
{
#if UNITY_EDITOR
touchSimulation = null;
#endif
}
public void OnPointerDown(PointerEventData eventData)
{
//获取与屏幕相关的相机
if (renderMode != RenderMode.ScreenSpaceOverlay)
{
screenCamera = eventData.pressEventCamera;
}
//摇杆没有被控制时分配控制权
if (joyStickTouch == null)
{
for (int i = 0; i < currentTouchScreen.touches.Count; i++)
{
var touch = currentTouchScreen.touches[i];
if (touch.phase.ReadValue() == UnityEngine.InputSystem.TouchPhase.Began)
{
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, touch.position.ReadValue(), screenCamera))
{
joyStickTouch = touch;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, joyStickTouch.position.ReadValue(), screenCamera, out var joyStickBgPos);
SetJoyStickUI(joyStickBgPos, Vector2.zero, true);
}
}
}
}
}
private void UpdateJoyStickUIPos()
{
if (joyStickTouch == null)
return;
bool isActive = true;
Vector2 joyStickBgPos = Vector2.zero;
Vector2 joyStickBtnPos = Vector2.zero;
Vector2 sendToControlValue = Vector2.zero;
switch (joyStickTouch.phase.ReadValue())
{
case UnityEngine.InputSystem.TouchPhase.None:
break;
case UnityEngine.InputSystem.TouchPhase.Began:
case UnityEngine.InputSystem.TouchPhase.Moved:
//更新摇杆位置数据
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, joyStickTouch.position.ReadValue(), screenCamera, out var touchInRectPos);
Vector2 delta = touchInRectPos - joyStickBackGround.anchoredPosition;
joyStickBgPos = joyStickBackGround.anchoredPosition;
if (joyStickType == JoyStickType.Flexible)
{
if (delta.magnitude > movementRange)
{
joyStickBgPos += delta.normalized * (delta.magnitude - movementRange);
}
}
joyStickBtnPos = Vector2.ClampMagnitude(delta, movementRange);
isActive = true;
sendToControlValue = delta / movementRange;
break;
case UnityEngine.InputSystem.TouchPhase.Ended:
case UnityEngine.InputSystem.TouchPhase.Canceled:
//收回Touch对摇杆的控制权
joyStickTouch = null;
joyStickBgPos = joyStickStartPos;
isActive = false;
break;
case UnityEngine.InputSystem.TouchPhase.Stationary:
break;
}
//设置摇杆位置
SetJoyStickUI(joyStickBgPos, joyStickBtnPos, isActive);
//给控制器发送新位置
SendValueToControl(sendToControlValue);
}
private void SetJoyStickUI(Vector2 joyStickBgPos, Vector2 joyStickBtnPos, bool isActive)
{
//设置joyStickBackGround位置
switch (joyStickType)
{
case JoyStickType.FixedInDefaultPosition:
break;
case JoyStickType.FixedInClickPosition:
case JoyStickType.Flexible:
joyStickBackGround.anchoredPosition = joyStickBgPos;
break;
}
//设置joyStickButton位置
joyStickButton.anchoredPosition = joyStickBtnPos;
//设置
if (isHideWithoutTouch && joyStickBackGround.gameObject.activeSelf != isActive)
{
joyStickBackGround.gameObject.SetActive(isActive);
}
}
}
4.使用
之后再按照“基本步骤”中的“绑定事件”就可以了。
本人新手,文章本是个人记录,仅供参考,如有不足和错误,欢迎指正。