所谓的 static type,使用的是 static 关键字
任务说明:
传统的做法是首先新建一个 Score 的类,用于存放累加后的结果:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Score : MonoBehaviour
{
public int num;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
这个脚本可以挂载到一个游戏对象 Score 上面
然后再用一个脚本进行累加操作:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StaticTest : MonoBehaviour
{
public Score score; // 实例化一个 Score 的类
// Start is called before the first frame update
void Start()
{
score = GameObject.Find("Score").GetComponent(); // 初始化
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
score.num += 10; // 对于类下面的 num 变量加 10
}
}
}
这个脚本也挂载到一个游戏对象下面,运行游戏后,按下空格键就可以看到 Score 里面的 Num 每次会加 10
然后我们尝试把 Score 类下面的 num 变量改为 static:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Score : MonoBehaviour
{
public static int num;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
计数程序就要做对应修改:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StaticTest : MonoBehaviour
{
// public Score score; // 不再需要实例化
// Start is called before the first frame update
void Start()
{
//score = GameObject.Find("Score").GetComponent(); // 也不需要初始化
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
//score.num += 10;
Score.num += 10; // 直接对于类下面的 num 变量加 10
Debug.Log(Score.num); // Inspector 中无法显示,需要通过 debug 进行显示
}
}
}
静态变量直接存储在内存中,无需通过类的实例化来分配内存,所以可以直接对其进行操作。
Static 的东西没有办法直接在 unity 的 inspector 中看到,所以可以通过 debug 的方式查看数值变化。
在运行大型项目的时候,由于静态数据会占据内存,需要额外关注。
不仅仅是变量可以 static,类和方法也可以是 static 的。
当你使用 static class 的时候,这个类无法继承别的父类,所以自然 static class 无法继承 MonoBehaviour。
首先创建一个 cube,命名为 Emeny,然后拖拽到 assets 中作为 prefab,原窗口中的 Enemy 可以删除,然后创建脚本 SpawnManager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
public GameObject enemyPrefab;
public static int enemyCount; // 这里使用静态变量
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(enemyPrefab); // 每次按下空格键生成 enemy
}
}
}
另外创建一个 Enemy 脚本,挂载到 Enemy 的 Prefab 上,用于控制 Enemy 的激活和关闭:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
private UIManager _ui; // 实例化
public void OnEnable() // unity 自带的方法,生成游戏对象的时候自动调用
{
SpawnManager.enemyCount++; // 激活的时候,enemy数量+1
// 静态变量可以直接操作,非常方便!
_ui = GameObject.Find("UIManager").GetComponent(); // 初始化
_ui.UpdateEnemyNum(); // 调用方法更新数字
Delet(); // 调用销毁方法
}
public void OnDisable() // unity 自带的方法,销毁游戏对象的时候自动调用
{
SpawnManager.enemyCount--; // 关闭的时候,enemy数量-1
// 静态变量可以直接操作,非常方便!
_ui.UpdateEnemyNum(); // 调用方法更新数字
}
void Delet() // 销毁方法
{
Destroy(this.gameObject, Random.Range(2.0f, 4.0f)); // 2~4秒后销毁自己
}
}
这里我们发现,把 enemyCount 设置为静态变量后,操作起来非常方便!不需要有实例化和初始化过程,直接可以对其进行操作!
将 Enemy 的 Prefab 拖拽到 SpawnManager 脚本上。
创建一个空的游戏对象,命名为 UIManager,并挂载同名脚本,用于显示现存的 Enemy 数量:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // 直接 using UI 库方便使用
public class UIManager : MonoBehaviour
{
public Text enemyNumText; // 实例化一个 Text
public void UpdateEnemyNum()
{
enemyNumText.text = "Enemy Number: " + SpawnManager.enemyCount;
}
}
在场景中新建一个 Text 游戏对象,按照喜好修改大小颜色等参数,然后将其拖拽到 UI Manger 的脚本中。
运行游戏,按下空格键就会生成 Enemy,UI会显示数字增加,当 Enemy 自动销毁后,数字会减小。
注意几点:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemTest // 自定义一个类
{
public string name;
public int id;
public static int itemNum; // 总的道具数量,设为静态变量
}
public class InstanceTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
// 当我们要使用自定义的类的时候,首先要进行实例化 instance
ItemTest sword = new ItemTest();
ItemTest spear = new ItemTest();
// 这里创建的两个实例,拥有不同的变量 name 和 id
// 但是 itemNum 这个变量只有一个,每个实例都共享
// 这个时候我们无法通过 sword.itemNum 来访问这个变量
// 可以直接通过 ItemTest.itemNum 来进行访问
}
// Update is called once per frame
void Update()
{
}
}
那静态变量如何使用的,举个例子,通过构造函数:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemTest // 自定义一个类
{
public string name;
public int id;
public static int itemNum; // 总的道具数量,设为静态变量
public ItemTest() // 每次实例化的时候自动调用构造函数
{
itemNum++; // 相当于每次实例化一个道具,道具总数+1
}
}
public class InstanceTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
// 当我们要使用自定义的类的时候,首先要进行实例化 instance
ItemTest sword = new ItemTest();
ItemTest spear = new ItemTest();
ItemTest axe = new ItemTest();
Debug.Log("Item number: " + ItemTest.itemNum);
// 前面生成了 3 个实例,所以这个得到的数字就是 3
}
// Update is called once per frame
void Update()
{
}
}
比如在线网游中,显示的当前在线玩家数量,就可以通过这个方法实现。
我们就可以把这个 utility helper class 设置为静态:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class UtilityHelper // 静态类不能继承父类,所以这里不能继承 MonoBehaviour
{
// 静态类下面的所有成员都必须是静态的,包括变量和方法等
public static void CreatCube() // 这个方法用于创建一个 cube
{
GameObject.CreatePrimitive(PrimitiveType.Cube); // 创建一个预设的 cube
}
public static void ChangePosition(GameObject obj) // 这个方法用于改变游戏对象位置
{
obj.transform.position += new Vector3(1, 0, 0); // 把游戏对象沿着 x 轴移动 1
}
}
然后我们创建一个 cube 作为 Player 并挂载同名脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) // 按下空格键
{
UtilityHelper.CreatCube(); // 调用生成 cube 的方法
}
if (Input.GetKeyDown(KeyCode.C)) // 按下 C 键
{
UtilityHelper.ChangePosition(this.gameObject); // 改变 player 的位置
}
}
}
以此来调用静态类。
这里我们使用的 utility helper class 下面可以放置多种静态方法,便于我们在其他程序段落中调用。
当然,我们也可以根据需求使用具有返回值的静态方法。需要注意的是,静态类和静态方法的生命周期是程序开始到程序结束,所以一直会占用到内存!
首先创建 helper class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class UtilityHelper // 静态类不能继承父类,所以这里不能继承 MonoBehaviour
{
public static void ChangeColor(GameObject obj, Color color) // 改变游戏对象颜色
{
obj.GetComponent().material.color = color;
}
}
然后创建 Player 并挂载同名脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.C)) // 按下 C 键
{
UtilityHelper.ChangeColor(this.gameObject, Color.red);
// player 变为红色
}
}
}
随机改变颜色:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class UtilityHelper // 静态类不能继承父类,所以这里不能继承 MonoBehaviour
{
public static void ChangeColor(GameObject obj, Color color, bool randomColor = false) // 改变游戏对象颜色
{
if (randomColor)
{
color = new Color(Random.value, Random.value, Random.value);
// Random.value 返回的是 0.0~1.0 的值,包含了0.0和1.0两个边界
}
obj.GetComponent().material.color = color;
}
}
对应修改 player 脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.C)) // 按下 C 键
{
UtilityHelper.ChangeColor(this.gameObject, Color.red, true);
// player 变为随机颜色
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Players // 玩家的类
{
public string name; // 姓名
public int id; // id
public int level; // 等级
public static string group; // 组织为静态变量
public Players() // 一般的实例化类构造函数,初始化非静态变量
{
Debug.Log("Instance Members initialized");
}
static Players() // 静态构造函数,初始化静态变量
{
group = "LOL";
Debug.Log("Static Members initialized");
}
}
public class InitialTest : MonoBehaviour
{
public Players p1;
public Players p2;
// Start is called before the first frame update
void Start()
{
p1 = new Players(); // 初始化 p1
p2 = new Players(); // 初始化 p2
}
// Update is called once per frame
void Update()
{
}
}
在 console 中可以看到,先显示一个 “Static Members initialized”,然后显示 2 个 “Instance Members initialized”,静态变量只初始化一次,而且是在其他初始化之前进行。
注意:静态变量的的初始化在实例化之前进行,因为静态变量会在所有实例化对象之间进行共享。