Unity笔记-消息框架

消息框架

这是比较简单的给脚本组件发送指令(消息)的图例:

适用于小型demo。
中等难度的:

适用于小型游戏和部分中型游戏。
高级的:

适用于中型游戏和部分大型游戏。
消息框架的作用是让各个类更方便的传输数据,达到简洁有条理的工作效果。
虽然越往上,创建的类越多,但是整个代码框架更加有条理。而且不容易出错。

编写消息类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Message //消息基类不需要继承MonoBehaviour
{
//类型(UI 角色 声音......)
public byte Type;
//命令
public int Command;

//参数
public object Content;
public Message() {}//如果需要以后赋值 则需要一个空的构造方法
public Message(byte type,int command,object content){
Type = type;
Command = command;
Content = content;
}
}
//消息类型
public class MessageType
{
public static byte Type_Audio=1;
public static byte Type__UI = 2;
public static byte Type_Player=3;
public static int Audio_PlaySound = 100;
public static int Audio_StopSound = 100;
public static int Audio_PlayMusic = 100;
public static int UI_AddScore=100;
//...
}

功能脚本

写消息究竟要执行哪些功能的脚本。
实现一个功能基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System.Collections;
using System.Collections.Generic;
using UnityEditor.VersionControl;
using UnityEngine;

public class MonoBase : MonoBehaviour//功能基类
{
// Start is called before the first frame update
public virtual void ReceiveMessage(Message message){//接收消息

}
void Start()
{

}

// Update is called once per frame
void Update()
{

}
}

然后实现管理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class ManagerBase : MySingletonBase<ManagerBase>//管理基类,不能被实例化
{
// Start is called before the first frame update
//管理的功能模块
public List<MonoBase> Monos = new List<MonoBase>();
//给功能模块一个注册方法(注册在xx管理类下面)
public void Register(MonoBase mono){//添加功能
//若功能模块不在数组中,则添加到数组中
if(!Monos.Contains(mono)){
Monos.Add(mono);
}
}
public virtual void ReceiveMessage(Message message){//接收消息
//如果消息类型不匹配,不向下传递
if(message.Type!=GetMessageType()){
return;
}
//如果匹配则向下传递
foreach(var mono in Monos){
mono.ReceiveMessage(message);
}
}
//设置当前管理类接受的消息类型
public abstract byte GetMessageType();
}

消息中心类

消息中心类管理着管理类,管理类再管理注册到管理类的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MessageCenter : MySingletonBase<MessageCenter>
{
public static List<ManagerBase> Managers = new List<ManagerBase>();
public void Register(ManagerBase manager){
if(!Managers.Contains(manager)){
Managers.Add(manager);
}
}
//发送消息
public void SendCustomMessage(Message message){
foreach(var manager in Managers){
manager.ReceiveMessage(message);
}
}
}

实践

在unity中创建一个平面(plane)和一个胶囊(player)

为player添加刚体,并开启运动学模式,冻结旋转xyz。

可以将材质赋值给player
玩法是player吃金币,所以创建一个球体(coin)
给球体一个材质(可选)
接着,勾选coin碰撞体组件的is Trigger
在场景上复制多个coin
创建空物体GameManager 附加Message Center脚本
接下来,创建一个画布和一个Panel(面板),切换2d视图,把面板缩放到画布左上角,接着,把锚点也放到左上角

在面板底下创建面板子对象Text(旧版),Text内容为分数:0,其余随便

逻辑

先创建三个脚本:

  • UIManager UI管理器
  • PlayerManager 玩家管理器
  • Panel 挂载在分数上的功能脚本

    UIManager

    代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class UIManager : ManagerBase
    {
    // Start is called before the first frame update
    void Start()
    {
    //注册到消息中心
    MessageCenter.Instance.Register(this);
    }

    // Update is called once per frame
    void Update()
    {

    }
    public override byte GetMessageType()
    {
    //指定管理器类型是UI
    return MessageType.Type__UI;
    }
    }

    Panel

    代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    public class Penal : MonoBase //继承功能基类
    {
    public Text text;
    // Start is called before the first frame update
    void Start()
    {
    // 注册到UI管理器
    UIManager.Instance.Register(this);
    }

    // Update is called once per frame
    void Update()
    {

    }
    public override void ReceiveMessage(Message message){
    base.ReceiveMessage(message);//base关键字:是用来调用基类方法,类似java的super
    //判断消息
    if(message.Command == MessageType.UI_AddScore){
    int score = (int)message.Content;//Content:参数
    text.text = "分数:"+score;

    }
    }
    }

    PlayerManager

    代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class PlayerManager : MonoBehaviour
    {
    //分数
    int score=0;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
    //获取输入向量
    float h = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(h,0,v);//得到向量值
    if(dir != Vector3.zero){//如果向量!=0,则player按了键
    //移动
    transform.Translate(dir * 5 * Time.deltaTime);//每帧移动
    }
    }
    /// <summary>
    /// OnTriggerEnter is called when the Collider other enters the trigger.
    /// </summary>
    /// <param name="other">The other Collider involved in this collision.</param>
    private void OnTriggerEnter(Collider other)
    {
    //碰到金币
    if(other.tag == "coin"){
    score++;
    //销毁金币
    Destroy(other.gameObject);
    //发送消息更新UI
    MessageCenter.Instance.SendCustomMessage(new Message(MessageType.Type_UI,MessageType.UI_AddScore,score));

    }
    }
    }
    最后,将PlayerManager挂载到player上,UImanager挂载到Canvas上,Penal挂载到Penal上
    运行测试,通过发送消息(命令)让玩家移动,吃取金币,加载分数。
    这是一个最简的消息框架,看起来复杂,但作用非常大。

    End