[Hướng Dẫn] C# cho Unity

Dark TrollDark Troll Posts: 201Registered
Đống này mình dịch từ quyển Mastering Unity Script :D
[size=medium]Lưu ý tí[/size]
[size=small]LƯU Ý 1: C# là ngôn ngữ phân biệt chữ hoa với thường nha có nghĩa là If khác if, DARKTROLL khác DarkTroll khác darktroll khác DaRKtRoLl.
LƯU Ý 2: Xem dòng code dưới đây[/size]
using UnityEngine;
using System.Collections;

public class demo : MonoBehaviour
{

// Hàm này gọi một lần trước hàm Update
void Start ()
{

}

// Hàm này sẽ được gọi liên tục
void Update ()
{

}
}
[size=medium]VARIABLES (Biến)
[/size]
Cốt lỗi trong lập trình bằng C# chính là biến. Giống như trong toán học, biến có giá trị có thể thay đổi. Chính nhờ vậy ta dùng nó để lưu giữ một cục thông tin hay dữ liệu, như tên nhân vật, chỉ số HP, MP, sát thương,... Mỗi biến đại diện cho một đơn vị dữ liệu hay thông tin. Và mỗi thông tin hay dữ liệu sẽ là một loại hay một kiểu xác định. Ví dụ ta có Tên nhân vật sẽ là chuỗi kí tự như là: "John", "Dark Troll Ẹp Chai",... hay Chỉ số HP, MP là một số nguyên hoặc có thể là 100%(1) hay 50%(0,5) tùy vào bạn có bị ăn damage vào mặt hay không. Bởi vậy mỗi biến nhất thiết là phải có 1 kiểu dữ liệu xác định. Và phải được khai báo theo cú pháp của C#: <Kiểu dữ liệu> <Tên biến> = <Giá trị>.
Xét đoạn code dưới đây, ta thấy đây là một dòng code thể hiện một file script và môt class (lớp) được gọi là "MyNewScript" trong đó có 3 biến khác nhau có 3 kiểu dữ liệu khác nhau đã được khai báo.
01 using UnityEngine;
02 using System.Collections;
03 
04 public class MyNewScript : MonoBehaviour 
05 {
06     public string PlayerName = "";
07     public int PlayerHealth = 100;
08     public Vector3 Position = Vector3.zero
09 
10     // Use this for initialization
11     void Start () {
12 
13     }
14 
15     // Update is called once per frame
16     void Update () {
17 
18     }
19 }
Một số kiểu dữ liệu của biến 
•  int (Số nguyên) = -3, -2, -1, 0, 1, 2, 3…
•  float (Mình nghe mấy ông dạy C# trên mạng bảo là số thực :) ) = -3.0, -2.5, 0.0, 1.7, 
3.9…
•  bool (Kiểu logic) = true or false (1 or 0)
•  string (Xâu kí tự hoặc kí tự) = "hello world", "a", "another 
word…", "123"...
•  Vector3 (Vị trí trong không gian Oxyz ) =(x, y, z), (0, 0, 0), (10, 5, 0)…
Bây giờ nhìn lại đống code ta chú ý vào 3 dòng 06, 07, 08 ta thấy
  • biến PlayerName có kiểu dữ liệu là string.
  • biến PlayerHealth có kiểu dữ liệu là int.
  • biến Position có kiểu dữ liệu là Vector3.
Biến có giá trị thay đổi thế nó thay đổi như thế nào? Ví dụ bạn chơi mario và có x5 mạng, nếu bạn chết một mạng nữa thì bạn còn x4 mạng. Ta thấy mạng là một biến và nó có giá trị ban đầu là 5 và sau đó nó thay đổi thành 4. Hay bạn chơi game và có 500 gold sau đó mua một bình thuốc hết 200 gold và bây giờ bạn còn 300 gold. Thì biến Gold của bạn từ 500 nó đã thay đổi giá trị thành 300 gold. Nhìn chung biến có thể thay đổi trực tiếp hoặc gián tiếp nhưng không bao giờ thay đổi một cách vô căn cứ hay khó lường.
Xem thêm về biến tại: https://msdn.microsoft.com/en-us/library/ aa691160(v=vs.71).aspx
[size=medium]Câu lệnh điều kiện[/size]
Biến sẽ được thay đổi trong nhiều trường hợp khác nhau. Khi người chơi di chuyển, khi quái vật bị hạ, khi nhân vật lên cấp, vân vân.

Do đó bạn cần phải thường xuyên kiểm tra lại giá trị của các biến để chia nhánh sự thực thi của script dẫn đến những chuỗi hành động khác nhau, tùy thuộc vào giá trị của biến.
Ví dụ bạn có biến playerhealth có giá trị bằng 0, thì nhân vật bạn sẽ chết. Hoặc nếu biến playerhealth có giá trị thấp thì bạn nhận được cảnh báo như "Máu bạn đang quá thấp!!" chẳng hạn.
Do đó giá trị của biến điều khiển chiều hướng của script.
Và C# cung cấp cho chúng ta 2 loại câu lệnh điều kiện chính để chia nhánh hay chia hướng gì gì đấy ra như trên.
Và hai bé nó là lệnh If và lệnh Switch, dùng thì cũng dễ thôi vì bác viết sách bảo thế :3
[size=small]Câu lệnh if[/size]
Câu lệnh if sẽ được thực hiện khi điều kiện đưa ra là đúng (true); Xét thử đoạn code:
01 using UnityEngine;
02 using System.Collections;
03 
04 public class MyScriptFile : MonoBehaviour 
05 {
06     public string PlayerName = "";
07     public int PlayerHealth = 100;
08     public Vector3 Position = Vector3.zero;
09 
10     // Use this for initialization
11     void Start () {
12     }
13 
14     // Update is called once per frame
15     void Update () 
16     {
17         //Check player health - the braces symbol {} are option  for one-line if-statements
18         if(PlayerHealth == 100)
19         {
20         Debug.Log ("Player has full health");
21         }
22     }
23 }
Đoạn code này sẽ hoạt động như bất kì đoạn code nào khác trong Unity, khi bạn nhấp nút Play từ thanh toolbar, miễn sao file script này trước đó đã được gắn với một vật thể trong một cảnh (Scene) đang hoạt động.

Lệnh if ở dòng thứ 18 sẽ liên tục kiểm tra giá trị của biến PlayerHealth. Nếu mà giá trị của biến PlayerHealth chính xác bằng bằng (==) 100. thì đoạn lệnh bên trong {} sẽ được thực thi (dòng 19~21 á). Việc kiểm tra đều đưa về kết quả là đúng (true) hoặc (false). Như trên ta thấy khi lệnh if kiểm tra biến và thấy giá trị của biến PlayerHealth có giá trị == 100  => true. Do đó đoạn lệnh hay biểu thức tiếp theo sẽ được thực hiện. 
Quay lại đoạn code cái nào! Dòng thứ 20 Debug.Log cái này là một chức năng outputs của Unity nó sẽ cho cái dòng "Player has full health"hiển thị lên màn hình console của unity .cmfqkoh.jpg?1
 Cơ mà khoan đã! Nếu giá trị của biến PlayerHealth khác 100 thì như thế nào ??? 99, 88, 69,... Đương nhiên thì lệnh if nó sẽ khiến cho hành động diễn ra theo hướng khác. Như trên nếu giá trị khác 100 như 99, 96, 69,... thì dòng "Player has full health" sẽ không được in lên console. Có nghĩa là nó sẽ chỉ thực hiện khi biểu thức điều kiên là true!
Ngoài ra bạn có thể dùng dấu > và < để kiểm tra xem giá trị của biến lớn hoặc nhỏ hơn giá trị khác. Hay nếu muốn xem thử giá trị của biến có khác (hay gọi là không bằng) một giá trị khác thì dùng dấu !=. Ngoài ra bạn có thể dùng &&(AND) hoặc ||(OR) trong câu điều kiện.
Ví dụ điều kiện để thực thi dòng lệnh trong {} là nếu biến PlayerHealth lớn hơn hoặc bằng 0 bé hơn hoặc bằng 100 và khác 50.
Khi ta viết thành lệnh thì nó trong như thế này:
if(PlayerHealth >= 0 && PlayerHealth <= 100 && PlayerHealth !=50)
{
Debug.Log ("Player has full health");
}
Ngoài ra ta còn có câu lệnh if - else
if(Điều kiện của bé :3)
{
//X - các lệnh sẽ thực hiện khi điều kiện là true
}
else
{
//Y – các lệnh sẽ thực hiện khi điều kiện là false
}

Thêm thông tin về câu lệnh if:  http://msdn.microsoft.com/en-GB/library/5011f09h.
Câu lệnh switch
Khi có quá nhiều điều kiện để chọn thực hiện thì dùng câu lệnh if sẽ rất rối rắm và dài dòng khi đó ta sẽ dùng câu lệnh switch.
Ví dụ kẻ địch có các tương tác với nhân vật của bạn như (Tấn công, phòng thủ, bỏ chạy, trốn,...)
Xem thử dòng lệnh trong đó có từ khóa break dùng để thoát khỏi khối lệnh switch và thực hiện lệnh tiếp theo sau khối switch đó. 
01 using UnityEngine;
02 using System.Collections;
03
04 public class MyScriptFile : MonoBehaviour
05 {
06 //Định nghĩa những trạng thái sẽ xảy ra của kẻ địch sử dụng enum
07 public enum EnemyState {DUOI, BOCHAY, CHIENDAU, TRON};
08
09 //Trạng thái hiện tại của kẻ địch (hay gọi là cơ bản ấy)
10 public EnemyState ActiveState = EnemyState.DUOI;
11
12 //Start() chạy một lần duy nhất trước hàm update, hay nói cách khác nó dùng để khởi tạo
13 void Start () {
14 }
15
16 //Update() là một vòng lặp chạy liên tục. Nó được gọi một lần cho mỗi khung hình
17 void Update ()
18 {
19 //kiểm tra biến ActiveState 
20 switch(ActiveState)
21 {
22 case EnemyState.CHIENDAU:
23 {
24 //Hành động chiến đấu
25 Debug.Log ("Trang thai chien dau duoc nhap");
26 }
27 break;
28
29
30 case EnemyState.BOCHAY:
31 case EnemyState.TRON:
32 {
33 //Bo chay và tron thể hiện cùng một hành vi
34 Debug.Log ("Trang thai bo chay hoac tron duoc nhap");
35 }
36 break;
37
38 default:
39 {
40 //Default dùng chọn case mặc định, mà cái mặc định của chúng ta là cái case DUOI ở dòng 10 ấy
41 //nên cái này dùng cho cái trạng thái DUOI
42 Debug.Log ("Trang thai duoi duoc nhap");
43 }
44 break;
45 }
46 }
47 }
 Enumerations ( kiểu liệt kê)
Dòng 07 trong đoạn code biểu thị một Enumeration (enum) có tên là EnemyState. Một enum là một cấu trúc đặt biệt sử dụng để lưu trữ  một loạt giá trị để dùng cho một hay nhiều biến khác nhau. Bản thân mỗi giá trị trong nó không phải là một biến, nhưng nó chính là một cách để giới hạn giá trị của một biến có thể có. Trong đoạn code ví dụ ở trên biến ActiveState ở dòng 10 đã tận dụng enum EnemyState, tức là giá trị của ActiveState chỉ có thể là các giá trị đã được khai báo từ enum EnemyState. Enum hỗ trợ bạn giới hạn giá trị của biến với một phạm vi xác định cùng chuỗi lựa chọn.

Một lợi ích khác từ enum là các biến sẽ có các giá trị  hiện ra từ danh sách thả xuống trong Object Inspector, giống trong hình sau đây: (Các bạn tìm hiểu thêm phần giao diện của Unity nhé :)) )
[size=small]NlshCW7.jpg[/size]
Thêm thông tin về enum: http://msdn.microsoft.com/en-us/library/sbbt4032.aspx.
Sau đây là giải thích về đoạn code trên:
Ở dòng 20: Câu lệnh switch được thực hiện. Trong đó dấu () chứa biến mà ta cần xét giá trị hoặc trạng thái(state). Ở đây là biến ActiveState.
Ở dòng 22: case(trường hợp) đầu tiên được đưa ra xét trong câu lệnh switch. Các dòng lệnh bên trong {} (dòng 24 và 25 ấy ) sẽ được thực thi nếu biến ActiveState được gắn là EnemyState.CHIENDAU. Hoặc nếu không thì các lệnh đó bị bỏ qua.
Ở hai dòng 30 và 31: Đây là hai case theo nhau. Dòng lệnh trong {}( dòng 33 và 34) sẽ thực thi khi và chỉ khi ActiveState là hoặc EnemyState.BOCHAY hoặc EnemyState.TRON .
Ở dòng 38: Nếu không có case nào thích hợp và trong câu lệnh switch có dùng câu lệnh default thì các câu lệnh của trường hợp default sẽ được thực hiện. Trong trường hợp này nó sẽ được thực thi nếu ActiveState là EnemyState.Chase.
Ở các dòng 27, 36, và 44: ta thấy có lệnh break. Như đã nói, lệnh này đặt dưới mỗi trường hợp để thoát khỏi khối lệnh switch khi mà nó được thực thi, tức là đã có một case được thực thi. Sau khi thoát khỏi vòng lặp chương trình của ta sẽ chạy tiếp tục ở dòng lệnh sau khối switch ở đây là dòng 45.
Thêm thông tin về lệnh switch: http://msdn.microsoft.com/en-GB/library/06tc147t.aspx.
[size=medium]Arrays ( Kiểu mảng) 
[/size]
Những danh sách và những dãy xuất hiện ở mọi nơi trong game. Đó là tại sao, bạn phải cần thường xuyên theo dõi danh sách các dữ liệu cùng loại: tất cả kẻ thù cùng level, tất cả vũ khí bạn đang giữ trong túi đồ, hay skills, item trong túi đồ của bạn. Một kiểu của danh sách chính là Array (mảng ). Mảng là một tập hợp có thứ tự các đối tượng có cùng kiểu . Mỗi item trong mảng, về cơ bản nó là một đơn vị thông tin có khả năng thay đổi trong suốt gameplay. Mảng là một cách đơn giản để tập hợp tất cả các biến có liên hệ với nhau thành một khối (tất cả các quái vật này, items này, skills này bla bla ). Đó là lí do vì sao ta lại phải dùng mảng.

