第一個也是最容易區分的一點就是聲明變量和方法。
JavaScript的腳本:
1. private var cubeTransform;
在C#中,同樣的代碼則會是:
1. private Transform cubeTransform;
這對方法同樣適用,在C#中,一個方法什么值也沒有返回,那么他的返回值為 void 類型,但是在JavaScript中則可以省略。
類的繼承也是不同的。在JavaScript和C#中,方法是隱型並且不可重載,除非方法聲明中添加虛擬關鍵字。不同的是C#只重載那些包含重載關鍵字的方法。而JavaScript不需要關鍵詞,只要重載類方法就可繼承他們。我們來看一個JavaScript類繼承的例子:
1. class Weapon extends Item
2. {
3. //Class members and declarations
4. }
在C#中,同樣的代碼則會是:
1. public class Weapon : Item
2. {
3. //Class members and declarations
4. }
這就是這兩種代碼的主要區別,實際上他需要定義全部的東西,像執行產出代碼,訪問GameObject和組件,激光投射等等。還有一些其他的不同點,比如導入函數庫的關鍵字(在JavaScript中用“Import”,在C#中使用“using”),但是這些聲明和關鍵字的不同就比較容易明白了。
1. //do this:
2. private var score:int;
3. //instead of this:
4. private var score;
======================================================
使用JavaScript來獲取GameObject很簡單,你只需要調用Find()靜態方法,並把想要的GameObject的名稱作為參數:
1. private var pawnGO:GameObject;
2. function Awake()
3. {
4. pawnGO = GameObject.Find("Pawn");
5. }
用C#也很相似:
1. using UnityEngine;
2. using System.Collections;
3.
4. public class PawnGetter : MonoBehaviour
5. {
6. private GameObject pawnGO;
7.
8. void Awake ()
9. {
10. pawnGO = GameObject.Find("Pawn");
11. }
12. }
在不考慮兩種語言的關鍵字和格式不同的情況下,代碼是完全一樣的(第一個代碼的第四行和第二個代碼的第八行是相同的)。不管代碼是強類型還是弱類型,GameObject.Find()方法總是會返回一個GameObject值。
現在,讓我們看看如何獲得一個GameObject上的組件。假設“PawnMover”組件賦給“Pawn”GameObject,讓我們來看看如何使用JavaScript獲得“PawnMover”組件:
1. private var pawnGO:GameObject;
2. private var pmSC:PawnMover;
3. function Awake()
4. {
5. pawnGO = GameObject.Find("Pawn");
6. pmSC = pawnGO.GetComponent("PawnMover");
7. }
基本上,要獲得“PawnMover”組件,我們所需要做的就是從“Pawn”GameObject調用GetComponent()方法,並把所需組件的名稱作為參數。除了名稱,我們也可以通過組件類型作為參數,但是像上面的例子我們用名字就行了。因為JavaScript是弱類型,返回值為組件,我們不需要把組件給PawnMover 類作為結果。在C#中也是一樣的:
1. using UnityEngine;
2. using System.Collections;
3.
4. public class PawnGetter : MonoBehaviour
5. {
6. private GameObject pawnGO;
7. private PawnMover pmSC;
8.
9. void Awake()
10. {
11. pawnGO = GameObject.Find("Pawn");
12. //returns a CS0266 error
13. pmSC = pawnGO.GetComponent("PawnMover");//<=returns a CS0266 error
14. //this is the right way to do it when using C#
15. pmSC = pawnGO.GetComponent< PawnMover >();
16. }
17. }
用C#就不可能只是調用GetComponent()方法並把該組件的名稱作為參數了,這樣他會導致錯誤CS0266,也就是說C#不能從一個類型隱型轉換為另一個格式。因為C#屬於強類型,我們不能把組件類型轉換為PawnMover類型。我們需要調用一個方法傳遞這個類型,強制GetComponent()方法返回“PawnMover”對象而不是組件。
======================================================
這系列第三節,解釋JavaScript和C#在Unity3d游戲引擎中編程時有什么不同。建議你最好先去閱讀第一和第二節,方便理解這節內容。
在第三節中,主要講解用JavaScript和C#讓一個GameObject向前移動有什么不同。現在我們來看一段使用JavaScript讓一個GameObject向前移動的代碼:
public var goTransform:Transform;
private var vel:int = 2;//how fast the game object is being moved
function Awake()
{
//get this GameObject's Transform
goTransform = this.GetComponent(Transform);
}
// Update is called once per frame
function Update()
{
//moves the containing GameObject forward
goTransform.position.z = goTransform.position.z + vel;
}
把這個腳本的目的是在每一個更新周期使goTransform的z軸坐標增加來控制讓goTransform向前移動的,現在讓我們看看用C#編寫代碼會是什么樣的:
using UnityEngine;
using System.Collections;
public class PawnMover : MonoBehaviour
{
public Transform goTransform;
private int vel = 2;//how fast the game object is being moved
void Awake()
{
//get this GameObject's Transform
goTransform = this.GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
//returns a CS1612 error
goTransform.position.z=goTransform.position.z + vel;//<=returns a CS1612 error
//this is the right way to do it when using C#
goTransform.Translate(Vector3.forward * vel);//moves the containing GameObject forward
}
}
這里我們可以看到,在C#中不能像JavaScript腳本中那樣直接改變goTransform的z軸坐標值來移動,這樣會產生CS1612error,因為我們是要改變一個值而不是引用該值。為了避免這個錯誤,在用C#編寫腳本時,我們用方法移動GameObejct,比如Translate()、 Rotate()、 RotateAround()等等。這些方法都是Transform類得公共成員變量。
=======================================================
yielding pauses代碼對於游戲編程是相當有用的,你可以用它更好的控制你游戲中的事件。無論是用JavaScript或C#都不能簡單的中斷Update()方法。相信你已經猜到了,我們今天要議論的是這兩種語言對此的解決方案有什么不同。我們這節中會給出這種解決方案的常用實例。現在我們來看看JavaScript是如何yield的:
private var textS:String;
private var counter:float = 0;
function Update ()
{
//call the function that waits three seconds to execute
WaitThreeSeconds();
}
//This function waits three seconds before executing
function WaitThreeSeconds()
{
//Waits three seconds
yield WaitForSeconds(3);
//converts the counter to a String and stores its value in textS
textS = "Three seconds has passed, now I'm counting..."+counter.ToString();
//add one to the counter
++counter;
}
function OnGUI()
{
//The next line displays the first line of text
GUI.Label(new Rect(20,20,250,20), "I will start counting in 3 seconds.");
//Displays the counter
GUI.Label(new Rect(20,40,500,20),textS);
}
這個代碼在屏幕上輸出了兩個文本,第一行會在開始不久就被渲染出來,第二行只會在暫停3秒后出現,yield代碼只會執行一次,然后再正常執行Update()循環(也就是說不會再等三秒在去執行一次WaitThreeSeconds())。有一點要注意,我們知道能在函數內用yield,Update()方法是不能被暫停的。
現在來看看C#代碼:
using UnityEngine;
using System.Collections;
public class Yield : MonoBehaviour
{
private string textS;
private float counter = 0;
void Update ()
{
//doesn't generate an error but doesn't work either.
WaitThreeSeconds();//<=does nothing
//start the coroutine named WaitThreeSeconds
StartCoroutine("WaitThreeSeconds");//<=right
}
//Waits three seconds before executing
IEnumerator WaitThreeSeconds()
{
//Waits three seconds
yield return new WaitForSeconds(3);
//converts the counter to a String and stores its value in textS
textS = "Three seconds has passed, now I'm counting..."+counter.ToString();
//add one to the counter
++counter;
}
void OnGUI()
{
//The next line displays the first line of text
GUI.Label(new Rect(20,20,250,20), "I will start counting in 3 seconds.");
//Displays the counter
GUI.Label(new Rect(20,40,500,20),textS);
}
}
主要區別就是我們在C#中不能把yield放在函數中使用,需要使用IEnumerator接口,之所以這樣只是因為C#就是這么設計的(關於IEnumerator接口的更多信息可以在http://www.devarticles.com/c/a/C-Sharp/Interface-IEnumerable-and-IEnumerator-in-C-sharp/2/這里找到)我們不能像調用普通函數那樣調用WaitThreeSeconds(),即便那么做也不會有任何反應的。所以我們的解決辦法就是想調用協同那樣調用WaitThreeSeconds()。(例如14行)
另外一個區別就是在21行,我們要用yield return new WaitForSeconds(3)來替換 yield WaitForSeconds(3)代碼,因為我們用IEnumerator接口需要一個返回值。
====================================================
先來看點兒基礎知識:何為射線投射?顧名思義,就是用程序模擬了一個現實生活中被打出的一道射線(“Ray”,譯者:O(∩_∩)O哈哈~我的名字)。在游戲編程中相當有用,Raycast類可以返回源點到射線碰撞某物體的距離(有的時候被用作得到碰撞物體的名稱)。Unity3D沒有單獨的Raycast類,它是被Physics, RaycastHit 和 Ray 功能分散的類。
我來舉一個用JavaScript投射射線的例子:
//Creates a ray object
private var ray : Ray;
//creates a RaycastHit, to query informarion about the objects that are colliding with the ray
private var hit : RaycastHit = new RaycastHit();
//Get this GameObject's transform
private var capsTrans : Transform;
function Awake()
{
//get this Transform
capsTrans = this.GetComponent(Transform);
}
// Update is called once per frame
function Update ()
{
//recreate the ray every frame
ray = new Ray(capsTrans.position, Vector3.left);
//Casts a ray to see if something have hit it
if(Physics.Raycast(ray.origin,ray.direction, hit, 10))//cast the ray 10 units in distance
{
//Collision has happened, print the distance and name of the object into the console
Debug.Log(hit.collider.name);
Debug.Log(hit.distance);
}
else
{
//the ray isn't colliding with anything
Debug.Log("none")
}
}
來看看它是如何工作的:
首先,我們需要創建一個射線對象(Ray object),並且每幀都要重新創建一次(例如第2和20行),該射線類具備如光線投射的方向和來源等屬性。
然后,我們需要一個RaycastHit類對象,獲取射線與其他GameObject的碰撞發生時的距離和一些其他的詳細信息。
接下來,我們需要從Physics類中調用Raycast()靜態方法(例如23行),這個方法將實際的投射出一道射線,記錄下射線源點、投射方向、RaycastHit 對象和距離這些參數,然后把距離和碰撞結果傳遞到RaycastHit對象。
乍一聽起來可能有些亂,但是多嘗試幾回就熟練了(更多信息請查看http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html),接下來看看C#代碼:
using UnityEngine;
using System.Collections;
public class Raycast : MonoBehaviour
{
//Creates a ray object
private Ray ray;
//creates a RaycastHit, to query informarion about the objects that are colliding with the ray
private RaycastHit hit = new RaycastHit();
//Get this GameObject's transform
private Transform capsTrans;
void Awake()
{
//get this Transform
capsTrans = this.GetComponent<Transform>();
}
// Update is called once per frame
void Update ()
{
//recreate the ray every frame
ray = new Ray(capsTrans.position, Vector3.left);
//Casts a ray to see if something have hit it
if(Physics.Raycast(ray.origin, ray.direction, out hit, 10))//cast the ray 10 units in distance
{
//Collision has happened, print the distance and name of the object into the console
Debug.Log(hit.collider.name);
Debug.Log(hit.distance);
}
else
{
//the ray isn't colliding with anything
Debug.Log("none")
}
}
}
當投射射線時,這兩種編程語言之間唯一的區別在第28行代碼上。現在來看看我們怎么Out關鍵詞來傳遞hit對象呢?因為在C#中Raycast()方法需要RaycastHit參數做參考,這恰巧也是out關鍵詞做的事情。所以我們用傳遞一個Raycast()的參考來代替傳遞對象(就好像我們在JavaScript中做的那樣)。(更多信息請參考http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx)。