【unity实战】事件(Event)的基本实战使用

文章目录

最终效果

前言

之前我们介绍过委托的用法,具体可以跳转:【unity小技巧】委托(Delegate)的基础使用和介绍

这期来讲讲事件,使用你会发现它和委托真的很像,那么他们具体有什么区别呢?

在Unity中,事件(Event)和委托(Delegate)是两种不同的概念,它们之间有一些区别:

  1. 委托(Delegate)

    • 委托是一种类型,用于引用一个或多个方法。委托可以看作是函数指针或函数的代理。
    • 委托用于实现回调函数、事件处理和方法的动态绑定。
    • 委托是一种类型安全的方式来封装方法调用。
  2. 事件(Event)

    • 事件是建立在委托之上的高级概念,它提供了一种更加简洁、安全的方式来实现观察者模式。
    • 事件使用委托来通知其他对象或类,当特定情况发生时,让它们执行相应的操作。
    • 事件可以通过"+="(添加订阅者)和"-="(移除订阅者)来管理委托的订阅和取消订阅。

何时使用事件和委托

  • 当需要实现一对多的消息传递时,可以使用事件。比如,当某个对象的状态发生变化时,需要通知多个其他对象做出相应的反应。
  • 当需要回调函数或方法引用时,可以使用委托。比如,当某个操作完成后需要执行特定的方法,可以使用委托来实现回调。

综合来说,事件和委托在Unity开发中都有各自的用途,根据具体情况选择合适的方式来实现功能会更加方便和有效。

一、素材

https://assetstore.unity.com/packages/2d/environments/pixel-art-top-down-basic-187605

二、角色金币交互

1. 拾取金币

金币事件,定义当金币增加时触发的事件

csharp 复制代码
public class GoldEvents
{
    public event Action<int> onGoldGained; // 当金币增加时触发的事件
    public void GoldGained(int gold) 
    {
        onGoldGained?.Invoke(gold); // 触发金币增加事件
    }
}

游戏事件管理中心,初始化各种事件

csharp 复制代码
public class GameEventsManager : MonoBehaviour
{
    public static GameEventsManager instance { get; private set; } // 单例实例
    
    public GoldEvents goldEvents; // 金币事件

    private void Awake()
    {
        if (instance != null)
        {
            Debug.LogError("在场景中找到多个游戏事件管理器"); // 如果场景中存在多个游戏事件管理器,则输出错误信息
        }
        instance = this; // 设置单例实例为当前实例
        
        // 初始化所有事件
        goldEvents = new GoldEvents(); // 初始化金币事件
    }
}

挂载脚本

管理玩家的金币,注册金币增加事件执行方法

csharp 复制代码
// GoldManager类,负责管理玩家的金币
public class GoldManager : MonoBehaviour
{
    [Header("Configuration")]
    // 游戏开始时玩家拥有的金币数量
    [SerializeField] private int startingGold = 5;

    // 当前玩家持有的金币数量,外部只能获取不能设置
    public int currentGold { get; private set; }

    // 在对象被激活时调用,初始化玩家的金币数量
    private void Awake()
    {
        currentGold = startingGold;
    }

    // 注册事件监听器
    private void OnEnable() 
    {
        // 当玩家获得金币时,注册GoldGained方法来处理事件
        GameEventsManager.instance.goldEvents.onGoldGained += GoldGained;
    }

    // 注销事件监听器
    private void OnDisable() 
    {
        // 当对象被禁用时,取消注册GoldGained方法
        GameEventsManager.instance.goldEvents.onGoldGained -= GoldGained;
    }

    // 处理获得金币的事件
    private void GoldGained(int gold) 
    {
        // 增加玩家的金币数量
        currentGold += gold;
    }
}

配置脚本

设置脚本执行顺序,在Unity的"Project Settings"中,你可以通过"Script Execution Order"设置脚本的执行顺序,确保GameEventsManager的Awake方法总是在其他依赖它的组件之前执行,不然可能会报错。

定义金币脚本,控制金币拾取和金币重新生成

