三、观察者设计模式-1-为何使用此模式。

前言:在我们进行项目开发中,经常会涉及到消息的传递。例如,玩家受到攻击,从而引发:1.屏幕左上角的血条减少,2.存储角色信息的脚本做相应处理,3.角色头上的血条减少,4.如果还是网络游戏的话,组队窗口里血条也会有变化。图示:
在这里插入图片描述
那么根据设计思路,我们来写一个《没有》《观察者设计模式》的实现方式。

一、创建相应的对象和脚本。

1.创建空物体,将其命名为:UI_Root_01,这个是屏幕左上角的血量信息,创建脚本"UIRoot01.cs",并挂载。
2.创建空物体,将其命名为:UI_Root_02,这个是屏幕右上角的角色信息,创建脚本"UIRoot02.cs",并挂载。
3.创建一个“Capsule”,将其命名为:Player,并修改其Tag为“Player”。创建脚本“Player.cs”和"UIPlayer.cs"脚本,并挂载。
4.创建空物体,将其命名为“GameController”,创建脚本“GameController.cs”,并挂载。
Hierarchy面板和Game视图如图所示:
在这里插入图片描述
在这里插入图片描述

二、实现功能,编写脚本。

1.GameController.cs脚本
a.它是一个单例。
b.它负责角色的信息的初始化。
c.当按下数字键1时,角色减血,当按下数字键2时,角色加血。
d.传递信息,告诉与角色血量相关的对象,当前减血了。
e.脚本如下:

using UnityEngine;

public class GameController : MonoBehaviour 
{
    public static GameController Instance;

    private void Awake()
    {
        Instance = this;
    }

    private void Start()
    {
        Player.Instance.Init();
    }

    private void Update()
    {
        //按下数字键 1 减血
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            if (!Player.Instance.PlayerDead())
            {
                ChangeHp(-20);
            }
        }

        //按下数字键 2 加血
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            if (!Player.Instance.PlayerFullBlood())
            {
                ChangeHp(20);
            }
        }
    }

    /// <summary>
    /// 修改血量
    /// </summary>
    private void ChangeHp(int hp)
    {
        Player.Instance.Current_Hp += hp;

        //todo 传递参数 告诉所有与Hp相关的对象 当前修改了HP
        GameObject.Find("UI_Root_01").GetComponent<UIRoot01>().ChangeHp();
        GameObject.Find("UI_Root_02").GetComponent<UIRoot02>().ChangeHp();
        GameObject.FindGameObjectWithTag("Player").GetComponent<UIPlayer>().ChangeHp();
    }

}

2.Player.cs脚本
a.存储角色信息(当前血量和最大血量)
b.判断当前是否死亡(当前血量小雨或者等于0)
c.判断当前角色是都满血(当前血量等于或者大于最大血量)
e.脚本如下:

using UnityEngine;

public class Player : MonoBehaviour 
{
    public static Player Instance;

    /// <summary>
    /// 满血血量
    /// </summary>
    public float Max_Hp;

    /// <summary>
    /// 当前血量
    /// </summary>
    public float Current_Hp;

    private void Awake()
    {
        Instance = this;
    }

    /// <summary>
    /// 角色初始化信息
    /// </summary>
    public void Init()
    {
        Max_Hp = 100;
        Current_Hp = Max_Hp;
    }

    /// <summary>
    /// 判断当前角色是否死亡
    /// </summary>
    /// <returns></returns>
    public bool PlayerDead()
    {
        if (Current_Hp <= 0)
        {
            Current_Hp = 0;
            return true;
        }
        return false;
    }

    /// <summary>
    /// 判断当前角色是否满血
    /// </summary>
    /// <returns></returns>
    public bool PlayerFullBlood()
    {
        if (Current_Hp >= Max_Hp)
        {
            Current_Hp = Max_Hp;
            return true;
        }
        return false;
    }

}

3.UIPlayer.cs脚本
a.根据收到的信息,修改相应的数据或显示内容。
b.脚本如下:

using UnityEngine;
using UnityEngine.UI;

public class UIPlayer : MonoBehaviour 
{
    private Image m_HpImage;

    private void Awake()
    {
        m_HpImage = transform.Find("Canvas/HP_Image/Image").GetComponent<Image>();
    }

    public void ChangeHp()
    {
        float b = Player.Instance.Current_Hp / Player.Instance.Max_Hp;
        m_HpImage.transform.localScale = new Vector3(b, 1.0f, 1.0f);
    }
}

4.UIRoot01.cs和UIRoot02.cs脚本
a.根据收到的信息,修改相应的数据或显示内容。
b.脚本如下:

using UnityEngine;
using UnityEngine.UI;

public class UIRoot01 : MonoBehaviour 
{
    private Image m_HpImage;

    private void Awake()
    {
        m_HpImage = transform.Find("Canvas/HP_Image/Image").GetComponent<Image>();
    }

    public void ChangeHp()
    {
        float b = Player.Instance.Current_Hp / Player.Instance.Max_Hp;
        m_HpImage.transform.localScale = new Vector3(b, 1.0f, 1.0f);
    }
}
using System.Text;
using UnityEngine;
using UnityEngine.UI;

public class UIRoot02 : MonoBehaviour 
{
    private Text m_Text;

    private void Awake()
    {
        m_Text = transform.Find("Canvas/PlayerInfo/Text").GetComponent<Text>();
    }

    public void ChangeHp()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("当前血量:");
        sb.Append(Player.Instance.Current_Hp);
        m_Text.text = sb.ToString(); ;
    }
}

三、总结

按照这样的设计思路,我们能完成我们想要开发的功能。可是,一旦我们随着我们需要通知的消息增多,GameController.cs脚本下的代码量就会增多,例如还有法力值变化等等。并且这样的设计方式也大大增加了耦合度,一旦多人合作开发的时候,会造成沟通等困难。
下一章,我们用委托的方式,重新实现这个功能的开发。

猜你喜欢

转载自blog.csdn.net/Dean272727/article/details/89044452