Tải bản đầy đủ (.pdf) (32 trang)

Lập trình game 2D với Unity

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (3 MB, 32 trang )

Chương

2

Lập trình Game 101
Bây giờ bạn đã biết cách sử dụng Trình soạn thảo Unity và đã sẵn sàng làm quen
với Trình soạn thảo script MonoDevelop. Đây chính là hai công cụ phát triển game
chính. Trình soạn thảo Unity là nơi bạn sẽ xây dựng game một cách trực quan, cũng
là nơi ghép nối bố cục cảnh của bạn bằng cách đặt các đối tượng trong đó. Còn
MonoDevelop là trình soạn thảo script nơi bạn sẽ viết mã nguồn. Mã nguồn này sẽ
cho các đối tượng game biết cách hành xử, ví dụ như cách phản hồi thao tác đầu
vào của người chơi hoặc phản hồi lẫn nhau. Script mã nguồn của bạn được đưa
vào game khi bạn liên kết nó với một đối tượng game. Trong chương này bạn sẽ
học cách tạo một script, viết một số mã nguồn đơn giản, sau đó liên kết script này
với một đối tượng game.
Bạn đã cài đặt MonoDevelop cùng với Unity trong Chương 1. Có lẽ bạn đã thấy trình
soạn thảo này trong thư mục Applications  Unity (Hình 2-1), ngoài ra bạn có thể
truy cập MonoDevelop trực tiếp từ Trình soạn thảo Unity. Đây là lựa chọn mặc định
nằm dưới mục External Script Editor trong mục Unity Preferences  External Tools
(Hình 2-2).

Hình 2-1.   Biểu tượng MonoDevelop.app và menu Finder của gói Unity đã tải về

25


26   CHƯƠNG 2: Lập trình Game 101

Hình 2-2.   Menu Unity Preferences
Với dự án AngryBots đã mở sẵn, trong Bảng Project hãy mở thư mục Assets 
Scripts  Animation và nhấn vào biểu tượng PlayerAnimation (Hình 2-3).



Hình 2-3.  Biểu tượng script PlayerAnimation trong Bảng Project
Trong bảng Inspector bạn sẽ thấy thông tin bổ sung về nội dung của script
PlayerAnimation (Hình 2-4). Bạn có thể mở script này trong MonoDevelop bằng
cách nhấn đúp vào file script hoặc nhấn nút Open… (Hình 2-5).


  CHƯƠNG 2: Lập trình Game 101 27

Hình 2-4.  Biểu tượng script PlayerAnimation trong Bảng Inspector3


28   CHƯƠNG 2: Lập trình Game 101

Hình 2-5.  Script PlayerAnimation đã sẵn sàng cho việc chỉnh sửa trong MonoDevelop
AngryBots là trò chơi thú vị và có thể dùng làm công cụ hữu ích để giới thiệu về Unity
và MonoDevelop, nhưng bây giờ đã đến lúc để bắt đầu học cách phát triển game
của riêng bạn.
Bạn sẽ bắt đầu từ đầu, vì vậy hãy tiếp tục và đóng cửa sổ MonoDevelop lại. Nếu
có thông báo nhắc nhở, thì đừng lưu bất cứ thay đổi nào cả. Từ menu trên cùng
của Trình soạn thảo Unity hãy chọn mục File  New Project để mở Project Wizard
(Hình 2-6).

Hình 2-6.  Menu Unity  File  New Project và Project Wizard
Đừng lưu bất cứ thay đổi nào đối với AngryBots nếu bạn được nhắc nhở. Hãy đặt
một cái tên cho dự án mới của bạn và nhấn Create Project. Unity sẽ đưa ra một vị trí
và tên dự án mặc định cho bạn. Nút Set… sẽ mở ra một cửa sổ Create New Project
để bạn có thể sử dụng làm phương tiện tùy chọn đặt tên và đặt lại vị trí của dự án
mới nếu như bạn thấy thế tiện lợi hơn. Hãy đặt một cái tên mang tính mô tả cho dự
án của mình nếu bạn thích; bạn có thể đặt lại tên sau này. Bạn có thể thấy các gói

tài nguyên riêng trong thư mục Standard Packages đã tải về với Unity, nhưng đừng


  CHƯƠNG 2: Lập trình Game 101 29
chọn bất kỳ gói nào tại thời điểm này. Hãy chắc chắn rằng tab Create new Project
được chọn, hãy để thiết lập mặc định là 3D, và tạo dự án mới.
Dự án mới sẽ xuất hiện như mô tả trong Hình 2-7.

Hình 2-7.  Sự xuất hiện của dự án mới trong giao diện Trình soạn thảo Unity
Chương này cung cấp phần giới thiệu về lập trình. Nếu bạn đã có một số kinh
nghiệm lập trình thì cũng đừng nên bỏ qua phần này – các ví dụ chứa một số biến và
hàm dành riêng và thường dùng trong Unity mà bạn sẽ sử dụng trong các chương
tiếp theo.

MonoDevelop
Khi Unity tạo ra một dự án mới, trình soạn thảo này sẽ cung cấp cho bạn bộ khung
xương (skeleton) của game. Bộ khung xương này có các yếu tố cần thiết cơ bản của
bất kỳ game nào, vì vậy khi bạn nhấn vào nút Play thì một game trống rỗng sẽ khởi
động và sau đó dừng lại khi bạn bỏ chọn nút Play. Việc phát triển game là “đắp thịt”
vào bộ khung xương này với nội dung kỹ thuật số và sự tương tác với các đối tượng
game, môi trường, và các script.
Ở menu trên cùng, hãy chọn mục GameObject  Create Empty (Hình 2-8).

Hình 2-8.   Menu trên cùng của Unity GameObject  Create Empty


30   CHƯƠNG 2: Lập trình Game 101
Bạn sẽ thấy đối tượng GameObject mới được liệt kê ra trong khung nhìn Hierarchy,
gizmo chuyển đổi của đối tượng trong khung nhìn Scene, và các chi tiết sâu hơn
trong mục Inspector (Hình 2-9).


