使用lua来实现一个自定义的摇杆,lua插件是xlua
摇杆说明:
为了方便观察,Joystick的背景设置成灰色,实际可设置成透明。
默认情况下Background是隐藏的,在Joystick的区域内点击后,会在点击的地方显示出Background,抬起后Background会隐藏,拖拽时Bar会跟随移动,但是会被限制在Backgroun的范围内
实现思路:
这个摇杆控件用到了鼠标点击/抬起/拖拽的事件,这些事件只能在csharp中实现EventSystem提供的接口才能获取,在lua中也想要获取的话,只能由csharp实现接口,提供委托然后lua去注册委托来。
C#代码
using UnityEngine;
using UnityEngine.EventSystems;
public delegate void OnPointerData(PointerEventData eventData);
namespace CF{
public class XLuaEventSystem :MonoBehaviour,IPointerDownHandler,
IPointerUpHandler,IDragHandler,IPointerEnterHandler,IPointerExitHandler{
private static XLuaEventSystem instance;
public static XLuaEventSystem Instance
{
get
{
return instance;
}
}
private void Awake()
{
instance = this;
}
public OnPointerData pointerdown;
public OnPointerData pointerup;
public OnPointerData pointerenter;
public OnPointerData pointerexit;
public OnPointerData pointerdrag;
public void OnPointerDown(PointerEventData eventData)
{
pointerdown?.Invoke(eventData);
}
public void OnPointerUp(PointerEventData eventData)
{
pointerup?.Invoke(eventData);
}
public void OnDrag(PointerEventData eventData)
{
pointerdrag?.Invoke(eventData);
}
public void OnPointerEnter(PointerEventData eventData)
{
pointerenter?.Invoke(eventData);
}
public void OnPointerExit(PointerEventData eventData)
{
pointerexit?.Invoke(eventData);
}
}
}
lua代码
local Joystick = {}
--Background的半径,offset是一个偏移量
local radius = 75
local offset = 10
--预制体加载成功的回调
local function LoadGameObjectCallback(gameobject)
--生成预制体,并放在Canvas下
local prefab = CS.CF.PrefabsManager.Instantiate(gameobject,CS.CF.TransformManager.Find("Canvas"))
--设置初始位置为左下角
prefab.transform.anchoredPosition = CS.UnityEngine.Vector2(-284,-150)
--添加XLuaEventSystem脚本,这个脚本实现了EventSystem事件接口
prefab:AddComponent(typeof(CS.CF.XLuaEventSystem))
--对复用的变量进行存储
Joystick.Instance = CS.CF.XLuaEventSystem.Instance
Joystick.Background = Joystick.Instance.transform:Find("Background")
Joystick.Bar = Joystick.Instance.transform:Find("Background/Bar")
--向csharp中注册委托
Joystick.Instance.pointerdown = OnPointerDown
Joystick.Instance.pointerup = OnPointerUp
Joystick.Instance.pointerdrag = OnDrag
end
--从Ab包中加载Joystick预制体
local function OnStart()
CS.CF.AssetBundleManager.LoadGameObject(
BootStrap.Configs.AssetBundlePath,
"startmain",
"Joystick",
LoadGameObjectCallback
)
end
OnStart()
------------------------------------ EventSystem -------------------------------
local function OnPointerDown(eventData)
local _,outPos = CS.UnityEngine.RectTransformUtility.ScreenPointToLocalPointInRectangle(
Joystick.Instance.transform,
eventData.position,
eventData.pressEventCamera,
outPos
)
Joystick.Background.gameObject:SetActive(true)
Joystick.Background.anchoredPosition = outPos
end
local function OnPointerUp(eventData)
Joystick.Background.gameObject:SetActive(false)
Joystick.Bar.anchoredPosition = CS.UnityEngine.Vector2.zero
end
local function OnDrag(eventData)
local _,outPos = CS.UnityEngine.RectTransformUtility.ScreenPointToLocalPointInRectangle(
Joystick.Background,
eventData.position,
eventData.pressEventCamera,
outPos
)
if(outPos.magnitude > (radius - offset)) then
outPos = outPos.normalized * (radius - offset)
end
Joystick.Bar.anchoredPosition = outPos
end
------------------------------------ EventSystem -------------------------------
return Joystick
lua中用到的CS.CF.AssetBundleManager/CS.CF.PrefabsManager/CS.CF.TransformManager是csharp编写的工具类用于加载ab包,创建prefab,查找transform子物体
if(outPos.magnitude > (radius - offset)) then
outPos = outPos.normalized * (radius - offset)
end
上面这段代码是将Bar限制在Background的范围内,实现的思路如下
- 当手在Background内滑动时,Bar和手的位置一致
- 当手滑出Background,如到红点的位置时,应该把Bar限制到绿点的位置上
因此通过判断向量的长度是否大于Background半径,就知道手是否在Background范围内。怎么把红点限制在绿点上呢,已知红点向量,取模得到长度为一的红色方向向量,再乘以半径就得到绿点的位置。