前言
這是紀錄本人學習Unity C#時的筆記,希望讓自己能夠整理思緒,方便記憶。 因為是新手自學的關係,也很有可能有誤解或錯誤的地方,請見諒…
類別Class
創造類別之後就可以持續使用創建的類別來創建物件,以武器為例,在遊戲裡有不同的武器,但是他們的屬性是一樣的,我們就可以在一個類別裡面設定不同的屬性來給不同的武器(物件)使用。
public class Weapon //創建一個名為Weapon的類別
{
private float _attack;
private float _attackSpeed;
private int _levelLimit;
//給予Weapon的類別裡三種屬性
}
↑為甚麼屬性要使用private而不是public,因為public不能夠給予限制,所以不夠安全(目前學到的,不知道有沒有例外),比如有可能出現負數的攻擊力或是負數的等級。
public float getAttack()
{
return _attack;
}
public void setAttack(float attack)
{
if (attack < 0)
{
attack = 0; //讓攻擊力不會為負數
}
_attack = attack;
}
↑利用上一篇使用到的method,再加上一些限制,就可以在調整屬性的時候不會出現設計者不想出現的數值(在這裡是不想出現負數的攻擊力)
另一種的封裝get與set的方式
這一種方法的好處是可以直接在inspector設置一些變數的設定欄位,方便在設定屬性時直接在Unity裡面操作。
public int levelLimit
{
get
{
return _levelLimit;
}
set
{
if (value < 0)
{
value = 0;
}
_levelLimit = value;
}
}
然後使用
NoviceSword.levelLimit = 50;
//set值,如果照之前的方式就是等於NoviceSword.setLevelLimit();
NoviceSword.levelLimit;
//get值,如果照之前的方式就是等於NoviceSword.getLevelLimit();
※備註1
雖然說按照上方的方式好處是可以直接在inspector設置一些變數的設定欄位,但是原本的setAttack()的方法我用以下方法↓一樣可以在inspector裡面直接調整NoviceSword的攻擊力…
[SerializeField] private int 調整攻擊力;
void Start()
{
Weapon NoviceSword = new Weapon();
NoviceSword.setAttack(調整攻擊力);
Debug.Log("攻擊力:" + NoviceSword.getAttack());
}
先記錄一下,應該有甚麼地方我誤會了。
物件
利用已封裝屬性的class創建物件,(這裡的封裝是指將屬性設為private,並且給予條件限制,請看上方攻擊力相關的程式碼。)
承接之前的程式碼,利用上方創建的Weapon類別,來創建名為NoviceSword的Weapon,以下以設定攻擊力屬性為例:
void Start()
{
Weapon NoviceSword = new Weapon();
NoviceSword.setAttack(100);
Debug.Log("攻擊力:" + NoviceSword.getAttack());
}
這樣就可以在屬性為private的情況下,修改屬性了,當然也可以使用前面的另一種方式來設定Weapon的屬性與修改。
有幾種屬性要設定就照著設定幾次。
建構子Constructor(有時簡稱ctor)別稱:構造方法、建構式)
如果不想要每一個屬性要設定的時候都要打一行程式碼來給予值的話,可以使用建構子,一次設定完屬性。
public class Weapon
{
private float _attack;
private float _attackSpeed;
private int _levelLimit;
public Weapon()
{
}
/*加上上方這一段是讓Weapon()小括號裡的值給予預設為0的參數,
不然只打下方的程式碼的話,
使用Weapon NoviceSword = new Weapon();會報錯沒有給予值。
必須使用Weapon NoviceSword = new Weapon(10,10,10);
像這樣有給予初始值的話才可以不打這一小段程式碼*/
public Weapon(float attack, float attackSpeed, int levelLimit)
{
_attack = attack;
_attackSpeed = attackSpeed;
_levelLimit = levelLimit;
}
}
↑建構子的格式:
- 名稱必須和類別一樣(在這個例子裡面都叫做Weapon)。
- 沒有回傳值(可以看到Weapon()前面直接是接public,沒有void也沒有int或是float)。
如何使用:
Weapon NoviceSword = new Weapon(100, 280, 50);
/*創建了一個名為NoviceSword的Weapon,屬性為…
float attack = 100,
float attackSpeed = 280,
int levelLimit = 50。
結構Struct
Struct與Class的使用格式基本上是一樣的,但是兩者在數值的類型上有差別。
按照我自己的理解Class有點像是上一篇裡面的Call By Reference,數值為參考類型(reference type),也就是對其中一個參數進行的變更可能會影響另一個參數所參考的物件,一種順著Class數值的地址順藤摸瓜找參數的感覺。
Struct則比較像是上一篇裡面的Call By Value,數值為實值型別(value type),也就是在傳遞參數時,是複製一份相同的資料結構後,再對資料進行處理。
命名空間namespace
Namespace它表示著一個識別碼(identifier)的可見範圍。一個識別碼可在多個命名空間中定義,它在不同命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何識別碼,它們不會與任何已有的識別碼發生衝突。
命名空間- 維基百科
命名空間(namespace),在我的理解裡像是資料夾,比如我們想要創造兩個不同種族的同一個名稱的Class,一個方法就是類別的名稱都不重複,或者我們可以創造這兩個種族的namespace然後在裡面創造同個名字的Class而不產生衝突。比如
namespace 種族A
{
public class Weapon
{
}
}
namespace 種族B
{
public class Weapon
{
}
}
使用的方法,在類別最上方可以使用using來指定預設是使用哪個名稱空間,例如:
using UnityEngine;
using System.Collections;
using 種族A;
public class 測試命名空間 : MonoBehaviour
{
void Start()
{
種族A.Weapon 武器1 = new 種族A.Weapon();
種族B.Weapon 武器2 = new 種族B.Weapon();
Weapon 武器3 = new Weapon();
}
}
在這種狀況,武器1跟武器2因為有指名道姓的創建物件,
所以武器1是使用種族A的Weapon類別;
武器2則是使用種族B的Weapon類別。
而武器3因為沒有指名道姓,所以程式碼會往上找有使用using的名稱空間裡的類別來優先使用,所以武器3是使用種族A的Weapon類別。
※備註2
如果在這個例子裡面最上方同時使用using 種族A; 與 using 種族B; 則系統會無法判斷要使用哪一個名稱空間裡的Weapon類別。
會報錯'Weapon' is an ambiguous reference between '種族A.Weapon' and '種族B.Weapon'
靜態成員Static
紀錄一下…似懂非懂…目前粗淺的理解,加上 static 修飾詞來宣告為靜態後,就會被存入Global,大家一起共用,任何人都可以使用,沒有存活周期,所以會一直佔用記憶體,因為共用所以也很難控制存取權限。
所以也不能把static變數所在的類別用new變成物件之後使用static變數,只能使用類別名稱去限定該static變數來使用。
public class TestStatic : MonoBehaviour
{
public static int staticVariable = 0;
public int variable = 0;
void Start()
{
TestStatic.staticVariable = 2;
只能使用類別名稱去限定該static變數來使用↑
如果int variable像上面static變數一樣使用類別名稱來限定的話則會出錯
ex : TestStatic.Variable = 2; (此為錯誤例子
TestStatic test = new TestStatic();
test.variable = 20;
new一個新物件之後才可以使用非靜態的變數, static變數則是不可在此使用
ex : test.staticVariable = 20;(此為錯誤例子
}
}