Hình 2-9.  Đối tượng GameObject mới trong Trình soạn thảo Unity
Trong mục Inspector, nhấn vào nút Add Component, sau đó chọn mục New Script
từ menu hiện ra. Hãy đặt tên cho script là HelloWorld, và đảm bảo rằng ngôn ngữ
được chọn là Java Script, sau đó nhấn vào Create and Add để liên kết script này với
đối tượng game rỗng (Hình 2-10). Theo quy tắc thì tên này nên mang tính chất mô
tả, và nên được viết hoa chữ cái đầu và không chứa các ký tự đặc biệt hay khoảng
trắng, tuy vậy thì dấu gạch dưới vẫn được cho phép sử dụng.

Hình 2-10.  Cửa sổ xổ ra Add Component để thêm vào một script mới
Script này bây giờ được liệt kê trong Inspector dưới dạng một thành phần của đối
tượng GameObject, và bạn sẽ thấy một biểu tượng của script này xuất hiện trong
thư mục Assets (Hình 2-11).


  CHƯƠNG 2: Lập trình Game 101 31

Hình 2-11.   Script mới trong bảng Inspector dưới dạng một thành phần và trong mục Assets của Bảng Project dưới dạng một
biểu tượng
Nhấn một lần lên biểu tượng này để chọn và xem nội dung của script trong Inspector
(Hình 2-12).

Hình 2-12.   Nội dung của script mới trong bảng Inspector
Bạn có thể mở script này trong MonoBehavior bằng cách chọn mục Open trong
Inspector hoặc nhấn đúp lên biểu tượng của script trong thư mục Assets (Hình 2-13).


32   CHƯƠNG 2: Lập trình Game 101

Hình 2-13.   Script HelloWorld đã sẵn sàng chỉnh sửa trong MonoDevelop

Tương tự Unity, MonoDevelop cũng có các phím tắt và bạn có thể xem các phím này
trong mục MonoDevelop  Unity Preferences  KeyBindings (Hình 2-13).

Hình 2-14.   Menu MonoDevelop  Unity Preferences  Key Bindings của các phím tắt


  CHƯƠNG 2: Lập trình Game 101 33
Khi bạn tạo một script mới, Unity sẽ tự động thêm vào một số thành phần. #pragma
strict sẽ được thêm vào đầu tất cả các script của bạn. Dòng này báo cho trình
biên dịch biết rằng các biến phải có khai báo kiểu, bạn sẽ được học chi tiết hơn
về khai báo kiểu trong chương này. Unity cũng sẽ tạo ra các hàm Start() và
Update() rỗng. Bây giờ, hãy tiếp tục và xóa hàm Update() đi, nhớ xóa cả các
dấu đóng mở ngoặc đi kèm:
function Update () {
}

Khi script mới được liên kết với đối tượng game, thì hàm Start() sẽ được gọi mỗi
khi đối tượng game này tham gia vào một cảnh. Trong dự án mẫu này, đối tượng
game xuất hiện trong cảnh, vì vậy hàm Start() của đối tượng đã được gọi ngay
khi việc chơi game bắt đầu. Hãy gõ dòng mã nguồn đầu tiên của bạn giữa hai dấu
ngoặc của hàm Start() để xem cách đối tượng này hoạt động.
function Start () {
print(“Hello World!”);
}

Nhấn ⌘+S để lưu lại, sau đó trở về Trình soạn thảo Unity. Trong bảng Project, hãy
chọn tab Console. Đây là nơi bạn sẽ thấy đầu ra xuất hiện là kết quả của đoạn mã
mà bạn vừa viết. Trong khung nhìn Game hãy chắc chắn rằng tùy chọn Maximize on
Play được bỏ chọn vì vậy khung nhìn này sẽ không che khuất bảng Console. Bây
giờ hãy tiếp tục và nhấn vào nút Play. Trong khung nhìn Console, bạn sẽ thấy dòng

chữ “Hello World!” xuất hiện! (xem Hình 2-15.)

Hình 2-15.   Đầu ra “Hello World!” của lệnh print trong bảng Console
Một cách nữa để in ra thông báo trên bảng Console là sử dụng Debug.Log. “Gỡ lỗi”
(debugging) là quá trình tìm và sửa các lỗi được gọi với tên “lỗi” (bug) trong mã nguồn
của bạn. Bạn sẽ học chi tiết hơn về cách sử dụng lớp Debug và các hàm (function)
của lớp này trong Chương 10. Hãy thay đổi dòng mã của bạn giống như sau:
function Start () {
Debug.Log(“Hello World!”);
}

Lưu lại, chạy đoạn mã này trong Trình soạn thảo Unity bằng cách nhấn vào nút Play,
và nhìn vào bảng Console, bạn cũng sẽ nhìn thầy dòng chữ “Hello World!” như cũ
kèm theo một đoạn chú thích nhỏ khác (Hình 2-16).

Hình 2-16.  Đầu ra Hello World! của Debug.Log trong bảng Console.


34   CHƯƠNG 2: Lập trình Game 101
Phát triển Game là một quá trình học hỏi liên tục. Các bậc tiền bối tại Unity vẫn đang
tiếp tục bổ sung nhiều năng lực mới và nền tảng mới để bạn có thể cài đặt game của
mình. Thậm chí các nhà phát triển dày dạn nhất cũng phải cập nhật những thay đổi
và bổ sung mới nhất một cách thường xuyên nhất bằng cách tham khảo tài liệu hỗ
trợ được cung cấp. Mỗi dự án game mới có thể có những thứ mà bạn không quen
dùng hoặc có thể bạn muốn kiểm tra cẩn thận những thay đổi. Như vậy cách tốt nhất
với bạn để học UnityScript là tự tạo ra những ví dụ trong cuốn sách này trên Unity và
MonoDevelop, bạn sẽ làm quen với việc tham khảo tài liệu hỗ trợ một cách nhanh
nhất thông qua việc sử dụng chúng.
Hãy dừng game này lại và trở về đoạn script trong MonoDevelop. (⌘+Tab là một
phím tắt hữu ích khi bạn đang làm việc giữa hai cửa sổ.) Nhấn vào bất cứ đâu trên

