Điều khiển cảm ứng, joystick
Assets/
Scenes/
Arena.unity
Scripts/
Settings/
đã có sẵnbài này thêm
Nhờ bài trước đã cho mọi thứ đi qua InputRouter, ở bài này bạn không phải sửa một script gameplay nào. Knight đã sẵn sàng nhận input từ bất cứ thứ gì điền được vào action Move.
Điều khiển cảm ứng không phải một game riêng. Nó chỉ là lớp UI tạo ra đúng cái Vector2 mà bàn phím vẫn tạo ra.
Ngón cái kéo núm, núm thành hướng, hướng đưa vào đúng action Move.
Cách nhanh nhất: On-Screen Controls
- 1
Tạo Canvas: , đặt tên TouchCanvas. Đặt Render Mode = Screen Space Overlay.
- 2
Canvas Scaler → Scale With Screen Size, tham chiếu 1080×1920, Match 0.5. Không có bước này là UI bé tí trên một số máy.
- 3
Thêm Image làm đế cần gạt, và Image con làm núm.
- 4
Gắn component On-Screen Stick vào núm rồi đặt Control Path trỏ tới binding Move.
- 5
Thêm On-Screen Button cho các nút hành động tương tự. Input System giờ thấy như có một tay cầm ảo.
Tự viết cần gạt ảo
Cần gạt tự viết cho bạn điểm gốc trôi theo ngón tay, vùng chết và cảm giác riêng. Khoảng 40 dòng.
using UnityEngine;
using UnityEngine.EventSystems;
public class VirtualJoystick : MonoBehaviour,
IPointerDownHandler, IDragHandler, IPointerUpHandler
{
[SerializeField] private RectTransform knob;
[SerializeField] private float radius = 90f;
[SerializeField] private float deadZone = 0.15f;
private RectTransform baseRect;
public Vector2 Value { get; private set; }
void Awake() => baseRect = GetComponent<RectTransform>();
public void OnPointerDown(PointerEventData e) => OnDrag(e);
public void OnDrag(PointerEventData e)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(
baseRect, e.position, e.pressEventCamera, out Vector2 local);
Vector2 clamped = Vector2.ClampMagnitude(local, radius);
knob.anchoredPosition = clamped;
Vector2 raw = clamped / radius; // -1 .. 1
Value = raw.magnitude < deadZone ? Vector2.zero : raw;
}
public void OnPointerUp(PointerEventData e)
{
knob.anchoredPosition = Vector2.zero;
Value = Vector2.zero; // luôn trả về 0
}
}ScreenPointToLocalPointInRectangle đổi vị trí ngón tay thành toạ độ bên trong cần gạt, bất kể độ phân giải màn hình.
ClampMagnitude giữ núm trong hình tròn thay vì hình vuông — cần gạt hình vuông là thấy sai ngay.
Vùng chết 0.15 chặn nhân vật tự trôi khi ngón cái chỉ đang tì lên màn hình.
Chạm, kéo và camera ở nửa phải
void Update()
{
//nửa phải màn hình xoay camera
foreach (Touch t in Input.touches)
{
if (t.position.x < Screen.width * 0.5f) continue; // nửa trái là cần gạt
if (t.phase != TouchPhase.Moved) continue;
yaw += t.deltaPosition.x * touchSensitivity;
pitch -= t.deltaPosition.y * touchSensitivity;
}
}Luật UI mobile không được bỏ qua
Vùng chạm ít nhất 44 pt trên iOS hoặc 48 dp trên Android — khoảng 7 tới 9 mm. Nhỏ hơn là bấm trượt liên tục.
Chừa hai góc dưới, đừng đặt nút nhỏ ở đó — chỗ đó ngón cái hay tì và trùng cử chỉ hệ thống.
Neo UI vào các góc, đừng neo giữa, rồi tôn trọng Screen.safeArea để tránh tai thỏ.
Thử ở chế độ Simulator (menu thả xuống của Game view → Simulator) với hồ sơ máy thật trước khi build.
using UnityEngine;
[RequireComponent(typeof(RectTransform))]
public class SafeAreaFitter : MonoBehaviour
{
void Start()
{
RectTransform rt = GetComponent<RectTransform>();
Rect safe = Screen.safeArea;
Vector2 min = safe.position;
Vector2 max = safe.position + safe.size;
min.x /= Screen.width; min.y /= Screen.height;
max.x /= Screen.width; max.y /= Screen.height;
rt.anchorMin = min;
rt.anchorMax = max;
rt.offsetMin = rt.offsetMax = Vector2.zero;
}
}