【unity小技巧】unity事件系统创建通用的对象交互的功能

简介: 【unity小技巧】unity事件系统创建通用的对象交互的功能

前言

游戏开发过程中,要实现玩家和物体之间的交互是非常常见的事情。如果在开发过程中,你希望和箱子交互触发开箱子的方法,和门交互,又触发开门的方法,实现方式其实有很多,比如继承同一个分类或者定义一个接口就是不错的方法,门和箱子都继承这个接口,然后各自重写方法接口里面的触发方法。


但是,如果我说要实现点击一个按钮,打开几个箱子同时开启几个门呢?你可能会说我先获取所有的箱子或者门,然后循环遍历执行里面对应的触发方法不就可以了?当然这种方法是可行的,但是不够优雅。今天我就分享一种使用委托和事件的方式来实现一个通用的物品的交互方式。

至于什么是委托和事件,之前文章我已经有所介绍了,感兴趣可以先去看看:

【unity小技巧】委托(Delegate)的基础使用和介绍

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

实现

1. InteractEvent 类

  • InteractHandler 委托: 定义了一个没有参数和返回值的委托类型。
  • HasInteracted 事件: 事件,当触发时调用所有注册的委托。

方法:

  • CallInteractEvent 方法: 触发 HasInteracted 事件,如果有订阅者,则调用它们。
public class InteractEvent
{
    public delegate void InteractHandler();
    public event InteractHandler HasInteracted;

    // 调用互动事件
    public void CallInteractEvent() => HasInteracted?.Invoke();
}

2. Interact 类

  • InteractEvent interact: 这是一个 InteractEvent 类的实例,用于处理交互事件。
  • Player player: 用于存储与之交互的玩家实例。

属性和方法:

  • GetInteractEvent 属性: 返回 InteractEvent 实例。如果 interact 为 null,会在首次访问时初始化。
  • GetPlayer 属性: 返回存储的玩家实例。
  • CallInteract 方法: 接受一个 Player 参数,设置 player 属性为该参数,然后调用 interactCallInteractEvent 方法。
public class Interact : MonoBehaviour
{
    InteractEvent interact = new InteractEvent();
    Player player;

    // 获取互动事件
    public InteractEvent GetInteractEvent
    {
        get
        {
            if (interact == null)
                interact = new InteractEvent();
            return interact;
        }
    }

    // 获取玩家
    public Player GetPlayer
    {
        get { return player; }
    }

    // 调用互动方法
    public void CallInteract(Player interactedPlayer)
    {
        player = interactedPlayer;
        interact.CallInteractEvent();
    }
}

3. Player 类

  • Update 方法: 每帧检查玩家是否按下 E 键,如果是,则调用 PlayerInteract 方法。
  • PlayerInteract 方法: 创建一条射线从相机的视口中心向前发射,然后检测是否击中了特定层级(层0和层3)的物体。如果击中了一个具有 Interact 组件的物体,则调用其 CallInteract 方法,并传递自身实例。
public class Player : MonoBehaviour
{
    void Update()
    {
        // 如果玩家按下E键,进行交互操作
        if (Input.GetKeyDown(KeyCode.E))
        {
            PlayerInteract();
        }
    }

    // 处理玩家交互的函数
    public void PlayerInteract()
    {
        // 定义用于层0和层3的层蒙版,0和3图层都可以满足条件
        var layerMask0 = 1 << 0;
        var layerMask3 = 1 << 3;
        var finalMask = layerMask0 | layerMask3;

        // 从屏幕中心创建一条射线
        Ray ray = Camera.main.ViewportPointToRay(new Vector3(.5f, .5f, 0));

        // 进行射线投射,检查在最终蒙版上是否命中物体(距离不超过15个单位)
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 15, finalMask))
        {
            // 从命中的物体获取Interact脚本组件
            Interact interactScript = hit.transform.GetComponent<Interact>();

            // 如果Interact脚本组件存在,调用其CallInteract方法并传递玩家实例
            if (interactScript != null)
            {
                interactScript.CallInteract(this);
            }
        }
    }
}

4. Chest 类

  • Interact openFromInteraction: 存储一个 Interact 类的实例,用于处理与宝箱的交互。

方法:

  • OnEnable 方法: 当对象激活时,订阅 openFromInteractionHasInteracted 事件到 OpenChest 方法。
  • OnDisable 方法: 当对象禁用时,取消订阅 openFromInteractionHasInteracted 事件。
  • OpenChest 方法: 当宝箱应该打开时调用,可以在其中添加具体的打开宝箱逻辑,例如生成掉落物品。
public class Chest : MonoBehaviour
{
    public Interact interact;

    // 当对象启用时订阅交互事件
    private void OnEnable()
    {
        if (interact != null)
        {
            interact.GetInteractEvent.HasInteracted += OpenChest;
        }
    }

    // 当对象禁用时取消订阅交互事件
    private void OnDisable()
    {
        if (interact != null)
        {
            interact.GetInteractEvent.HasInteracted -= OpenChest;
        }
    }