mục Debug, rồi nhấn ⌘+‘ để mở phần tham khảo viết script Debug.Log trong trình
duyệt web của bạn (Hình 2-17).

Hình 2-17.  Mô tả về Debug.Log trong phần Scripting Reference của Unity
Bạn sẽ thấy mô tả rằng Debug.Log ghi ra một thông báo tới bảng Console, theo
sau là một dòng mã tương tự như dòng mã bạn đã viết.
Có một mô tả thứ hai nữa với mã nguồn mẫu cung cấp cho bạn nhiều thông tin hơn
trong tình huống có lỗi. Thay đổi dòng mã của bạn bằng cách thêm vào tham chiếu
tới đối tượng gameObject: Debug.Log("HelloWorld!", gameObject); nhấn
⌘+S để lưu lại, và nhấn vào Play trong Trình soạn thảo Unity. Bây giờ thông báo
“Hello World!” sẽ xuất hiện cùng với một số thông tin bổ sung khác do Debug.Log
tạo ra (Hình 2-18).


  CHƯƠNG 2: Lập trình Game 101 35

Hình 2-18.  Đầu ra của Debug.Log trong bảng Console kèm theo phạm vi Object
Bạn sẽ học thêm về gỡ lỗi và cách sử dụng những thông tin này trong các phần sau
của cuốn sách. Bây giờ thì như thế là đủ vì bạn đã thử nghiệm thành công đoạn mã
mẫu từ tài liệu hỗ trợ này.
Việc phát triển Game là một quá trình tương tác, bao gồm phương pháp thử và sai
cổ điển. Tài liệu hỗ trợ này chứa mã nguồn mẫu đầy đủ. Sẽ có lúc các phần diễn
giải được viết có thể không dễ hiểu ngay đối với bạn, nhưng khi bạn xem mã nguồn
mẫu hoạt động thì bạn sẽ hiểu rõ hơn. Đừng ngại thử làm những điều nhỏ nhặt này!
Một mẹo nhỏ trong quá trình thử nghiệm đó là: Trong mục Preferences  Key
Bindings bạn sẽ thấy rằng MonoDevelop cũng sử dụng các phím tắt như ⌘+Z để
Undo và Shift+⌘+Z để Redo giống như bạn thấy bảng các phím nóng của Unity bên
dưới mục Edit.
Khi bạn gõ mã nguồn của mình, bạn có thể thấy rằng MonoDevelop luôn cố gắng trợ
giúp bạn với chức năng tự động điền (autocomplete). Hãy lựa chọn và nhấn phím

Tab, khi đó MonoDevelop sẽ tự điền phần còn lại (Hình 2-19). Đây là chức năng hữu
ích giúp tăng tốc và đặc biệt là tăng độ chính xác bằng cách giảm khả năng lỗi chính
tả gây ra các lỗi nhỏ phiền toái.

Hình 2-19.  Những gợi ý xổ ra của tính năng tự động điền trong MonoDevelop
Ngoài ra MonoDevelop còn trợ giúp bạn xác định các lỗi. Hãy thử tạo một lỗi bằng
cách bỏ qua dấu chấm phẩy ở cuối dòng lệnh và lưu lại. Trong Trình soạn thảo Unity,
bạn sẽ thấy một cảnh báo được hiển thị trong bảng console, kèm theo gợi ý trợ giúp
từ Unity để sửa lỗi này (Hình 2-20).

Hình 2-20.  Cảnh báo lỗi trong bảng Console


36   CHƯƠNG 2: Lập trình Game 101
Nếu bạn cố tình nhấn vào Play, thì Unity sẽ liên tục nhắc bạn sửa lỗi này (Hình 2-21).

Hình 2-21.  Cảnh báo lỗi bổ sung trong bảng Console sau khi cố tình nhấn Play trong tình trạng còn lỗi
Biểu tượng cảnh báo lớn màu đỏ thật khó chịu, vì vậy hãy tiếp tục và sửa mã nguồn,
sau đó lưu lại.

Biến và Hàm
Máy tính chỉ làm theo những gì bạn bảo. Chúng sử dụng các biến để chứa dữ liệu,
và làm theo các chỉ thị để điều khiển và xử lý dữ liệu mà bạn đưa vào các hàm.
Hãy thay đổi mã nguồn của bạn giống như sau:
#pragma strict
// khai báo biến myVar của kiểu integer (số nguyên) và gán giá trị bằng 8.
var myVar : int = 8;
function Start () {

Debug.Log(myVar);

}

Trước tiên, hãy xem kỹ dòng lệnh thứ hai. Việc thêm vào hai dấu gạch chéo // ở đầu
dòng sẽ biến dòng đó thành chú thích, được biểu thị trong MonoDevelop bằng font
chữ màu xám. Chú thích được dùng để ghi chú cho chính bạn hoặc những nhà phát
triển khác, chẳng hạn như mô tả mục đích của khối mã theo sau. Mã nguồn hoàn
toàn rõ ràng khi bạn đang làm việc với nó nhưng có thể không rõ đối với người khác,
hoặc thậm chí gây khó hiểu cho bạn khi kiểm tra lại nhiều ngày hay nhiều tuần sau
đó. Vậy nên bạn và các đồng đội của mình hãy học cách xây dựng một thói quen tốt
đó là viết chú thích mã nguồn trong quá trình làm việc.

Chú ý  Việc chú thích mã nguồn luôn hữu ích trong quá trình gỡ lỗi. Bạn có thể vô
hiệu hóa đoạn mã bằng cách chuyển chúng thành chú thích thay vì xóa chúng đi, sau
đó bạn có thể dễ dàng kích hoạt lại khi cần thiết.

Với chú thích trên nhiều dòng, bạn hãy đặt ký tự /* ở đầu và */ ở cuối chú thích hay
đoạn mã. Hãy thử kiểu chú thích này trong hàm Start().


  CHƯƠNG 2: Lập trình Game 101 37
