18.NGUI进阶-EventListener和EventTrigger特殊事件监听相关
18.1 知识点
控件自带事件的局限性
- 目前复合控件只提供了一些常用的事件监听方式,比如:
- Button —— 点击
uIButton.onClick.Add(new EventDelegate(ClickDoSomthing));
- Toggle —— 值变化
uIToggle.onChange.Add(new EventDelegate(Change));
- Button —— 点击
- 如果想要制作按下、抬起、长按等功能,利用现有的知识是无法完成的。
NGUI事件响应函数
- NGUI事件响应函数是用于添加了碰撞器的对象挂载脚本,在脚本中写入响应函数和逻辑。即写好逻辑事件响应函数脚本挂载到添加了碰撞器的控件。
- NGUI提供了一些利用反射调用的函数。原理是NGUI会在EventSystem不停地检测玩家输入,当触发到某种输入时,会去触发对象身上的各个脚本找是否有对应的函数,有的话执行对应事件。
常用NGUI事件响应函数有
- 经过
OnHover(bool isOver)
- 按下
OnPress(bool pressed)
- 点击
OnClick()
- 双击
OnDoubleClick()
- 拖曳开始
OnDragStart()
- 拖曳中
OnDrag(Vector2 delta)
- 拖曳结束
OnDragEnd()
- 拖曳经过某对象
OnDragOver(GameObject go)
- 拖曳离开某对象
OnDragOut(GameObject go)
- 等等等等
NGUI事件响应函数代码
void OnPress(bool pressed)
{
if (pressed)
{
print("按下");
}
else
{
print("抬起");
}
}
void OnHover(bool isOver)
{
if (isOver)
{
print("鼠标经过");
}
else
{
print("鼠标离开");
}
}
void OnClick()
{
print("点击相关");
}
void OnDoubleClick()
{
print("双击相关");
}
void OnDragStart()
{
print("开始拖曳");
}
void OnDrag(Vector2 delta)
{
print("拖曳中" + delta);
}
void OnDragEnd()
{
print("拖曳结束");
}
void OnDragOver(GameObject obj)
{
// 这个函数传进来的是拖的对象是谁
print("拖曳经过" + obj.name);
}
void OnDragOut(GameObject obj)
{
// 这个函数传进来的是拖的对象是谁
print("拖曳离开" + obj.name);
}
更加方便事件监听的UIEventListener和UIEventTrigger
- 如果使用上述的NGUI事件响应函数,那么Panel下的所有子控件都要写一个脚本挂上去,很不方便、不面向对象。
- NGUI提供了更加方便的UIEventListener和UIEventTrigger。
- UIEventListener和UIEventTrigger帮助我们封装了所有特殊响应函数,可以通过它们进行事件监听管理添加。
UIEventListener 用代码给对象添加事件监听
UIEventListener uIEventListener = UIEventListener.Get(UISpriteA.gameObject);
uIEventListener.onPress += (obj, isPress) => {
print(obj.name + "被按下或者抬起了" + isPress);
};
uIEventListener.onDragStart += BeginDrag;
private void BeginDrag(GameObject obj)
{
print(obj.name + "开始拖曳");
}
UIEventTrigger 在Inspector面板给UISpriteB添加UIEventTrigger脚本 添加按下事件监听
UIEventListener和UIEventTrigger区别
- Listener更适合代码添加监听,Trigger适合拖曳对象添加监听。
- Listener传入的参数更具体,Trigger则不会传入参数,我们需要在函数中去判断处理逻辑。
18.2 知识点代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson18_NGUI进阶_EventListener和EventTrigger特殊事件监听相关 : MonoBehaviour
{
public UISprite UISpriteA;
public UISprite UISpriteB;
void Start()
{
#region 知识点一 控件自带事件的局限性
//目前复合控件只提供了一些常用的事件监听方式
//比如
//Button —— 点击 uIButton.onClick.Add(new EventDelegate(ClickDoSomthing));
//Toggle —— 值变化 uIToggle.onChange.Add(new EventDelegate(Change));
//等等
//如果想要制作 按下 抬起 长按等功能 利用现在的知识是无法完成的
#endregion
#region 知识点二 NGUI事件响应函数
//NGUI事件响应函数的是用于添加了碰撞器的对象 挂载脚本 脚本中写入响应函数和逻辑
//NGUI提供了一些利用反射调用的函数
//原理是NGUI会在EventSystem不停的检测玩家输入
//当触发到某种输入时 回去触发对象身上的各个脚本找是否有对应的函数
//有的话执行对应事件
//常用NGUI事件响应函数有
//经过 OnHover(bool isOver)
//按下 OnPress(bool pressed)
//点击 OnClick()
//双击 OnDoubleClick()
//拖曳开始 OnDragStart()
//拖曳中 OnDrag(Vector2 delta)
//拖曳结束 OnDragEnd()
//拖曳经过某对象 OnDragOver(GameObject go)
//拖曳离开某对象 OnDragOut(GameObject go)
//等等等等
#endregion
#region 知识点三 更加方便事件监听的UIEventListener和UIEventTrigger
//如果用上面的NGUI事件响应函数 那么Panel下的所有子空间都要写一个脚本挂上去 很不方便 不面向对象
//NGUI提供了更加方便的UIEventListener和UIEventTrigger
//UIEventListener和UIEventTrigger帮助我们封装了所有 特殊响应函数
//可以通过它们进行事件监听管理添加
//UIEventListener 用代码给对象添加事件监听
//调用UIEventListener的Get方法 获得想要添加监听的游戏对象的UIEventListener脚本 假如没有就会加一个UIEventListener脚本 有就直接拿
UIEventListener uIEventListener = UIEventListener.Get(UISpriteA.gameObject);
//UIEventListener这个类里定义了很多委托和委托变量 和NGUI事件响应函数名字大多一样 可以给对应委托添加监听
//鼠标按下或抬起添加监听
uIEventListener.onPress += (obj, isPress) => {
print(obj.name + "被按下或者抬起了" + isPress);
};
//开始拖曳时添加监听
uIEventListener.onDragStart += BeginDrag;
//UIEventTrigger 在Inspector面板添加UIEventTrigger脚本给对象添加事件监听
//UIEventListener和UIEventTrigger区别
//1.Listener更适合 代码添加监听 Trigger适合拖曳对象添加监听
//2.Listener传入的参数 更具体 Trigger就不会传入参数 我们需要在函数中去判断处理逻辑
#endregion
}
#region 知识点三 更加方便事件监听的UIEventListener和UIEventTrigger
private void BeginDrag(GameObject obj)
{
print(obj.name + "开始拖曳");
}
public void Press()
{
}
#endregion
#region 知识点二 NGUI事件响应函数
void OnPress(bool pressed)
{
if (pressed)
{
print("按下");
}
else
{
print("抬起");
}
}
void OnHover(bool isOver)
{
if (isOver)
{
print("鼠标经过");
}
else
{
print("鼠标离开");
}
}
void OnClick()
{
print("点击相关");
}
void OnDoubleClick()
{
print("双击相关");
}
void OnDragStart()
{
print("开始拖曳");
}
void OnDrag(Vector2 delta)
{
print("拖曳中" + delta);
}
void OnDragEnd()
{
print("拖曳结束");
}
void OnDragOver(GameObject obj)
{
//这个函数传进来的是拖的对象是谁
print("拖曳经过" + obj.name);
}
void OnDragOut(GameObject obj)
{
//这个函数传进来的是拖的对象是谁
print("拖曳离开" + obj.name);
}
#endregion
}
18.3 练习题
在Anchor锚点的练习题基础上,请用现在所学知识,制作一个这样的功能,制作一个NGUI摇杆可以控制场景上的坦克移动
在GamePanel下创建一大一小两个Sprite作为摇杆背景和摇杆,小的摇杆是大摇杆背景的子物体并且层级更高。给小的摇杆添加碰撞器
在GamePanel脚本中创建一个Sprite对象并关联小的摇杆Sprite,在拖拽摇杆时添加移动摇杆和玩家移动的监听,在停止拖拽摇杆是恢复摇杆位置并让玩家停止移动
#region Lesson18_NGUI进阶_EventListener和EventTrigger特殊事件监听相关练习题
public UISprite controller;
#endregion
void Start()
{
#region Lesson18_NGUI进阶_EventListener和EventTrigger特殊事件监听相关练习题
UIEventListener listener = UIEventListener.Get(controller.gameObject);
// 通过给控制图标 GameObject 对象添加的 UIEventListener 组件来监听鼠标/手指的拖曳操作
listener.onDrag = (obj, vector) => {
// 根据拖曳偏移量实现控制图标跟随鼠标移动 给本地坐标加位置 本地坐标默认(0,0)
controller.transform.localPosition += new Vector3(vector.x, vector.y, 0);
// 判断是否超出了可拖曳区域,并进行限制,使其不至于越过设定的最大半径 magnitude是向量求模
if (controller.transform.localPosition.magnitude > 130)
//大于最大拖拽区域就把他变成130 normalized是该方向的单位向量
controller.transform.localPosition = controller.transform.localPosition.normalized * 130;
// 根据摇杆控制图标位置计算出摇杆操纵的移动方向(以世界坐标系下的 x-z 平面为基础)
Vector2 dir = new Vector2(controller.transform.localPosition.x,
controller.transform.localPosition.y).normalized;
// 更改玩家对象当前的朝向和位移信息
player.Move(dir);
};
listener.onDragEnd = (obj) =>
{
// 拖放结束后,重置摇杆图标回到原点位置
controller.transform.localPosition = Vector3.zero;
// 结束时让玩家停止移动
player.StopMove();
};
#endregion
}
理清摇杆偏移的方向向量和坦克要移动的方向向量的映射逻辑
在TankObj脚本中,添加移动相关的变量。在Update判断要移动时,设置坦克边旋转边向前走。
// 定义一个TankObj类,继承自MonoBehaviour
public class TankObj : MonoBehaviour
{
// 移动速度
public float moveSpeed = 10;
// 旋转速度
public float roundSpeed = 20;
// 移动标识
private bool isMoving = false;
// 要移动的方向向量
private Vector3 moveDir;
// 更新函数,在每一帧执行
private void Update()
{
// 判断坦克是否处于移动状态来进行相应的逻辑处理
if (isMoving)
{
// 坦克沿着前方方向移动
this.transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
// 旋转坦克使其朝向移动方向 用Lerp插值计算Quaternion之间的插值转换,第三个参数表示在0到1之间进行插值,越接近1就越靠近目标值
this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.LookRotation(moveDir), roundSpeed * Time.deltaTime);
}
}
// 传入移动方向
public void Move(Vector3 dir)
{
// 设置实际要转的角度 摇杆的x轴对应坦克的x轴 摇杆的y轴对应坦克的z轴
moveDir.x = dir.x;
moveDir.z = dir.y;
isMoving = true; // 设置为移动状态
}
// 停止移动
public void StopMove()
{
isMoving = false;
}
}
18.4 练习题代码
GamePanel
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GamePanel : MonoBehaviour
{
private static GamePanel instance;
public static GamePanel Instance => instance;
public UIButton btn;
public TankObj player;
public UIToggle togSound;
public UILabel labName;
public UIButton btnChangeName;
#region Lesson13_NGUI基础_组合控件_PopupList下拉列表练习题
public UIPopupList list;
public Light lightObj;
#endregion
#region Lesson14_NGUI基础_组合控件_Slider滑动条练习题
public UISlider sliderSound;
#endregion
#region Lesson15_NGUI基础_组合控件_ScrollBar滚动条和ProgressBar进度条练习题
public UIProgressBar progressBar;
#endregion
#region Lesson18_NGUI进阶_EventListener和EventTrigger特殊事件监听相关练习题
public UISprite controller;
#endregion
private void Awake()
{
instance = this;
}
void Start()
{
btn.onClick.Add(new EventDelegate(() =>
{
player.Fire();
}));
togSound.onChange.Add(new EventDelegate(() =>
{
MusicData.isOpenSound = togSound.value;
}));
btnChangeName.onClick.Add(new EventDelegate(() =>
{
ChangeNamePanel.Instance.gameObject.SetActive(true);
}));
#region Lesson13_NGUI基础_组合控件_PopupList下拉列表练习题
list.onChange.Add(new EventDelegate(() =>
{
switch (list.value)
{
case "白天":
lightObj.intensity = 1;
break;
case "黑夜":
lightObj.intensity = 0.2f;
break;
}
}));
#endregion
#region Lesson14_NGUI基础_组合控件_Slider滑动条练习题
sliderSound.onChange.Add(new EventDelegate(() =>
{
MusicData.soundValue = sliderSound.value;
}));
#endregion
#region Lesson15_NGUI基础_组合控件_ScrollBar滚动条和ProgressBar进度条练习题
HideHpPro();
#endregion
#region Lesson16_NGUI基础_组合控件_ScrollView滚动视图练习题
btnBag.onClick.Add(new EventDelegate(() =>
{
BagPanel.Instance.gameObject.SetActive(true);
}));
#endregion
#region Lesson18_NGUI进阶_EventListener和EventTrigger特殊事件监听相关练习题
UIEventListener listener = UIEventListener.Get(controller.gameObject);
listener.onDrag = (obj, vector) =>
{
controller.transform.localPosition += new Vector3(vector.x, vector.y, 0);
if (controller.transform.localPosition.magnitude > 130)
controller.transform.localPosition = controller.transform.localPosition.normalized * 130;
Vector2 dir = new Vector2(controller.transform.localPosition.x,
controller.transform.localPosition.y).normalized;
player.Move(dir);
};
listener.onDragEnd = (obj) =>
{
controller.transform.localPosition = Vector3.zero;
player.StopMove();
};
#endregion
}
/// <summary>
/// 显示蓄能条
/// </summary>
public void ShowHpPro()
{
progressBar.gameObject.SetActive(true);
}
/// <summary>
/// 隐藏蓄能条
/// </summary>
public void HideHpPro()
{
progressBar.gameObject.SetActive(false);
}
/// <summary>
/// 更新蓄能条
/// </summary>
/// <param name="nowValue"></param>
/// <param name="maxValue"></param>
public void UpdatePro(float nowValue, float maxValue)
{
progressBar.value = nowValue / maxValue;
}
}
TankObj
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankObj : MonoBehaviour
{
public float moveSpeed = 10;
public float roundSpeed = 20;
public Transform shootPos;
private AudioClip clip;
private float nowTime;
public int nowHp = 100;
private bool isMoving = false;
private Vector3 moveDir;
public void Fire()
{
AudioSource source = this.gameObject.AddComponent<AudioSource>();
if (clip == null)
clip = Resources.Load<AudioClip>("Sound/CannonShoot");
source.clip = clip;
source.volume = MusicData.soundValue;
source.mute = !MusicData.isOpenSound;
source.Play();
Destroy(source, 2);
Instantiate(Resources.Load<GameObject>("Obj/Bullet"), shootPos.position, shootPos.rotation);
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
GamePanel.Instance.ShowHpPro();
nowTime = 0;
GamePanel.Instance.UpdatePro(nowTime, 5);
}
else if (Input.GetMouseButtonUp(0))
{
GamePanel.Instance.HideHpPro();
}
else if (Input.GetMouseButton(0))
{
nowTime += Time.deltaTime;
GamePanel.Instance.UpdatePro(nowTime, 5);
if (nowTime >= 5)
{
nowTime = 0;
nowHp += 5;
print("当前血量" + nowHp);
}
}
if (isMoving)
{
this.transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.LookRotation(moveDir), roundSpeed * Time.deltaTime);
}
}
public void Move(Vector3 dir)
{
moveDir.x = dir.x;
moveDir.z = dir.y;
isMoving = true;
}
public void StopMove()
{
isMoving = false;
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com