    // 处理宝箱打开的函数
    public void OpenChest()
    {
        // 掉落一些酷炫的东西
    }
}

工作流程说明:

  • Player 类中的 PlayerInteract 方法检测玩家按下 E 键后,发射一条射线检测是否与可交互物体碰撞。
  • 如果射线击中了具有 Interact 组件的物体,就调用其 CallInteract 方法,并传递玩家实例。
  • Interact 类中的 CallInteract 方法将玩家实例存储,并调用其内部的 InteractEvent 实例的 CallInteractEvent 方法,从而触发 HasInteracted 事件。
  • Chest 类中的 OnEnable 方法在对象启用时订阅 HasInteracted 事件,当事件触发时调用 OpenChest 方法来打开宝箱。

开单个箱子

挂载脚本

效果

按钮触发打开很多箱子

我们可以让一个按钮与多个对象进行交互,挂载脚本

效果

拾取物品(传参)

带玩家参数的拾取物品功能,脚本挂载在物体预制体上即可

public class ItemPickup : MonoBehaviour
{
    public string item; // 物品名称
    public int amount; // 物品数量
    public Interact interact; // 拾取物品的交互对象

    private void OnEnable()
    {
        Interact getInteract = GetComponent<Interact>();
        if (getInteract == null)
        {
            getInteract = gameObject.AddComponent<Interact>(); // 如果没有,则添加Interact组件   
        }
        interact = getInteract;
        interact.GetInteractEvent.HasInteracted += InteractPickup;
    }

    private void OnDisable()
    {
        if (interact)
        {
            interact.GetInteractEvent.HasInteracted -= InteractPickup; // 取消监听交互事件
        }
    }

    public void InteractPickup()
    {
        AddItem(interact.GetPlayer); // 执行AddItem方法,传入交互对象的玩家信息
    }

    public void AddItem(Player player)
    {
        // 给玩家添加物品的逻辑在这里实现
    }
}

参考

https://www.youtube.com/watch?v=MdOi9ymb07s

目录
相关文章
|
29天前
|
C# 图形学 开发者
【Unity3D实例-功能-镜头】俯视角
本文介绍了Unity中常用的俯视角镜头实现方法,涵盖模型添加、角色Tag设置、摄像机脚本编写及测试运行,帮助开发者快速掌握俯视角在策略与模拟类游戏中的应用技巧。
160 0
|
30天前
|
人工智能 定位技术 C#
【Unity3D实例-功能-移动】通过鼠标点击进行角色移动
本文介绍了如何在Unity中实现鼠标点击控制角色移动的功能。通过安装导航网格、设置地图与角色、烘焙路径及编写脚本,带领读者一步步构建角色自动寻路系统,增强游戏交互体验。
76 0
|
2月前
|
C# 图形学 开发者
【Unity3D实例-功能-移动】复杂移动(Blend Tree方式)
本文介绍了使用Unity中Blend Tree实现角色移动控制的完整教程,涵盖动画器设置、Blend Tree创建、CharacterController组件添加及代码控制,帮助开发者实现流畅自然的角色动画效果。
65 0
|
2月前
|
图形学 开发者
【Unity3D实例-功能-移动】角色移动-通过WSAD(CharacterController方式)
本文介绍了如何在Unity中使用CharacterController组件实现角色灵活移动。内容包括模型准备、动画处理、添加组件、编写移动脚本及测试运行,帮助开发者快速掌握角色控制技巧,打造流畅的游戏体验。
96 0
|
2月前
|
C# 图形学 开发者
【Unity3D实例-功能-移动】角色移动-通过WSAD(Rigidbody方式)
本文介绍了如何在Unity中使用Rigidbody组件实现角色自由移动,包括模型准备、组件添加、脚本编写与测试运行,帮助开发者快速掌握基础角色控制技巧。
119 0
|
2月前
|
C# 图形学
【Unity3D实例-功能-移动】角色移动-通过WSAD(Transform方式)
本文介绍了如何在Unity中实现角色移动功能,使用Transform组件控制角色基础移动,并详细讲解了模型导入、动画设置、动画控制器配置及移动脚本编写等内容,适合Unity初学者学习角色控制的基础知识。
85 0
|
7月前
|
存储 API 图形学
Unity 给Animator动画添加事件(动态的)
在 Unity 中,通过动画事件系统可在动画播放的特定时间点触发自定义函数。动态添加事件的步骤包括获取 `AnimationClip` 对象,创建并添加 `AnimationEvent`,最后调用 `Rebind()` 更新动画控制器。示例代码展示了如何在动画开始、中间和结束时触发事件,实现与游戏逻辑的交互。
|
7月前
|
图形学 UED
unity Tab键实现切换输入框功能
该脚本用于简化输入框之间的Tab键切换操作。只需将脚本挂载在InputField上,无需其他设置。脚本通过监听Tab键和Shift键组合,自动选择下一个或上一个可交互的InputField,提升用户体验。
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
765 6
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
1290 6