Trong C# , có hai loại mảng: Mảng tĩnh(static)mảng động(dynamic). Mảng tĩnh lưu giữ  một số lượng phần tử giới hạn cố định có trong bộ nhớ, bạn phải quyết định trước giới hạn đó, và nó sẽ giữ nguyên trong suốt quá trình chương trình thực hiện, cả khi bạn cần lưu trữ một lượng thông tin ít hơn giới hạn, dẫn đến là một số các phần tử sẽ bị lãng phí. Về mảng động có thể tăng hoặc giảm trong khả năng và theo yêu cầu để chính xác với lượng thông tin cần chứa. Với mảng tĩnh hoạt động nhanh và tốt hơn, còn mảng động thì tạo cảm giác trống trải và tránh lãng phí bộ nhớ.
Ở phần này ta chỉ tìm hiều về mảng tĩnh(static ) mảng động sẽ giành cho các phần sau.
Và ô kê, bắt tay vào ví dụ nào! 
01 using UnityEngine;
02 using System.Collections;
03
04 public class MyScriptFile : MonoBehaviour
05 {
06 //Array of game objects in the scene
07 public GameObject[] MyObjects;
08
09 // Use this for initialization
10 void Start ()
11 {
12 }
13
14 // Update is called once per frame
15 void Update ()
16 {
17 }
18 }
Dòng thứ 7 trong đoạn mã đã khai báo một mảng rỗng thuộc GameObjects có tên là MyObjects
Để khai báo mảng, ta sử dụng theo cú pháp <Kiểu dữ liệu>[]<tên mảng> ở trong ví dụ đây là mảng có kiểu dữ liệu là GameObjects và có tên là MyObjects. Và nó biểu thị một danh sách thuộc GameObjects đang được khai báo nó trái ngược với một GameObjects đơn lẻ.
Lúc này mảng được khai báo sẽ là một danh sách của tất cả các objects có trên scene. Ban đầu nó sẽ rỗng, sau đó bạn có thể dùng Object Inspector trong Unity Editor để bắt đầu xây dựng mảng bằng cách điều chỉnh giới hạn số phần tử của mảng và đính nó vào bất kì object nào mà bạn cần. Và bạn làm như sau, chọn object đã đính script vào, sau đó nhập vào giá trị cho phần Size trong trường My Objects để xác định giới hạn số phần tử của mảng, cần để bạn giới hạn lại số object mà bạn cần giữ. Sau đó để đưa các object vào các phần tử đang rỗng trong mảng bạn chỉ cần kéo các object mà bạn cần từ màn hình Hierarchy vào các slot của mảng ở Object Inspector để đưa các vật vào danh sách, như hình bên dưới.
vl2HIFX.png
Thay vì sử dụng Object Inspector chúng ta còn có thể tạo mảng trong code qua hàm Start() .
01 using UnityEngine;
02 using System.Collections;
03
04 public class MyScriptFile : MonoBehaviour
05 {
06 //Array of game objects in the scene
07 public GameObject[] MyObjects;
08
09 // Use this for initialization
10 void Start ()
11 {
12 //Build the array manually in code
13 MyObjects = new GameObject[3];
14 //Scene must have a camera tagged as MainCamera
15 MyObjects[0] = Camera.main.gameObject;
16 //Use GameObject.Find function to
17 //find objects in scene by name
18 MyObjects[1] = GameObject.Find("Cube");
19 MyObjects[2] = GameObject.Find("Cylinder");
20 }
21
22 // Update is called once per frame
23 void Update ()
24 {
25 }
26 }
Dòng thứ 10: Hàm Start() là hàm được thực thi đầu tiên. (Tạm thời thì bạn biết nó là hàm chạy đầu tiên :blush: )
Dòng thứ 13: Từ khóa new sử dụng tạo 1 mảng mới với sức chứa là 3 phần tử. Có nghĩa không thể có hơn 3 giá trị ( hay object nào đó ), cùng chứa trong mảng tại một thời điểm. (Bạn có 3 cái hộp và bốn cái nắp bạn chỉ có thể đậy 3 cái hộp với 3 cái nắp nếu muốn thế cái này phải lấy cái kia ra  :dodgy: ) Lúc đâu tiên mới khỏi tạo thì các phần tử trong mảng đều có giá trị là null. Nói chung là không có gì :(
Dòng thứ 15: Lúc này yếu tố đầu tiên trong mảng được set vào là camera object trên scene. Hai thứ cần phải nhớ, thứ nhất để gọi đến một phần tử trong mảng thì ta sử dụng chỉ số trong []. Giống như địa chỉ vậy ví dụ Mario[0], Mario[1]. Thứ hai phần tử đầu tiên của mảng có chỉ số là "0" tiếp theo là "1", "2", "3", ... Cho nên cái phần tử cuối trong mảng trên có chỉ số là 2 không phải 3.
Dòng 18 - 19: Phần tử chỉ số 1 và 2 của mảng MyObject sử dụng hàm GameObject.Find. Nó sẽ tìm trong scene đang hiện hành object có tên giống chuỗi trong "". Nếu nó không tìm được thì phần tử đó bằng null.
Tìm hiểu thêm về mảng: [size=x-small]http://msdn.microsoft.com/en-GB/library/9b9dty7d.aspx.
[/size]
[size=medium]LOOPS (Vòng lặp)[/size]
[size=medium]
[/size]
[size=medium]Trong Unity 3D chúng ta có sẵn hàm Update(){} cũng là một dạng vòng lặp. Và trong ngôn ngữ C# chúng ta có 2 loại vòng lặp là foreach(){}, for(){} while() (và do{}while()  nữa :3)[/size]
[size=medium]vòng lặp for[/size]

Giả sử mình có 5 cái xô, và mình cần đổ nước và các cái xô ấy
1 using UnityEngine;
2 using System.Collections;
3
4 public class NewBehaviourScript : MonoBehaviour {
5    public string[] MayCaiXoCuaTui;
6    // Use this for initialization
7    void Start () {
8        for(int i = 0;i < 5;i++){
9            MayCaiXoCuaTui[i] = "Nuoc";
10       }
11   }
12    
13   // Update is called once per frame
14   void Update () {
15   
16   }
17}
Dòng 5 mình khai báo mảng có tên là MayCaiXoCuaTui có kiểu dữ liệu là string
Dòng 8 là lệnh for(đầu tiên mình khai báo biến i có kiểu int; sau đó so sánh biến i với 5 ; tăng biến i lên  1)
Dòng 9 nếu i < 5 thỏa thì, cho cái xô thứ i bằng "Nuoc", nếu i = hoặc > 5 thì thoát ra khỏi vòng lặp
Sau khi vòng lặp thoát phần tử MayCaiXoCuaTui[0],[1],[2],[3],[4] sẽ có giá trị = "Nuoc"
vòng lặp while
Giả sử mình có 5 cái xô, và mình cần đổ nước và các cái xô ấy
1 using UnityEngine;
2 using System.Collections;
3
4 public class NewBehaviourScript : MonoBehaviour {
5    public string[] MayCaiXoCuaTui;
6    // Use this for initialization
7    void Start () {
8  int i = 0;
9        while(i < 5){
10           MayCaiXoCuaTui[i] = "Nuoc";
11      i++; 
12       }
13   }
14    
15   // Update is called once per frame
16   void Update () {
17   
18   }
19}
Dòng 5 mình khai báo mảng có tên là MayCaiXoCuaTui có kiểu dữ liệu là string
Dòng 8 mình khai báo biến đếm i
Dòng 9 là câu lệnh while nếu i < 5 thỏa thì chạy phần lệnh bên trong nó
Dòng 11 mình tăng i lên 1, i++; <=> i = i + 1;
Sau khi vòng lặp thoát phần tử MayCaiXoCuaTui[0],[1],[2],[3],[4] sẽ có giá trị = "Nuoc"
vòng lặp foreach
Giả sử mình chả biết mình có bao nhiêu cái xô, nhưng mình sẽ đổ hết nước vào nó
01 using UnityEngine;
02 using System.Collections; 
03 
04 public class MyScriptFile : MonoBehaviour 
05 { 
06     //Array of game objects in the scene 
07     public String[] MayCaiXoCuaTui; 
08 
09     // Use this for initialization 
10     void Start () 
11     { 
12      
13          foreach(String Xo in MayCaiXoCuaTui)
14          { 
15              Xo = "Nuoc"; 
17          } 
18    } 
19 
20    // Update is called once per frame 
21    void Update () 
22    { 
23    } 
24 }
Dòng 5 mình khai báo mảng có tên là MayCaiXoCuaTui có kiểu dữ liệu là string
Dòng 13 là dòng lệnh foreach, bạn có thể coi biến Xo là đại diện cho một phần tử bất kì trong
MayCaiXoCuaTui( gọi sao cho đúng ấy nhỉ? :( ), vòng lặp dừng khi duyệt toàn bộ phần tử trong mảng   
Sau khi vòng lặp kết thúc thì tất cả phần tử trong MayCaiXoCuaTuisẽ có giá trị = "Nuoc"

Vòng lặp vô hạn
Ở đây là 2 vòng lặp vô hạn
for(;;){
 //câu lệnh của bạn
}
while(true){
 //câu lệnh của bạn
}
Tớ muốn ngừng vòng lặp dù điều kiện vẫn thỏa hoặc thoát ra khỏi vòng lặp vô hạn?
dùng break;
Ví dụ tớ muốn đổ nước cho 3 cái xô và dùng vòng lặp vô hạn
while(true){
 MayCaiXoCuaTui[i] = "Nuoc";
 if(i == 2){ // vì xô của tớ được đánh số từ 0 tới 2
 break; // nếu i = 2 tức cái xô thứ 3 thì thoát vòng lặp
 }
}
Nếu tớ có 5 cái xô và tớ không thích đổ nước vào cái xô số 3, lúc đó tớ xài continue;
for(int i = 0;i < 5; i++){
 if(i == 3) continue; // nếu i = 3 => bỏ qua các dòng lệnh phía dưới
 MayCaiXoCuaTui[i] = "Nuoc";
}
Sau khi chạy xong MayCaiXoCuaTui[0],[1],[2],[4] sẽ có giá trị là "Nuoc"
[size=medium]
[/size][size=medium]Function (Hàm)[/size][size=medium]
[/size]
Hàm là tập hợp những đoạn mã, khi bạn gọi hàm tức là bạn gọi các đoạn mã đó.
Mục đích của hàm là để bạn không phải lặp lại 1 đoạn code y hệt nhiều lần.
Giả sử mình có ba loại nước: nước mía, nước dừa, nước cam. Và mình muốn đổ vào 3 cái xô và bỏ thêm tí nước đá:
01  using UnityEngine;
02  using System.Collections;
03
04  public class NewBehaviourScript : MonoBehaviour {
05    public string[] MayCaiXoCuaTui;
06    // Use this for initialization
07     void DoNuocVaoXo(ref string Xo, string LoaiNuoc){
08       Xo = LoaiNuoc + "có bỏ đá";
09   }
10   void Start () {
11        DoNuocVaoXo(ref MayCaiXoCuaTui[0], "Nước Cam");
12        DoNuocVaoXo(ref MayCaiXoCuaTui[1], "Nước Mía");
13        DoNuocVaoXo(ref MayCaiXoCuaTui[2], "Nước Dừa");
14        //hiển thị ra console các giá trị của các phần tử
15        Debug.Log (MayCaiXoCuaTui [0]);
16        Debug.Log (MayCaiXoCuaTui [1]);
17        Debug.Log (MayCaiXoCuaTui [2]);
18
19   }
20
21    // Update is called once per frame
22    void Update () {
23
24    }
25
26}
Dòng 7 là hàm DoNuocVaoXo() của mình có hai giá trị mình khai báo là Xo LoaiNuoc, lí do trước string Xo có "ref" là vì đây là tham biến( giá trị của biến thay đổi sau khi hàm chạy xong).
Dòng 8 cho biến Xo có giá trị bằng chuỗi loại nước cộng với "có bỏ đá" ví dụ loại nước của mình là "Nước Dừa" thì Xo có giá trị là "Nước Dừa có bỏ đá".
Dòng 11 vì là tham biến nên mình dùng từ khóa "ref" ở trước, sau đó mình ghi tên loại nước.
Dòng 12-13 tương tự dòng 11 khác cái xô.
Dòng 15-17 in ra console giá trị của các biến MayCaiXoCuaTui[0][1][2].

Đôi chút về tham biến va tham trị
- Tham biến thay đổi giá trị sau khi hàm chạy xong
- Tham trị giữ nguyên giá trị
Ví dụ như trên bạn thêm vào trên dòng 11
for(int i = 0; i < 3; i++){
  MayCaiXoCuaTui[i] = "rỗng";
}
sau đó cho chạy bạn sẽ thấy console in ra khi run:
GnGGuD4.png
sau đó bạn xóa hết từ khóa "ref" đi, bạn sẽ thấy console in ra khi run:
RohwS9N.png
Điều đó có nghĩa là trước khi xóa "ref" biến MayCaiXoCuaTui[0][1][2] sau khi truyền vào hàm và gán giá trị, sẽ thay đổi theo giá trị đã được gán trong hàm, ở đây ban đầu giá trị là rỗng và sau khi hạy hàm được gán thành LoaiNuoc + "bỏ nước đá".
Còn sau khi xóa "ref" biến MayCaiXoCuaTui[0][1][2] sau khi truyền vào hàm và gán giá trị, sẽ giữ nguyên giá trị ban đầu khi ra khỏi hàm, ở đây ban đầu giá trị là "rỗng".

Khi mình làm game sẽ có những khi nào mình cần gọi hàm ???
Ví dụ mình làm một cái battle system, mình có 4 nút "Tấn công :cool:  ", "Phòng thủ :dodgy: ", "Kĩ năng ;) ", "Run for your life  :( ". Khi đó mình bấm nút "Tấn công" mình sẽ gọi hàm TanCong(){}, nút "Phòng thủ" gọi hàm PhongThu(){},...
ví dụ ở đây hàm tấn công của mình như sau
void TanCong(int myDmg, ref int EnemyHP, int EnemyArmor){
    EnemyHP = EnemyHP - myDmg + EnemyArmor;
    myTurn = false;

}
Bạn có thể thấy hàm mình chạy sẽ tính lượng HP còn lại của con quái địch bằng công thức : Máu sau khi bị đánh = máu hiện tại của nó - sát thương mình gây + giáp. Đây chỉ là ví dụ thôi, một hàm tấn công có thể phức tạp hơn nếu như có chí mạng, block damage theo tỉ lệ bla bla tùy hệ thống game của bạn.
biến myTurn của mình các bạn có thể thấy, ví dụ trong một game đánh theo lượt thì sau khi thực hiện hành động tấn công, thủ, skills,... thì sẽ chuyển lượt cho đối thủ, nên sau khi tấn công xong biến này sẽ thành false.
hoặc hàm tấn công của mình có thể viết như sau
int TanCong(int myDmg,int EnemyHP, int EnemyArmor){
    myTurn = false;
    return EnemyHP - myDmg + EnemyArmor;
}
int trước TanCong gọi là kiểu trả về (ở đây là int, có thể là string, float, double, bool, bla bla)
Thường khi dùng hàm có kiểu trả về thì ta sẽ dùng một biến nào đó gán nó vào
lúc này thì nguyên cái hàm TanCong sẽ trả về giá trị có kiểu in giá trị đó bằng EnemyHP - myDmg + EnemyArmor.
Ví dụ ban đầu các biến EnemyHP = 10, myDmg = 4 và EnemyArmor = 1:
EnemyHP = TanCong(myDmg, EnemyHP, EnemyArmor); // Mình sử dụng biến EnemyHP gán giá trị của TanCong vào như trên nói này
tức là nó như thế này EnemyHP = TanCong(4, 10, 1); Và TanCong trả về (return) giá trị bằng 10 - 4 + 1 =  7
nên EnemyHP = 7
Lâu lâu mình update thêm một số cái trong phần lưu ý mọi người nhớ xem nhé :#
Còn tiếp...
«1

Comments

Sign In or Register to comment.