#pragma strict
// khai báo biến myVar thuộc kiểu Integer (số nguyên) và gán giá trị bằng 8.
var myVar : int = 8;
/* function Start () {

Debug.Log(myVar);
}*/

Lưu ý rằng đoạn mã của hàm Start() sẽ đổi sang màu xám, chỉ ra rằng hàm này
đang bị vô hiệu hóa. Lưu và chạy đoạn mã trong Unity, đúng như dự đoán của bạn,

bảng Console vẫn trống trơn. Bây giờ hãy bỏ ký hiệu chú thích ở hàm Start() để
kích hoạt lại hàm này và lưu lại.
Biến (variable) được dùng để lưu trữ và truy xuất (lấy) dữ liệu. Đây là cách mà
chương trình game ghi nhớ những thứ cần thiết cho việc quản lý gameplay.
Hãy nhìn vào dòng mã sau:
var myVar : int = 8;

Chia dòng mã thành các phần sau:
(1)

var

(2)

(3)

myVar :

(4)

int

(5)
=

(6)
8

(7)
;


1. Khai báo biến với lệnh var.
2. Tên biến. Tên biến nên mang tính mô tả, điều này sẽ giúp cho mã nguồn của
bạn dễ đọc hơn. Bạn có thể sử dụng bất kỳ ký tự nào trong bảng chữ cái và
dấu gạch dưới, nhưng không được dùng dấu chấm hay các ký tự đặc biệt
khác. Một thói quen tốt giúp cho mã nguồn của bạn dễ đọc hơn đó là tuân
thủ các quy ước lập trình chuẩn. Quy ước chuẩn trong việc đặt tên biến đó
là nếu ký tự đầu tiên của tên biến là một chữ cái thì nó không được viết hoa.
3. Dấu hai chấm phân tách tên biến và kiểu dữ liệu.
4. Kiểu dữ liệu của biến, trong trường hợp này int là kiểu số nguyên (integer).
5. Toán tử gán, được dùng để gán giá trị cho biến mà bạn vừa khai báo và đặt
tên. Bạn có thể không cần gán giá trị cho một biến kiểu integer khi khai báo.
6. Giá trị được gán cho biến, trong trường hợp này là kiểu integer. Integer là
toàn bộ các số bao gồm cả số âm (được biểu thị bằng dấu trừ ở trước). Dấu
phẩy và dấu cách không được cho phép – ví dụ 24, 0, và –3 là các số integer
hợp lệ nhưng 2,500 thì không, còn 2500 thì được.
7. Dấu chấm phẩy báo hiệu kết thúc lệnh. Tất cả các lệnh phải kết thúc bằng
một dấu chấm phẩy.
Trong hàm Start(), thông báo mà Debug.Log đã in ra bảng Console chính là giá
trị của biến myVar. Lưu và nhấn play để xác nhận điều này.
Biến chứa dữ liệu, còn hàm thì thực hiện một công việc gì đó. Các chỉ thị cho quá
trình thực hiện hàm được chứa bên trong cặp dấu ngoặc. Hãy xem những thành
phần của hàm Start():


38   CHƯƠNG 2: Lập trình Game 101

(1)
(2) (3) (4)
function Start () {


(5)

Debug.Log(MyVar);
(6)
}

1. Khai báo hàm với từ khóa dành riêng function.
2. Đặt tên hàm. Tên hàm bắt đầu bằng các chữ cái in hoa.
3. Các đối số mang thông tin được truyền tới hàm. Các dấu đóng mở ngoặc là
bắt buộc, vì vậy nếu không có đối số thì chúng sẽ được để rỗng.
4. Dấu mở ngoặc nhọn báo hiệu bắt đầu nội dung của hàm.
5. Các chỉ thị của hàm tuân theo định dạng của các câu lệnh – trong ví dụ này,
là lệnh Debug.Log.
6. Dấu đóng ngoặc nhọn báo hiệu kết thúc hàm. Vì đây là điểm kết thúc hàm
chứ không phải là lệnh, do vậy không cần sử dụng dấu chấm phẩy ở đây.

