前言:在我们进行项目开发中,经常会涉及到消息的传递。例如,玩家受到攻击,从而引发: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脚本下的代码量就会增多,例如还有法力值变化等等。并且这样的设计方式也大大增加了耦合度,一旦多人合作开发的时候,会造成沟通等困难。
下一章,我们用委托的方式,重新实现这个功能的开发。