赞
踩
官方中文教程请戳。
如何在类外访问类内的成员变量?将变量声明为
p
u
b
l
i
c
public
public——这是可行的,但是不是最好的做法——使用属性。
属性本身可以当作变量,并且可以封装成员变量(也称字段)。通过这种封装,我们可以更好的控制字段的访问时间和访问方式。
using UnityEngine; using System.Collections; public class Player { //成员变量可以称为 //字段。 private int experience; //Experience 是一个基本属性 public int Experience { get { //其他一些代码 return experience; } set { //其他一些代码 experience = value; } } //Level 是一个将经验值自动转换为 //玩家等级的属性 public int Level { get { return experience / 1000; } set { experience = value * 1000; } } //这是一个自动实现的属性的 //示例 public int Health{ get; set;} }
using UnityEngine;
using System.Collections;
public class Game : MonoBehaviour
{
void Start ()
{
Player myPlayer = new Player();
//属性可以像变量一样使用
myPlayer.Experience = 5;
int x = myPlayer.Experience;
}
}
相较于 p u b l i c public public,属性有什么过人之处吗?当然,通过省略 g e t get get或 s e t set set,我们可以将字段变成只写或只读;我们也可以认为 g e t 、 s e t get、set get、set是两个函数,在其内部可以运行其他代码或者调用其他函数,正如上例的 L e v e l Level Level所示。
静态成员可直接通过类访问而无需实例化对象。静态成员是这个类的所有实例所共有的,非静态成员是这个类的每个实例所私有的。
using UnityEngine; using System.Collections; public class Enemy { //静态变量是在类的所有实例之间 //共享的变量。 public static int enemyCount = 0; public Enemy() { //通过递增静态变量了解 //已创建此类的多少个对象。 enemyCount++; } }
using UnityEngine; using System.Collections; public class Game { void Start () { Enemy enemy1 = new Enemy(); Enemy enemy2 = new Enemy(); Enemy enemy3 = new Enemy(); //可以使用类名和点运算符 //来访问静态变量。 int x = Enemy.enemyCount; } }
静态方法无法访问非静态成员变量。
using UnityEngine;
using System.Collections;
public static class Utilities
{
//可以在没有类对象的情况下调用
//静态方法。请注意,静态方法无法访问
//非静态成员变量。
public static int Add(int num1, int num2)
{
return num1 + num2;
}
}
using UnityEngine;
using System.Collections;
public class UtilitiesExample : MonoBehaviour
{
void Start()
{
//可以使用类名和点运算符
//来访问静态方法。
int x = Utilities.Add (5, 6);
}
}
如果某个类的所有成员和方法都是静态的,那么可以把这个类声明称静态类。静态类无法创建实例。
接口可被视为关于功能的协定。实现接口的任何类必须拥有其所有方法和属性。接口本身不是类,不能有任何实例。
using UnityEngine; using System.Collections; //这是只有一个必需方法的基本 //接口。 public interface IKillable { void Kill(); } //这是一个通用接口,其中 T 是 //将由实现类提供的数据类型的 //占位符。 public interface IDamageable<T> { void Damage(T damageTaken); }
using UnityEngine; using System.Collections; public class Avatar : MonoBehaviour, IKillable, IDamageable<float> { //IKillable 接口的必需方法 public void Kill() { //执行一些有趣操作 } //IDamageable 接口的必需方法 public void Damage(float damageTaken) { //执行一些有趣操作 } }
接口的主要优势是允许跨多个类定义通用功能。
通过扩展方法可以向类型添加功能,而不需要修改原类型或者继承。它非常适用于需要向类添加功能而不能编辑类的情况,比如 u n i t y unity unity中的一些内置类。
using UnityEngine; using System.Collections; //创建一个包含所有扩展方法的类 //是很常见的做法。此类必须是静态类。 public static class ExtensionMethods { //扩展方法即使像普通方法一样使用, //也必须声明为静态。请注意,第一个 //参数具有“this”关键字,后跟一个 Transform //变量。此变量表示扩展方法会成为 //哪个类的一部分。 public static void ResetTransformation(this Transform trans) { trans.position = Vector3.zero; trans.localRotation = Quaternion.identity; trans.localScale = new Vector3(1, 1, 1); } }
using UnityEngine;
using System.Collections;
public class SomeClass : MonoBehaviour
{
void Start () {
//请注意,即使方法声明中
//有一个参数,也不会将任何参数传递给
//此扩展方法。调用此方法的
//Transform 对象会自动作为
//第一个参数传入。
transform.ResetTransformation();
}
}
协同程序可被视为按时间间隔执行的函数,这类函数与特殊语句 y i e l d yield yield搭配使用。 y i e l d yield yield语句从函数中返回代码执行,然后当函数继续时,从上次停止的地方开始执行。强烈推荐看一下这一节对应的视频。
using UnityEngine; using System.Collections; public class CoroutinesExample : MonoBehaviour { public float smoothing = 1f; public Transform target; void Start () { StartCoroutine(MyCoroutine(target)); } IEnumerator MyCoroutine (Transform target) { while(Vector3.Distance(transform.position, target.position) > 0.05f) { transform.position = Vector3.Lerp(transform.position, target.position, smoothing * Time.deltaTime); yield return null; } print("Reached the target."); yield return new WaitForSeconds(3f); print("MyCoroutine is now finished."); } }
委托可被简单的视作函数的容器,可以进行传递或像变量一样被使用。
using UnityEngine; using System.Collections; public class DelegateScript : MonoBehaviour { delegate void MyDelegate(int num); MyDelegate myDelegate; void Start () { myDelegate = PrintNum; myDelegate(50); myDelegate = DoubleNum; myDelegate(50); } void PrintNum(int num) { print ("Print Num: " + num); } void DoubleNum(int num) { print ("Double Num: " + num * 2); } }
using UnityEngine; using System.Collections; public class MulticastScript : MonoBehaviour { delegate void MultiDelegate(); MultiDelegate myMultiDelegate; void Start () { myMultiDelegate += PowerUp; myMultiDelegate += TurnRed; if(myMultiDelegate != null) { myMultiDelegate();//一次执行多个函数 } } void PowerUp() { print ("Orb is powering up!"); } void TurnRed() { renderer.material.color = Color.red; } }
[ E x e c u t e I n E d i t M o d e ] [ExecuteInEditMode] [ExecuteInEditMode]可以让该脚本在编辑模式下运行。但是请注意,在编辑模式下所做的改动是真实有效的!
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class ColorScript : MonoBehaviour
{
void Start()
{
renderer.sharedMaterial.color = Color.red;
}
}
事件是一种特殊委托,非常适用于想要提醒其他类发生了某个事件。事实上,事件函数和公共多播委托非常类似。事件可被视为广播系统,对事件感兴趣的任何类都可以将方法订阅到事件,发生这个特定事件时,比如点击按钮、充能或玩家受伤,我们会调用事件进而调用已订阅的类的方法。
using UnityEngine; using System.Collections; public class EventManager : MonoBehaviour { //委托 public delegate void ClickAction(); //事件 注意它是一个静态变量 public static event ClickAction OnClicked; //这个类只负责在发生相应情况时 调用事件 void OnGUI() { if(GUI.Button(new Rect(Screen.width / 2 - 50, 5, 100, 30), "Click")) { //调用没有订阅者的事件将发生错误 if(OnClicked != null) OnClicked(); } } }
using UnityEngine; using System.Collections; public class TeleportScript : MonoBehaviour { //创建或启用这个脚本关联的对象时将调用这个内置方法 void OnEnable() { EventManager.OnClicked += Teleport; } //场景中的某个对象被禁用或销毁时会调用这个内置方法 void OnDisable() { EventManager.OnClicked -= Teleport; } void Teleport() { Vector3 pos = transform.position; pos.y = Random.Range(1.0f, 3.0f); transform.position = pos; } }
using UnityEngine; using System.Collections; public class TurnColorScript : MonoBehaviour { void OnEnable() { EventManager.OnClicked += TurnColor; } void OnDisable() { EventManager.OnClicked -= TurnColor; } void TurnColor() { Color col = new Color(Random.value, Random.value, Random.value); renderer.material.color = col; } }
取消事件的订阅是非常重要的,不然可能导致内存泄漏或游戏出错等问题。从上面的例子我们可以看到,
E
v
e
n
t
M
a
n
a
g
e
r
EventManager
EventManager只需要留意事件本身和事件触发器;
T
e
l
e
p
o
r
t
S
c
r
i
p
t
TeleportScript
TeleportScript和
T
u
r
n
C
o
l
o
r
S
c
r
i
p
t
TurnColorScript
TurnColorScript也不需要相互了解。
但是不难发现上面的例子利用公共委托变量也可以实现,那么为什么要使用事件呢?事件具有内在安全性,而委托变量没有。通过事件,其他类只能订阅和退订;如果改用公共委托变量,其他类可能会调用或覆盖公共委托变量。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。