Lưu ý rằng MonoDevelop đã lùi đầu dòng lệnh Debug. Việc lùi đầu dòng này giúp
cho mã nguồn dễ đọc hơn. Theo đó, bạn có thể dễ dàng xác định riêng từng khối
mã. MonoDevelop sẽ thực hiện việc này tự động cho bạn, nhưng đôi khi bạn nhận
thấy rằng mình cần sắp xếp lại mã nguồn cho dễ đọc hơn. Trong mục MonoDevelop
Preferences  Key Bindings  Edit bạn sẽ thấy các phím tắt +] để lùi đầu dòng
hoặc ⌘+[ bỏ lùi đầu dòng (tiến ra ngoài), các phím này sẽ di chuyển khối lệnh có
kích thước bất kỳ nào được bạn bôi đậm. Hãy thử điều này với lệnh Debug, sau đó
với toàn bộ hàm Start. Thật dễ dàng, đúng không nào?
Để xem nhanh các toán tử số học (Bảng 2-1), hãy thay dòng mã Debug trong hàm
Start bằng các dòng sau:
print(6+2);
print(6-2);
print(6*2);

print(6/2);
print(6%2);

Bảng 2-1.  Định nghĩa toán tử số học
Toán tử số học

Ý nghĩa

+

phép cộng

-

phép trừ

*

phép nhân

/

phép chia

%

phép lấy phần dư

Lưu và nhấn play. Đầu ra trong bảng console sẽ giống như Hình 2-22:



  CHƯƠNG 2: Lập trình Game 101 39

Hình 2-22.   Kết quả đầu ra từ các toán tử số học
Bạn có thể đã biết bốn toán tử đầu tiên. Toán tử lấy phần dư là một phương tiện cho
phép bạn lấy phần dư, trong ví dụ trên là phần dư của phép chia 6 cho 2. Thử thay
đổi 6 thành 5, lưu, và nhấn play. Lần này thì dòng cuối cùng của đầu ra là 1, chính
là phần dư của phép chia 5 cho 2.
Tương tự hầu hết các ngôn ngữ lập trình khác, UnityScript cũng tuân theo thứ tự
chuẩn của các phép toán, trong đó phép nhân và phép chia được ưu tiên hơn phép
cộng và phép trừ.
Chỉnh sửa hàm Start về như sau:
print(6+2*4);

Đọc từ trái qua phải, tổng của 6 và 2 là 8, nhân với 4 là 32. Lưu và nhấn nút play,
và bạn sẽ thấy rằng Unity nhân 2 với 4 trước thành 8, sau đó cộng với 6 để trả về
đầu ra là 14.
Bạn có thể thay đổi thứ tự tính toán bằng cách sử dụng các dấu đóng mở ngoặc. Các
toán tử trong dấu đóng mở ngoặc có thứ tự cao hơn. Thay đổi dòng mã đó như sau:
print((6+2)*4);

Bây giờ khi bạn lưu và nhấn nút play, đầu ra sẽ là 32 vì Unity đã thực hiện thao tác
cộng bên trong cặp dấu đóng mở ngoặc trước.
Những toán tử số học này cũng được sử dụng cho các giá trị số học chứa trong các
biến. Hãy thay dòng mã đó bằng lệnh sau:
print(myVar + myVar);

Với giá trị 8 đã được gán trước đó cho biến myVar, thì bây giờ bạn sẽ thu được kết
quả là 16.
Hiện tại bạn đang làm việc với các biến integer, nhưng bạn cũng có thể khai báo một

biến kiểu dữ liệu float để xử lý các số thập phân. Biến có thể chứa tất cả các loại
kiểu dữ liệu, gồm string, boolean, và nhiều kiểu dữ liệu phức tạp hơn. Thực ra, bạn
đã sử dụng kiểu chuỗi trong những dòng mã nguồn đầu tiên của mình:
print("Hello World!");

Chuỗi ở trong dòng lệnh trên là các ký tự chứa trong dấu nháy kép. Phép nối
(concatenation) là thuật ngữ dùng cho việc ghép hai chuỗi độc lập với nhau thành
một chuỗi duy nhất. Hoặc diễn đạt theo một cách khác là bạn đã “cộng” các chuỗi
với nhau, nhưng điều quan trọng là bạn học được các thuật ngữ chính xác khi được


40   CHƯƠNG 2: Lập trình Game 101
giới thiệu, và điều này sẽ giúp bạn thuận lợi hơn khi thực hiện tìm kiếm trợ giúp trên
diễn đàn trong mục Unity Answers hoặc sáng suốt hơn khi rơi vào những nơi hỗn
độn. Hãy chỉnh sửa mã nguồn của bạn như sau:
#pragma strict
// khai báo biến myVar kiểu integer và gán giá trị bằng 8.
var myVar : int = 8;
var myString1 : String = “Hello “;
var myString2 : String = “World!”;
var myNewString: String;
function Start () {

myNewString = String.Concat(myString1, myString2);

Debug.Log(myNewString);
}

Lưu, nhấn play, và đầu ra của bạn sẽ là “Hello World!” Lỗi phổ biến nhất ở đây là
quên thêm các dấu cách khi cần.

Lệnh String.Concat giống với Debug.Log ở chỗ chúng đều chứa toán tử dấu
chấm (dot operator). Toán tử dấu chấm này là một dạng cú pháp viết mã, trong đó
dấu chấm phân tách các từ mã. Concat là một thành phần của String, tương tự
Log là một thành phần của Debug. Bạn có thể sử dụng phím tắt quen thuộc ⌘+’ trên
lệnh String và Debug để xem thêm các thành phần của chúng trong phần Unity
Scripting Reference.
Hàm Start là ví dụ khá tốt để chứng minh các lý thuyết cơ bản này, nhưng bây giờ
bạn cần sẵn sàng để viết hàm riêng của mình. Hàm (function) nhận vào các thông
tin, được gọi là đối số (argument), và thực hiện một số thao tác với những thông tin
này, sau đó trả về kết quả tùy theo đó.
Xóa các khai báo biến kiểu chuỗi đi và sửa hàm Start như sau:
var myVar : int = 8;
function Start () {

myVar = AddFive(myVar);

Debug.Log(myVar);
}

Lệnh myVar = AddFive(myVar); gọi hàm tên là AddFive(), bạn sẽ tạo hàm
này sau, và truyền vào cho hàm đó giá trị integer được lưu trong biến myVar.
Sau dấu đóng ngoặc nhọn của hàm Start(), hãy viết hàm mới được gọi trong hàm
Start và đặt tên là AddFive:
function AddFive (numberFromStartFunction : int) {

var newVar : int;

newVar = numberFromStartFunction + 5;

return newVar;

}

Khác với hàm Start(), hàm AddFive() cần nhận thông tin để xử lý thông
tin này với phép cộng thêm năm. Trong dấu đóng mở ngoặc là tham số
numberFromStartFunction được khai báo là kiểu dữ liệu integer. Điều này
nghĩa là khi gọi hàm, bạn phải truyền vào hàm một giá trị integer. Bạn đã khai
báo biến myVar là một số nguyên, vì vậy bạn sẽ thực hiện đúng việc gửi tới hàm
AddFive()kiểu dữ liệu integer trong lời gọi hàm AddFive(myVar). Tham số


  CHƯƠNG 2: Lập trình Game 101 41
numberFromStartFunction hoạt động giống như một biến trong hàm AddFive()
để chứa giá trị integer nhận được từ lời gọi hàm.
Lệnh đầu tiên của hàm AddFive() như sau:
var newVar : int;

Ở đây bạn đang khai báo một biến mới tên là newVar thuộc kiểu integer. Có lẽ nếu
nhớ lại phần phân tích các thành phần của hàm ở phía trên, thì bạn không nhất thiết
phải gán giá trị cho biến khi khai báo biến đó.
Biến newVar được khai báo trong hàm AddFive() vì vậy biến này chỉ có thể được
dùng trong hàm này mà thôi. Đây là một ví dụ của biến cục bộ (local variable), vì
phạm vi của biến bị giới hạn trong hàm mà biến được khai báo. Biến myVar là một
ví dụ của biến toàn cục (global variable); với phạm vi lớn hơn nhiều, biến này có
thể được dùng bởi bất kỳ hàm nào trong đoạn script này.
Lệnh thứ hai trong hàm, newVar = numberFromStartFunction + 5;, là quá
trình xử lý thực sự, bao gồm các chỉ thị của bạn, trong đó giá trị 5 được cộng vào giá
trị integer nhận được từ tham số numberFromStartFunction. Kết quả của phép
tính này sau đó sẽ được lưu trong biến cục bộ newVar.
Cuối cùng, lệnh return newVar; trả về giá trị được gán cho biến newVar và theo
đó giá trị này sẽ được gán cho myVar.

Quá trình này được mô tả trong Hình 2-23. Chạy (lưu và nhấn nút play) đoạn script
và tôi chắc chắn rằng, Unity sẽ cho bạn kết quả là 13. Tuyệt vời!
var myVar : int = 8;
function Start () {
myVar = AddFive(myVar);
}

Debug.Log(myVar);

function AddFive (numberFromStartFunction int)
:
{
var newVar : int;
newVar = numberFromStartFunction + 5;
}

return newVar;

Hình 2-23.   Luồng dữ liệu giữa hai hàm


42   CHƯƠNG 2: Lập trình Game 101
Toán học cần thiết đối với việc phát triển game, nhưng đối với những ai không có
hứng thú đặc biệt đối với việc giải các bài toán để giải trí thì tôi có một tin tuyệt vời:
Unity cung cấp hàng tá các hàm toán học có sẵn cho bạn. Nhưng trên hết việc thực
hiện siêu tốc các phép tính vẫn là những gì máy tính có thể làm tốt nhất, và mục
đích ở đây là giúp cho việc phát triển game tổng thể của bạn trở nên dễ dàng hơn.
Mathf là một trong số các bộ chứa các biến và hàm toán học tiện ích do Unity cung
cấp. Trong MonoDevelop, hãy cập nhật mã nguồn của bạn về giống như sau:
#pragma strict

function Start () {

Debug.Log(Mathf.PI);
}

Nhấn vào Mathf.PI, sau đó nhấn ⌘+‘ để mở phần Unity Scripting Reference của
hàm này (Hình 2-24):

Hình 2-24.  Mô tả hàm Mathf.PI từ trong mục Unity Scripting Reference
Tại đây bạn sẽ thấy rằng Mathf.PI là một biến tĩnh của kiểu dữ liệu float. Giá trị
của pi là hằng số, và biến tĩnh (static) tức là biến này sẽ không cho phép mã nguồn
của bạn thay đổi giá trị mà Mathf.PI đang chứa. Nhớ rằng khi bạn tạo một hàm,
thì kiểu đối số phải khớp với kiểu dữ liệu mà hàm chấp nhận. Phần tham khảo này
cung cấp cho bạn một thông tin hữu ích đó là kiểu dữ liệu của Mathf.PI là float, và
kèm theo một đoạn ngắn mã nguồn mẫu để minh họa cách thức sử dụng biến này.
Khi chạy script bạn sẽ thấy kết quả hiển thị trong bảng console hầu như không
có nhiều số thập phân như đã mô tả trong phần tham khảo. Điều này là bình
thường – vì bạn sẽ không cần đến độ chính xác hơn như vậy khi sử dụng các
game thông thường.
Nhấn vào chữ “Mathf” màu xanh da trời trong tiêu đề của mục Scripting Reference
để xem danh sách các biến và hàm Mathf đầy đủ (Hình 2-25).


  CHƯƠNG 2: Lập trình Game 101 43

Hình 2-25.   Mô tả về Mathf từ mục Unity Scripting Reference
Làm tròn số là hàm mà bạn chắc chắn sẽ phải dùng trong khi phát triển game. Đi tiếp
và cuộn xuống tới hàm Round và chọn (Hình 2-26).

Hình 2-26.   Mô tả về Mathf.Round từ mục Unity Scripting Reference

Tại đây bạn sẽ thấy rằng Mathf.Round là một hàm tĩnh chấp nhận kiểu dữ liệu float
dưới dạng tham số, kèm theo sau là một số ví dụ. Tiếp tục và sao chép rồi dán các
ví dụ này vào trong trình soạn thảo MonoDevelop và thử chạy xem sao.
Lưu ý chú thích cuối cùng trong phần mô tả này cho biết rằng hàm Mathf.Round
không làm tròn lên tất cả các số kết thúc bằng .5, mà sẽ tùy chọn làm tròn lên hoặc
xuống, tùy theo cách nào cho kết quả cuối cùng là số chẵn. Trong ví dụ thứ tư đã
nêu, bạn sẽ thấy 10.5 được làm tròn xuống thành 10 chứ không phải là 11 như bạn


44   CHƯƠNG 2: Lập trình Game 101
nghĩ. Khi bạn tra cứu bất cứ thông tin gì trong mục Scripting Reference, hãy dành
thời gian đọc toàn bộ phần mô tả - việc này có thể giúp bạn tránh được các tình
tiết khó chịu về sau thông qua các hành vi mà Unity đã cố gắng muốn báo cho bạn
trước.
Tuyệt vời! Bây giờ bạn đã làm quen với những kiến thức cơ bản về biến và hàm. Bạn
cũng sẽ dần quen với việc tham khảo mục Unity Scripting Reference và sử dụng các
hàm có sẵn mà Unity cung cấp. Đừng lo nếu phần lý thuyết này có chút mơ hồ; từ
các phần sau bạn sẽ có rất nhiều bài tập thực hành. Hãy tiếp tục làm việc với các ví
dụ và thực hành chúng, bạn sẽ sớm biết cách vận dụng các ví dụ thôi.

Biểu Thức Điều Kiện
Ngoài hàm toán học, các script của bạn cũng sẽ sử dụng hàm logic để định nghĩa
các luật của game, chẳng hạn như bao nhiêu lần bắn trúng thì tiêu diệt được một
quân địch, hay hành vi của một nhân vật dựa trên sức mạnh và khả năng tích lũy
được, và dĩ nhiên là các điều kiện này phải được đáp ứng để có chiến thắng lớn.

Boolean và Biểu Thức Điều Kiện
Biến kiểu boolean chỉ có thể có hai giá trị: true và false.
Trong trình soạn thảo MonoDevelop, hãy sửa script của bạn như sau:
var skyIsClear : boolean = true;

function Start () {

Debug.Log(skyIsClear);
}

Chạy script này và bảng console sẽ hiển thị true. Biến kiểu boolean thường được
dùng để quản lý hoặc “báo hiệu” (flag) một trạng thái hay một điều kiện. Ví dụ, tôi có
thể nói rằng “Nếu trời quang thì tôi sẽ đi ra ngoài chơi”. Như vậy tôi sẽ cần kiểm tra
xem mặt trời đã lên chưa, rồi sau đó mới ra quyết định dựa trên điều kiện đó.
Cập nhật lại đoạn mã trong hàm Start() về thành:
if (skyIsClear == true) {

Debug.Log("I will go out and play");
}

Đoạn mã này khá dễ đọc. Điều kiện mà bạn muốn kiểm tra được đặt trong cặp dấu
ngoặc đơn sau từ khóa if. Nếu điều kiện này được đáp ứng, thì khối lệnh trong các
dấu ngoặc nhọn sẽ được thực thi. Lưu ý rằng toán tử so sánh “bằng” là ==, khác với
toán tử gán = mà bạn dùng để thiết lập giá trị của biến. Tiếp tục và chạy đoạn mã
này. Tuyệt vời – Tôi phải ra ngoài chơi chút đây!
Lưu ý  Một trong các lỗi phổ biến của các lập trình viên mới bắt đầu là sử dụng dấu
= thay vì dấu == trong biểu thức điều kiện.


  CHƯƠNG 2: Lập trình Game 101 45
Chờ đã—nhưng điều gì sẽ xảy ra nếu trời vẫn quang nhưng thời gian lúc đó đã là
buổi tối? Vậy thì tôi không nên ra ngoài chơi trong trời tối như vậy. Bên dưới khai
báo biến đầu tiên, hãy thêm vào một dòng thứ hai:
var sunIsUp: boolean = true;


Bây giờ tôi muốn nói, “Nếu trời quang và mặt trời lên thì tôi sẽ ra ngoài chơi”. Sửa
lại biểu thức điều kiện if của bạn như sau:
if (skyIsClear == true && sunIsUp == true) {

&& là toán tử logic AND (VÀ). Bây giờ thì cả hai điều kiện này phải được đáp ứng để
đoạn mã bên trong khối lệnh được thực thi.
Toán tử logic OR (HOẶC) được biểu diễn bởi dấu ||, bằng cách nhấn tổ hợp Shift+\
hai lần trên máy Mac. OR có ý nghĩa đúng như những gì từ này mô tả: nếu một điều
kiện này hoặc một điều kiện khác được đáp ứng, mà không nhất thiết phải đáp ứng
cả hai, thì khối lệnh sẽ được thực thi.
Nếu bạn muốn các khối mã khác được thực thi dưới những điều kiện nhất định, thì
bạn có thể sử dụng nhiều hơn một lệnh if:
function Start () {

if (sunIsUp) {

Debug.Log(“I will get out of bed”);
}

if (skyIsClear) {

Debug.Log(“I do not need an umbrella”);
}
}

Vì cả hai biến này được thiết lập là true, nên khi chạy script này thì bạn sẽ thấy cả
hai lệnh trên đều xuất hiện trong bảng console.
Trong ví dụ này, nếu mặt trời không lên và trời không quang thì không có gì xảy ra
cả. Khi bạn muốn thực thi một khối mã khác nếu như không có điều kiện nào trong
số các điều kiện trước được đáp ứng thì bạn có thể sử dụng lệnh else:

function Start () {

if (sunIsUp) {

Debug.Log(“I will get out of bed”);
}

if (skyIsClear) {

Debug.Log(“I do not need an umbrella”);
}
else {

Debug.Log(“I am staying in bed”);
}
}

Các biến này vẫn được thiết lập là true, vì vậy script của bạn khi chạy vẫn sẽ không
làm gì khác, nhưng bạn có thể thấy rằng có nhiều cách để thử nghiệm một loạt các
điều kiện để điều khiển trực tiếp gameplay.
Lệnh if cũng có thể so sánh các giá trị số học. Các toán tử so sánh khác (Bảng 2-2)
mà bạn cũng có thể dùng gồm có toán tử <, >, <=, >=, và !=. ! biểu thị là “không,” vì
vậy != là toán tử so sánh có nghĩa “không bằng”.


46   CHƯƠNG 2: Lập trình Game 101
Bảng 2-2.  Định nghĩa các toán tử so sánh
Các toán tử so sánh

Ý nghĩa


==

Bằng

!=

Không bằng

<

Nhỏ hơn

>

Lớn hơn

<=

Nhỏ hơn hoặc bằng

>=

Lớn hơn hoặc bằng

Biểu thức điều kiện switch-case làm việc thay cho chuỗi lệnh if-else khi bạn
cần so sánh một biến với nhiều giá trị khác nhau.
Sửa script của bạn như sau:
#pragma strict


var diceRoll : float;
function Start () {

diceRoll = Random.Range(1, 6);

switch (diceRoll) {

case 1:
print
break;

case 2:
print
break;

case 3:
print
break;

case 4:
print
break;

case 5:
print
break;

case 6:
print
break;


default:

print
break;
}
}

(“You rolled a 1!”);
(“You rolled a 2!”);
(“You rolled a 3!”);
(“You rolled a 4!”);
(“You rolled a 5!”);
(“You rolled a 6!”);
(“It’s your turn - roll!”);

Đây là tình huống khi bạn khai báo biến nhưng không gán giá trị ngay. Thay vào
đó, khi gọi hàm Start(), thì biến diceRoll sẽ được gán bằng một số sinh ngẫu
nhiên giữa 1 và 6.
Sinh số ngẫu nhiên là một hàm phổ biến khác trong các game để xác định những thứ
như vị trí của các đối tượng game mới xuất hiện trong cảnh hoặc số lượng quân địch
trong đợt tấn công tiếp theo. Từ dòng mã diceRoll = Random.Range(1, 6);,
bạn có thể đoán được chuyện gì sẽ xảy ra, tuy vậy hãy tiếp tục và nhấn ⌘+‘ trên dòng
Random.Range để xem mục Scripting Reference (Hình 2-27):


  CHƯƠNG 2: Lập trình Game 101 47

Hình 2-27.  Mô tả hàm Random.Range từ mục Unity Scripting Reference
Đúng như những gì bạn nghĩ, khi gọi tới hàm Start(), biến diceRoll được gán

một số sinh ngẫu nhiên dựa trên hai đối số trong dấu ngoặc đơn, min và max. Lưu ý
rằng các tham số này là “inclusive” (tính cả giá trị hai tham số), hoặc nếu không bạn
sẽ phải sử dụng các đối số khác để sinh ra các số từ 1 đến 6.
Tiếp theo, lệnh switch lấy giá trị đã gán cho biến diceRoll và so sánh giá trị này
với các giá trị hằng số của mỗi trường hợp, trong ví dụ này là từ 1 tới 6. Khi so khớp
với một giá trị trong mệnh đề case nào đó, thì khối lệnh theo sau đó được thực thi.
Lệnh break sẽ kết thúc việc thực thi lệnh switch. Sau mệnh đề case cuối cùng,
bạn sẽ thấy lệnh default hoạt động tương tự như lệnh else—lệnh này được thực
hiện nếu không có giá trị nào trong các giá trị case khớp với đối số được truyền tới
lệnh switch lúc đầu.

Vòng lặp
Vòng lặp có tác dụng lặp lại các dòng mã. Bạn có thể kiểm tra trạng thái của một
nhóm các đối tượng game, hoặc tạo những đối tượng mới mà trong đó sử dụng các
dòng mã giống nhau đối với mỗi phần tử của nhóm.


48   CHƯƠNG 2: Lập trình Game 101

Vòng lặp for
Để dẫn chứng một vòng lặp for, trong trình soạn thảo MonoDevelop hãy sửa mã
nguồn như sau:
#pragma strict


var targets : int = 4;

function Start () {

for(var i: int = 0; i < targets; i++)

{

Debug.Log("This is target #" + i);
}
}

Hãy phân tích vòng lặp for này:

(1)
(2)
(3)
(4)
for(var i: int = 0; i < targets; i++)
(7)
{

(5) (6)


(8)

Debug.Log(“ This is target #” + i);
(9)
}

1. Từ khóa for.
2. Khai báo biến chỉ số có kiểu integer và gán giá trị khởi tạo là 0. Máy tính bắt
đầu đếm từ 0 thay vì 1, việc này có thể khiến chúng ta mất một chút thời gian
để làm quen và thường gây lỗi nếu như chúng ta quên mất.
3. Dấu chấm phẩy tách thành phần đầu tiên và thành phần thứ hai của lệnh for.

4. Lệnh điều kiện. Chỉ cần điều kiện này được đáp ứng, khối lệnh lặp sẽ được
thực thi. Nếu điều kiện không được đáp ứng, vòng lặp sẽ kết thúc và sự
thực thi của chương trình sẽ nhảy đến lệnh theo sau vòng lặp, trong trường
hợp này là dấu đóng ngoặc nhọn của hàm Start().
5. Dấu chấm phẩy tách thành phần thứ hai và thành phần thứ ba của lệnh for.
6. Bước tăng của vòng lặp. Bước tăng có thể được viết dưới dạng i = i + 1,
hay thậm chí là i += 1, tuy nhiên toán tử tăng ++ có nghĩa là cộng thêm 1
và là một dạng ký pháp viết tắt đẹp mắt. Ở đây 1 sẽ được cộng vào biến chỉ
số trước khi chỉ số được ước lượng trong lệnh điều kiện ở lần lặp tiếp theo
của vòng lặp for. Tương tự, biến chỉ số cũng có thể được giảm đi sử dụng
toán tử giảm -- (hoặc -=).
7. Dấu mở ngoặc nhọn của thân vòng lặp for.
8. Khối lệnh chứa các dòng mã được thực thi trong mỗi lần lặp của vòng lặp for.
9. Dấu đóng ngoặc nhọn của thân vòng lặp for. Tương tự một hàm, vòng lặp
for kết thúc bằng dấu đóng ngoặc nhọn chứ không phải là dấu chấm phẩy.
Chạy script của bạn, và bạn sẽ thấy rằng bạn có bốn lệnh mục tiêu phản ánh hiệu
ứng “đếm từ giá trị 0“ (Hình 2-28).


  CHƯƠNG 2: Lập trình Game 101 49

Hình 2-28.  Kết quả của vòng lặp for qua bảng Console

Vòng lặp while
Vòng lặp while cho phép bạn viết mã linh hoạt hơn bởi vì vòng lặp này sẽ có số lần
lặp bất kỳ miễn là kết quả của biểu thức điều kiện là true.
Thay đổi đoạn mã của bạn như sau:
#pragma strict
var numberOfTires : int = 0;
function Start () {


while(numberOfTires < 4)
{

Debug.Log(“I replaced an old tire on my car!”);
numberOfTires++;
}
}

Hãy phân tích đoạn mã này:
(1)(2)
while(numberOfTires < 4)
(3)
{
(4)

Debug.Log(“I replaced an old tire on my car!”);
numberOfTires++;
(5)
}

1. Từ khóa while.
2. Lệnh điều kiện.
3. Dấu mở ngoặc nhọn của thân vòng lặp while.
4. Khối lệnh chứa đoạn mã sẽ được thực thi trong mỗi lần lặp của vòng
lặp while.
5. Dấu đóng ngoặc nhọn của thân vòng lặp while. Giống như vòng lặp for,
vòng lặp while kết thúc bằng dấu đóng ngoặc nhọn chứ không phải là dấu
chấm phẩy.



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×