csharp 复制代码
[RequireComponent(typeof(CircleCollider2D))]
public class Coin : MonoBehaviour
{
    [Header("Config")]
    [SerializeField] private float respawnTimeSeconds = 8; // 重生时间
    [SerializeField] private int goldGained = 1; // 获得的金币数量

    private CircleCollider2D circleCollider; // 圆形碰撞体
    private SpriteRenderer visual; // 视觉元素

    private void Awake() 
    {
        // 初始化圆形碰撞体和视觉元素
        circleCollider = GetComponent<CircleCollider2D>();
        visual = GetComponentInChildren<SpriteRenderer>();
    }

    // 收集金币的方法
    private void CollectCoin() 
    {
        circleCollider.enabled = false;
        visual.enabled = false;
        // 触发获得金币事件
        GameEventsManager.instance.goldEvents.GoldGained(goldGained);
        StopAllCoroutines();
        StartCoroutine(RespawnAfterTime());
    }

    // 在一定时间后重生金币
    private IEnumerator RespawnAfterTime()
    {
        yield return new WaitForSeconds(respawnTimeSeconds);
        circleCollider.enabled = true;
        visual.enabled = true;
    }

    // 触发进入触发器事件
    private void OnTriggerEnter2D(Collider2D otherCollider) 
    {
        if (otherCollider.CompareTag("Player"))
        {
            CollectCoin();
        }
    }
}

金币挂载脚本

运行效果

拾取金币后,currentGold加1,说明没问题

2. 显示金币数UI

一直查看金币变量数据变化,不是很方便,我们可以让金币数显示出来

修改GoldEvents,新增金币变化事件

csharp 复制代码
public class GoldEvents
{
	//。。。
	
    public event Action<int> onGoldChange; // 当金币数量变化时触发的事件
    public void GoldChange(int gold) 
    {
        onGoldChange?.Invoke(gold); // 触发金币变化事件
    }
}

新增GoldUI,注册金币数量发生变化时调用的方法

csharp 复制代码
public class GoldUI : MonoBehaviour
{
    [Header("Components")]
    // 用于显示金币数量的TextMeshProUGUI组件
    [SerializeField] private TextMeshProUGUI goldText;

    // 在对象激活时注册事件监听器
    private void OnEnable() 
    {
        // 当金币数量发生变化时,注册GoldChange方法来处理事件
        GameEventsManager.instance.goldEvents.onGoldChange += GoldChange;
    }

    // 在对象禁用时注销事件监听器
    private void OnDisable() 
    {
        // 当对象被禁用时,取消注册GoldChange方法
        GameEventsManager.instance.goldEvents.onGoldChange -= GoldChange;
    }

    // 处理金币数量变化的事件
    private void GoldChange(int gold) 
    {
        // 将金币数量转换为字符串,并更新UI显示
        goldText.text = gold.ToString();
    }
}

同样配置GoldUI 脚本执行顺序

挂载脚本

修改GoldManager,广播当前金币数量的改变事件

csharp 复制代码
// 在第一帧更新之前调用,广播当前金币数量的改变
private void Start()
{
    GameEventsManager.instance.goldEvents.GoldChange(currentGold);
}

// 处理获得金币的事件
private void GoldGained(int gold) 
{
    // 增加玩家的金币数量
    currentGold += gold;
    // 广播金币数量的变化
    GameEventsManager.instance.goldEvents.GoldChange(currentGold);
}

效果

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

相关推荐
_oP_i5 分钟前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
PandaQue33 分钟前
《怪物猎人:荒野》游戏可以键鼠直连吗
游戏
代码盗圣4 小时前
GODOT 4 不用scons编译cpp扩展的方法
游戏引擎·godot
白狐欧莱雅5 小时前
使用python中的pygame简单实现飞机大战游戏
经验分享·python·游戏·pygame
豆本-豆豆奶6 小时前
用 Python 写了一个天天酷跑(附源码)
开发语言·python·游戏·pygame·零基础教程
Leoysq9 小时前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
PandaQue11 小时前
《潜行者2切尔诺贝利之心》游戏引擎介绍
游戏引擎
_oP_i12 小时前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid1 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh1 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生