Unity半月学习总结(二)

文章介绍了如何在Unity中使用UnityEvent和UnityAction以及ScriptableObject来实现在不同场景之间的血量变化事件传递,如PlayerStatBar组件接收并显示角色血量变化,通过CharacterEventSO作为事件中间件订阅和传递事件。
摘要由CSDN通过智能技术生成

基于unity event,unity action,script object实现的跨场景的事件订阅传递(实现血量变化传递给UI)

主题代码部分

PlayerStatBar

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerStatBar : MonoBehaviour
{
    public Image healthImage;

    public Image healthDelayImage;

    public Image powerImage;

    private void Update()
    {
        if(healthDelayImage.fillAmount>healthImage.fillAmount)
        {
            healthDelayImage.fillAmount-=Time.deltaTime;
        }
    }
    /// <summary>
    ///    接收health的变更百分比
    /// </summary>
    /// <param name="persentage">百分比:Current/Max</param>

    public void OnHealthChange(float persentage)
    {
        healthImage.fillAmount = persentage;
    }
}

script object(CharacterEventSO)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(menuName ="Event/CharacterEventSO")]
public class CharacterEventSO : ScriptableObject
{
    public UnityAction<Character> OnEventRaised;

    public void RaiseEvent(Character character)
    {
        OnEventRaised?.Invoke(character);
    }
}

UIManager

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public PlayerStatBar playerStatBar;

    [Header("事件监听")]
    public CharacterEventSO healthEvent;


    public void OnEnable()
    {
        healthEvent.OnEventRaised += OnHealthEvent;
    }

    public void OnDisable()
    {
        healthEvent.OnEventRaised -= OnHealthEvent;
    }

    private void OnHealthEvent(Character character)
    {
        var persentage = character.currentHealth / character.maxHealth;
        playerStatBar.OnHealthChange(persentage);
    }
}

character(部分)

    public void TakeDamage(Attack attacker)
    {
        if (invulnerable)
            return;

        //Debug.Log(attacker.damage);
        if (currentHealth - attacker.damage > 0)
        {
            currentHealth -= attacker.damage;
            TriggerInvulnerable();
            //执行受伤
            OnTakeDamage?.Invoke(attacker.transform);
        }
        else
        {
            currentHealth = 0;
            //触发死亡
            OnDie?.Invoke();
        }

        OnHealthChange?.Invoke(this);
    }

关于ScriptableObject(SO)

ScriptableObject是存储在我们项目中的一个资产性文件类型,  unity官方手册给出的解释是:ScriptableObject 是一个可独立于类实例来保存大量数据的数据容器。

创建、使用ScriptableObject的方法

1.首先在文件夹下创建 一个脚本,然后双击打开这个脚本,之后删除MonoBehaviour(它不需要挂在在物体上),然后继承ScriptableObject  

2.加上CreateAssetMenu特性方便日后的使用 menuName(目录名字:鼠标右键创建时的位置)

代码实现逻辑

按照我当前的理解,SO像是一个中间容器(SO的实例是Unity靠assets文件反序列化出来的,但全局共享这一个实例,它可以在运行时被修改,但是不能被持久化下来,比如存档不能依靠SO机制做,必须手动序列化进本地文件)依靠SO的特性和优点我们把想要传递的内容用SO进行存储。通过订阅事件把需要的数据传递出去。(本文中传递给UIManager)

把characterEventSO比作报纸的话,character就是写入报纸的内容。注册character改变这一事件,如果character发生改变所有订阅这个事件的对象就会呼叫,把内容传递出去。最后UIManager接受内容,通过函数方法进行处理。

单项平台

Platform Effector 2D

利用Platform Effector 2D组件,实现单项平台。

然后在组件Platform Effector 2D中取消使用碰撞器遮罩,然后点击使用单向这样我们就实现了一个可以从下面跳上去的平台。

(Use One Way:勾选此选项后,平台将变为单向平台,角色可以从平台上方穿过,但无法从平台下方穿过。
Use Side Friction:勾选此选项后,角色在平台上将受到侧面的摩擦力,可以防止角色因为平台的移动而滑落。
Surface Arc:这是一个角度值,表示角色在平台上的接触面积大小。如果值较小,角色将紧贴着平台移动;如果值较大,角色将有一定的间隙,可以让角色跳跃等动作更加灵活。
Side Arc:和 Surface Arc 类似,但是作用于平台的侧面。
Rotational Offset:旋转偏移量,可以用来调整平台的旋转角度。
Use Collider Mask:勾选此选项后,可以指定一个碰撞层,只有和该层的物体才能和平台碰撞。
Use Global Angle:勾选此选项后,将会使用全局角度,而不是相对于平台自身的角度。
Use One Way Grouping:勾选此选项后,同一组的平台将共享同一个单向平台属性,可以方便批量设置。)

但是这样不能实现S+空格落下平台

想到使用S+空格 短暂关闭角色的碰撞器。导致角色穿模,卡在地面。

最后改成短暂关闭特定平台的碰撞器,当角色触发器和平台不在重叠时恢复平台。代码改的比较凌乱就不展示了。

平台移动

在平台上方设置一个触发器,当平台上升到触发器就消失。


using UnityEngine;
 
public class PlatFormMove : MonoBehaviour
{
    Vector3 movement;//transform是3D组件所以用Vector3
    GameObject topline;//获取标志物
    public float speed;//定义平台上升速度
 
    void Start()
    {
        movement.y = speed;
        topline = GameObject.Find("TopLine");
    }
 
    void Update()
    {
        MovePlantForm();
    }
 
    void MovePlantForm()
    {
        transform.position += movement * Time.deltaTime;//平台上升
        if (transform.position.y >= topline.transform.position.y)//如果到达标记位就消失
            Destroy(gameObject);
    }
}

类似的写了一个不会消失而是回到初始位置,这样子循环往复。

Unity event,unity action的学习

总结半天发现还是不如大佬总结的好,贴上博客先【Unity】Delegate, Event, UnityEvent, Action, UnityAction, Func 傻傻分不清_unity action-CSDN博客

 UntiyAction,它是 Unity 对 C# Action 委托的一个封装(佬写的特别好,跟着他的博客回顾了C#委托
C#事件

优化血瓶,精力条

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class BloodVials : MonoBehaviour, IInteractable
{
    public Character character;

    public UnityEvent<Character> OnHealthChange;

    private void Awake()
    {
        GameObject Player = GameObject.Find("Player");

        character = Player.GetComponent<Character>();
    }
    public void TriggerAction()
    {
        if (character.currentHealth + 50 > 100)
            character.currentHealth = 100;
        else
            character.currentHealth += 50;
        OnHealthChange?.Invoke(character);
        
    }
}

把血瓶回血的代码优化(其实就是加深理解了利用SO进行事件订阅后的优化),用事件的方式更新血量UI。

给血瓶加了一个慢慢喝完的动画。

学习进度

在b站看完了唐老师的unity入门和基础

行为树学习【Unity教程搬运】使用行为树在UNITY中重现大黄蜂Boss战(空洞骑士)_哔哩哔哩_bilibili

算法题。。。

刷题,爽 !

  • 20
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值