@Data

2022-10-22
游戏对象之间数据的访问
一个游戏对象访问另外一个游戏对象的数据,需要声明一个对目标游戏对象所挂载脚本类A.cs的公开public引用;
即:对象通过对象访问类中的数据;
[]脚本之间的数据访问
1. 创建游戏对象objA,并挂载脚本A.cs;
2. 创建游戏对象objB,并挂载脚本B.cs:通过public暴露一个对类A.cs的引用;
3. 将游戏对象objA拖动到游戏对象objB暴露的类A接口;虽然暴露的是类A.cs,但是赋值/拖进去的是游戏对象objA,系统会自动寻找游戏对象objA上挂载的类A.cs;
4. 运行游戏,查看数据调用情况;
//A.cs
public class A : MonoBehaviour
{
    public void Greeting()
    {
        print("hello,world....");
    }
}
//B.cs
public class B : MonoBehaviour
{
    public A a;
    void Start()
    {
        a.Greeting();
    }
}
[] 既然暴露的是类A,可以直接把脚本A.cs拖进去吗?
[] 如果暴露的是游戏对象objA,如何使用数据?
public class B : MonoBehaviour
{
    public GameObject obj;
    void Start()
    {
        //根据对象获取其加载的脚本
        print(obj.GetComponent<A>().age);
        obj.GetComponent<A>().greeting();
    }
}
暴露的不同类型数据在监视视图的提示也不同:
静态数据 Static Data
静态变量 Static Variables && 静态方法 Static Methods
为类创建静态static变量或方法,无需实例化即可通过类名 直接 使用,适合整个游戏/全局共同使用的场合;
[]静态变量和静态方法的使用
1. 创建脚本A.cs,定义一个静态变量age;
2. 创建一个对象b,创建脚本B.cs并挂载到b,访问脚本A.cs的静态变量和方法;
//A.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class A : MonoBehaviour
{
    public GameObject prefab;
    public static int age = 0;
    void Start()
    {
        age = 5;
    }

    void Update()
    {
        age = age + 1;
    }
    public static void greeting()
    {
        print("hi,there.");
    }
}
//B.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class B : MonoBehaviour
{
    void Start()
    {
        print(A.age);
        A.greeting();
    }
}
[]为什么A.cs中的Start和Update没有执行?
[]没有挂载到游戏对象。
[系统常见静态方法]
对象销毁 Destroy
对象生成 Instantiate
[常见静态变量]
比如数学库中的PI,更多变量,请查看:mathf
静态类 Static Class
. 单例模式;
. 将脚本类声明为一个静态类;
. 需要保证单例是唯一的;
. 通常在Awake()声明;
. 同样的,如需要在对象的生命周期函数内修改变量或方法,需要将静态类挂载到某个游戏对象;
[]不间断播放背景音乐
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioCtrl : MonoBehaviour
{
    public static AudioCtrl instance;
    public AudioSource bgPlayer;
    public AudioClip bgPlayerClip;
    void Awake()
    {
        if (instance != null)
        {
            Destroy(gameObject);
            //return;
        }
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
}
数据文件脚本 Data File
. 脚本仅仅是定义数据,对应的脚本类不需要继承游戏的MonoBehaviour,因此不需要挂载到游戏对象;也挂载不上:只有继承了MonoBehaviour的,才可以挂载到游戏对象;
. 需要序列化才能被其他脚本使用;序列化语句是对整个脚本类的序列化,不是对其中某一个变量的序列化;
. 数据通常指定一个初值,也可以不指定;
. 游戏对象通过公开声明数据文件类来使用其中的数据;因为是公开public,每个使用数据的游戏对象都可以根据自己的需求修改这些数据;
[]数据文件的使用
1. 创建数据文件Data.cs,并序列化;
2. 创建使用数据的文件C.cs,并声明数据文件对应的变量,在游戏对象的监视视图Inspectors中就可以看到数据;
3. 运行游戏,查看数据的使用情况;
//Data.cs
[System.Serializable]
public class Data
{
    public float speed;
    public float inter;
    public int num;
}
//C.cs
public class C : MonoBehaviour
{
    public Data data;
    void Update()
    {
        data.speed++;
        print(data.speed);
    }
}
消息发送 SendMassage
. 组件方法:用于对象自身脚本之间、父级对子级、子级对父级的通信;不适合游戏对象之间的数据通信;
1. Component.SendMessage
. 游戏对象挂载的所有组件中即兄弟脚本,只要定义了该方法都会执行;
. Every script attached to the game object that has a xxx function will be called.
2. Component.BroadcastMessage
. 向兄弟脚本,同时 向子对象脚本发送;
. Every script attached to the game object and all its children that has a xxx function will be called.
3. Component.SendMessageUpwards
. 向兄弟脚本,同时 向父级对象脚本、祖先对象脚本发送;
. Every script attached to this game object and any ancestor that has a xxx function will be called.
. 更多使用细节,请查阅API
[]SendMessage的使用
1. 创建一个游戏对象,分别挂载3个脚本:A.cs、B.cs、C.cs;
2. 脚本A:每次按下鼠标左键,就发送消息;脚本B、C接收消息并执行指定的函数;
3. 运行游戏,查看函数的调用情况;
4. 如果A也有greeting函数,它也会执行:自己发给自己;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class A : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            SendMessage("greeting","Cnplaman");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class B : MonoBehaviour
{
    void greeting(string str)
    {
        print(str + " B, hi,there.");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class C : MonoBehaviour
{
    void greeting(string str)
    {
        print(str + " C, hi,there.");
    }
}
[]BroadcastMessage的使用
1. 创建一个游戏对象GM,挂载脚本GM.cs向3个子对象发送消息;
2. 创建3个子对象a、b、c,分别挂载3个脚本:A.cs、B.cs、C.cs;每个脚本都定义了消息接受函数;
3. 运行游戏,查看消息的发送情况:每个子对象都执行函数;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GM : MonoBehaviour
{
    void Start()
    {
        BroadcastMessage("greeting","broadMsg");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class A : MonoBehaviour
{
    void greeting(string str)
    {
        print(str + " A, hi,there.");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class B : MonoBehaviour
{
    void greeting(string str)
    {
        print(str + " B, hi,there.");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class C : MonoBehaviour
{
    void greeting(string str)
    {
        print(str + " C, hi,there.");
    }
}
4. 如果将GM.cs的BroadcastMessage换成SendMessage,则会提示发送失败:无同级组件;也可以指定发送选项为不需要接受者DontRequireReceiver;
5. 如果在GM.cs也定义了消息接受函数,或者游戏对象GM又挂载了其它也定义了消息接受函数的脚本,则这些同级脚本和子对象脚本都会执行函数;