1. Trang chủ
  2. » Công Nghệ Thông Tin

Phát triển game đơn giãn trên máy tính nhanh nhất

41 500 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 41
Dung lượng 338 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Lập trình game Lập trình game đơn giảnLập trình game nhanh nhấtcách Lập trình game Lập trình game trên máy tínhCách lập trình game đơn giảnLàm game onlineHướng dẫn làm gameLOLlàm game Liên minh online

Trang 1

Phát triển game đơn giãn trên Mobile(P1)

Giới thiệu:

Bài này nhằm mục tiêu cung cấp hướng dẫn, giới thiệu về cách thức để phát triển một trò chơi đơn giãn trong J2ME Trước khi đọc bài này, tôi khuyên bạn nên tìm hiểu sơ lược về platform J2ME.Đây là một trong 3 platform của Java được sử dụng để phát triển các ứng dụng trên các thiết bị nhúng, mobile…Bây giờ, hãy cùng tìm hiểu phần 1

Phần một:

Ngõ vào ứng dụng(entry point):

Trong tất cả các ứng dụng trên J2ME, để chạy ứng dụng chúng ta phải extends từ lớp

ảo(abstract) MIDlet trong gói javax.microedition.midlet, tương tự như tạo một applet phải extend

từ lớp java.applet.Applet Và entry point của nó là phương thức startApp(), tương tự như phươngthức main() trong J2SE

Ví dụ: Ta có một lớp MyMidlet

publicclass MyMidlet extends MIDlet{

// invoked when the application starts and each time is resumed

protectedvoid startApp() throws MIDletStateChangeException {}

// invoked when the MIDlet needs to be destroyed

protectedvoid destroyApp(boolean uncondicional) throws MIDletStateChangeException {}

// invoked when the MIDlet needs to be paused (Some phones ignore pauseApp().)

protectedvoid pauseApp() {}

}

Nếu bạn tạo project và chạy file này thì nó chỉ hiển thị màn hình blank

Tiếp theo, để trình bày nội dung trong ứng dụng, bạn cần sử dụng lớp Display Lớp Display điều khiển tất cả những gì xảy trong màn hình của MIDlet, mỗi MIDlet có một đối tượng Display và truy cập nó thông qua việc sử dụng phương thức tĩnh getDisplay()

Để biểu diễn một đối tượng nào đó trên màn hình, bạn cần phải sử dụng phương thức

setCurrent() của lớp Displayable

Ví dụ: ta có một lớp Alert, lớp này kế thừa từ lớp Displayable, trong ví dụ này sử dụng Alert để hiển thị một câu thông báo đơn giãn lên màn hình

Alert alert;

//entry point for the application

protectedvoid startApp() throws MIDletStateChangeException {

// creates alert

alert = new Alert("Hello World");

// shows alert in the screen.

Display.getDisplay(this).setCurrent(alert);

}

Nếu chạy chương trình, bạn sẽ thấy nó hiển thị ra một thông điệp như sau:

Tiếp theo, để thêm các command cho ứng dụng, như commad exit, bạn xử lý như sau:

Command comExit;

[ ]

protectedvoid startApp() throws MIDletStateChangeException {

Trang 2

// create command

comExit = new Command("Exit", Command.EXIT, 1);

// add a command to exit the Midlet

publicclass MyMidlet extends MIDlet implements CommandListener{ publicvoid startApp()

{ [ ] // adds a listener to the alert alert.setCommandListener(this); } publicvoid

commandAction(Command cmd, Displayable display) { // check what command was selectedif

(cmd == comExit) { notifyDestroyed(); } } }

Với thay đổi này, chúng ta có một MIDlet hoàn chỉnh Ở phần tiếp theo, chúng ta sẽ có một cái nhìn chi tiết hơn về các phần tử giao diện người dùng như: Alert, Display, và CommandListener

Trang 3

Phát triển game đơn giãn trên Mobile(P2)

Ở phần này, ta tìm hiểu về các thành phần giao diện người dùng(UI) có sẵn trong J2ME nhằm tạo ra sự tương tác giữa người dùng với điện thoại, đây là vấn đề quan trọng bởi kích thước của màn hình điện thoại được giới hạn J2ME cung cấp đặc tả MIDP chứa các thành phần giao diện

đồ họa, hiện nay đã có rất nhiều phiên bản MIDP 3.0, tuy nhiên trong bài này tôi chỉ xét MIDP 2.0 Ta cùng tìm hiểu sơ đồ phân lớp của nó:

MIDP 2.0 cung cấp các lớp UI trong một gói javax.microedition.lcdui, trong đó lcdui là viết tắt của liquid crystal display user interface(LCD UI) Để show một phần tử UI lên màn hình, bạn phải sử dụng một lớp Displayable Ví dụ, một lớp Displayable có thể có một title, một ticker, và các command liên kết với nó

Lớp Display quản lý những cái gì hiển thị lên màn hình Phương thức static getDisplay(MIDlet midlet) cho phép bạn truy cập vào Display của MIDlet Sau đó, bạn sử dụng phương thức

setCurrent(Displayable element) để lựa chọn đối tượng nào extend từ Displayable được hiển thị lên màn hình Tại một thời điểm, chỉ có một đối tượng Displayable được hiển thị trên màn hình Hãy xem lại ví dụ từ bài trước:

Display.getDisplay(this).setCurrent(alert);

Trong MIDP, nó phân chia các lớp thành 2 thành phần: các thành phần giao diện cấp level interface component) và cấp thấp(low-level)

Trang 4

cao(high-Các thành phần high-level được thực thi thông qua các lớp extends từ class Screen, còn các thànhphần low-level được thực thi thông qua các lớp extends từ class Canvas Và tất cả chúng đều extends từ class Displayable.

Bất kỳ một ứng dụng nào cũng có thể kết hợp cả các thành phần giao diện high-level và level để phục vụ cho mục đích của ứng dụng Ví dụ, trong một ứng dụng game, List và Form có thể được sử dụng để chọn lựa hay cấu hình game, trong khi Canvas (hay GameCanvas) được sử dụng cho các thành phần tương tác của game như tạo nhân vật chuyển động, ảnh background

dụ, sử dụng lớp Command để tạo ra đối tượng command thông qua cung cấp các giá trị trong Constructor:

// adds a command to exit the MIDlet

comExit = new Command("Exit", Command.EXIT, 1);

Lưu ý rằng các command không thay đổi khi chúng được tạo ra.

Nếu xác định command type, bạn có thể cho phép thiết bị chạy MIDlet ánh xạ(map) bất kỳ phím định sẵn nào trên thiết bị vào command đó Ví dụ, một command với kiểu OK được ánh xạ vào phím OK của thiết bị Trong MIDP 2.0, nó có sẵn các kiểu command sau: BACK, CANCEL, EXIT, HELP, ITEM, SCREEN và STOP Kiểu SCREEN liên quan đến một command được maptrong ứng dụng cho màn hiền hiện thời Cả SCREEN và ITEM không có bất kỳ các phím được ánh xạ trên thiết bị.Để nhận được phản hồi từ người dùng, bạn cần phải listen từ các command, điều này được thực hiện thông qua thực thi giao diện CommandListener Trong ví dụ Hello World, Interface được thực thi thông qua phương thức commandAction()

Giao diện người dùng cấp cao(High-level User Interface):

Các API của giao diện người dùng cấp cao được thiết kế cho các ứng dụng kinh doanh của các khách hàng mà các thành phần client của nó chạy trên các thiết bị di động Đối với các loại ứng

Trang 5

dụng này, tính linh động(portability) qua nhiều thiết bị là rất quan trọng Để đạt được tính linh động như vậy, các API của nó ở mức cao được trừu tượng hóa(abstraction) và cung cấp ít các điều khiển hơn các look anh feel Điều này cho phép thiết bị sử dụng look and feel giao diên người dùng tự nhiên(native) để hiển thị thay thế cho các thành phần giao diện MIDP high-level Điều này có nghĩa khi một môt ứng dụng được viết bằng API high-level, nó look and feel một cách tự động sử dụng look and feel của thiết bị mà ứng dụng đang chạy, còn đối với người dùng cuối, điều này cung cấp sự tương tác với người dùng một cách liền mạch, đó là ứng dụng MIDP làm việc như là các ứng dụng native trên thiết bị.

Tóm lại, khi sử dụng API high-level, bạn có thể:

 Vẽ để được hiển thị bởi hệ thống phần mềm của thiết bị Ứng dụng không định nghĩa giao diện trực quan như hình dáng, màu sắc… của các thành phần high-level

 Điều hướng, cuộn, và các tương tác nguyên thủy khác với các thành phần giao diện ngườidùng được thực hiện bởi thiết bị Tuy nhiên, ứng dụng không nhận biết được các tương tác này

 Ứng dụng không thể truy cập vào các kỹ thuật input cụ thể, như các phím nhấn cụ thể nàođó

Alert:

Ứng dụng Hello World sử dụng một alert Phần tử này đại diện cho một màn hình(Screen) dùng

để show dữ liệu đến người dùng và đợi một thời gian trước khi xử lý đối tượng Displayable tiếp theo Một Alert thì có thể chứa môt chuỗi text và một image.Thông thường, Alert được sử dụng

để thông báo lỗi hay các ngoại lệ khác

TextBox:

Kế thừa từ lớp Screen, cho phép người dùng nhập và chỉnh sửa text Lớp này có thể được cấu hình để thích nghi với các nhu cầu của bạn.Bạn có thể giới hạn maximum các ký tự hiển thị trong TextBox Ngoài ra, bạn có thể ràng buộc các kiểu nhập cho TextBox bằng cách sử dụng các flag được định nghĩa trong lớp TextField Có 6 ràng buộc(constrain) để giới hạn nội dung hiển thị, đó là: ANY, EMAILADRR, NUMBERIC, PHONENUMBER, URL và DECIMAL Có

6 ràng buộc ảnh hưởng tới kiểu nhập: PASSWORD, UNEDITABLE, SENSITIVE,

NON_PREDICTIVE, INITIAL_CAPS_WORD, và INITIAL_CAPS_SENSITIVE Ví dụ, chỉ cho phép địa chỉ email được phép nhập trong TextBox, bạn thiết lập flag

TextField.EMAILADRR sử dụng phương thức setConstrains(), ngoài ra để kết hợp nhiều ràng buộc cùng lúc, bạn sử dụng toán tử OR giữa các flag Ví dụ:

setConstraints(TextField.EMAILADDR | TextField.UNEDITABLE);

List:

Một List chứa một danh sách các chọn lựa Khi List được biểu diễn trên màn hình, người dùng

có thể tương tác với nó bằng cách chon lựa các phần tử, di chuyển qua lại giữa các phần tử của List Nó có các kiểu cấu hình sau:

 Choice.EXCLUSIVE: chỉ có 1 phần tử được chọn lựa

 Choice.MULTIPLE: có thể có nhiều phần tử được chọn lựa

 Choice.IMPLICIT: phần tử được hightlight được chọn lựa

Trang 6

Nó chứa nhiều item, bất kỳ lớp nào extends từ lớp Item để có thể được chứa trong một Form Việc thực thi xử lý các layout, traversal, và scrolling Nội dung của Form có thể được cuộn lại với nhau

Các loại Item có thể được thêm vào trong Form:

StringItem: là một label và không cho phép người dùng sửa lên nó Item này có thể chứa một

tiêu đề và một text, và cả hai đều có thể null

DateField: cho phép người dùng nhập ngày date/time một trong 3 dạng sau: DATE, TIME và

DATE_TIME

TextField: Tương tự như TextBox.

ChoiceGroup: Tương tự như List.

Gauge: sử dụng để mô phỏng process bar, tuy nhiên nó có thể sử dụng trong kiểu tương tác bởi

người dùng, ví dụ nếu bạn muốn dùng nó để show một Volume Control

ImageItem: Nắm giữ một image.

CustomItem: là một lớp ảo abstract cho phép các subclass tạo ra giao diện riêng, tương tác riêng

và cơ chế thông báo riêng của nó Nếu bạn muốn một phần tử UI khác so với các phần tử được cung cấp thì bạn có thể tạo ra subclass

Giao diện người dùng cấp thấp(Low-level User Interface):

Các API của low-level user interface( như lớp Canvas) được thiết kế cho các ứng dụng cần sự sắp đặt và điều khiển các phần tử graphics một cách chính xác cũng như truy cập vào các low-level input event Ví dụ điển hình là game board, một chart object hay một graph Sử dụng low-level user interface, một ứng dụng có thể:

 Kiểm soát những gì được vẽ trên màn hình

 Điều khiển được các sự kiện primitive như các sự kiện nhấn phím(key press) và nhả phím(key release)

 Truy cập vào cụ thể từng phím và các thiệt bị đầu vào khác

Ngoài ra, trong MIDP 2.0 còn cung cấp javax.microediton.lcdui.game Gói này bao gồm 5 class dùng để thiết kế cho các game, đó là : GameCanvas, LayerManger, Layer, Sprite và TiledLayer Bạn có thể tìm hiểu phần này sau

Ví dụ về giao diện người dùng:

Đối với mỗi màn hình game, chúng ta tạo một phương thức init[ScreenName] để khởi tạo màn hình và trả về đối tượng Displayable được tạo ra:

Đối với Main Menu, bạn sử dụng component List để biểu diễn main options Ví dụ:

public Displayable initMainForm() {

if (mainForm == null) {

Trang 7

// creates a implicit List where the current element is

// the selected

mainForm = newList("Menu", List.IMPLICIT);

// append list options

mainForm.append("New Game", null);

mainForm.append("Options", null);

mainForm.append("Scores", null);

mainForm.append("Help", null);

mainForm.append("Exit", null);

// adds a select Command

comSelect = new Command("Select", Command.ITEM, 1);

public Displayable initSettingsForm() {

// check if already created

if (settingsForm == null) {

settingsForm = new Form("Settings");

settingsForm.addCommand(initBackCommand());

settingsForm.setCommandListener(this);

// creates a choice Group for sound options

soundChoice = new ChoiceGroup("Sound", List.EXCLUSIVE);

Đối với Help Screen, bạn chọn phần tử Form với static message:

public Displayable initHelpForm() {

if (helpForm == null) {

helpForm = new Form("Help");

helpForm

append("User cursors to move your pad, don't let "+

"the ball go by you, hit all the bricks!");

Để giới thiệu High Score, bạn sử dụng một Form với các item của nó là TextField và DateField:

public Displayable initNewHighScore(int score, int pos) {

Trang 8

if (newHighScoreForm == null) {

newHighScoreForm = new Form("New High Score");

newHighScoreForm.setCommandListener(this);

// create items

highScoreName = newTextField("Name", "", 20, TextField.ANY);

highScoreValue = new StringItem("Score", Integer.toString(score));

highScorePosition = new StringItem("Position", Integer.toString(pos));

// create save command

highScoreSave = new Command("Save", Command.OK, 1);

// append command and itens to screen

publicvoid endGame(int lifes, int score, int time) {

Displayable nextScreen = initMainForm();

Bây giờ, tất cả các phương thức đã được tạo ra, bạn link chúng đến phương thức

commandAction() Rewrite code:

publicvoid commandAction(Command cmd, Displayable display) {

// check what screen is being displayed

Trang 9

int pos = Integer.parseInt(highScorePosition.getText())-1;

// advance all the scores

for ( int i = scores.length-1; i > pos ; i ){

Bạn lưu ý cách thức sử dụng phương thức display(), vì đây là cách đơn giãn để kích hoạt đối tượng Displayable

publicvoid display(Displayable display) {

// shows display in the screen.

Display.getDisplay(this).setCurrent(display);

}

Bài tiếp theo sẽ mô tả làm thế nào để cài đặt một Game Screen

Trang 10

Phát triển game đơn giãn trên Mobile(P3)

Ở bài trước, chúng ta đã hoàn thành một giao diện menu cho game.Tuy nhiên, màn hình Game Screen vẫn chưa được tạo ra Mục đích của bài này là sinh ra một Game Screen có giao diện như hình dưới:

Các thành phần giao diện cấp cao không thể sử dụng cho game screen bởi vì chúng ta phải điều khiển tất cả các phần tử trong game khi chúng được vẽ và làm thế nào để game tương tác trở lại với keypad Để làm được điều này, chúng ta phải sử dụng các class giao diện low-level Các class thuộc nhóm low-level cho phép bạn kiểm soát chi tiết các phần tử và sự kiện trên màn hình game.Sử dụng các class này, bạn có thể xác định rõ vị trí, màu sắc và kích thước.Cũng chính vì vậy, bạn phải thiết kế màn hình game screen cho mỗi loại màn hình ứng với mỗi thiết bị

Diagram sau cho biết các lớp chính trong giao diện low-level :

Trang 11

Với entry point là lớp Canvas, nó cho phép bạn truy cập các sự kiện của hệ thống:

keyPressed(), keyReleased(), keyRepeated() thông báo tới Canvas khi keypad được sử

dụng

pointerPressed(), pointerDragged(), pointerReleased() thông báo tới Canvas khi

pointer được sử dụng, đây là các phương thức xử lý trong các màn hình cảm ứng

paint() thông báo đến Canvas khi nó cần vẽ lên màn hình, phương thức này dùng để truy

cập vào đối tượng Graphics

getWidth(), getHeight() truy cập vào kích thước hiện tại của màn hình được vẽ.

Lớp Graphics cung cấp các phương thức để vẽ trực tiếp lên màn hình:

drawLine() vẽ đường thẳng.

drawRect(), fillRect() vẽ hay đổ màu một rectangle lên màn hình.

drawArc() vẽ một cung(arc) lên màn hình, có thể dùng nó để vẽ đường tròn.

drawChar() vẽ một ký tự lên màn hình.

drawString() vẽ một chuỗi lên màn hình.

drawImage() vẽ một bitmap image lên màn hình

setFont() thiết lập Font chữ.

setColor() thiết lập màu.

Ngoài ra trong MIDP 2.0 còn nhiều phương thức khác, bạn tự tìm hiểu thêm

Để tạo Game Screen, bạn phải tạo một lớp extends từ lớp Canvas và cài đặt phương thức paint()

Trang 12

g.fillRect(0, 0, width, height);

// draw a red circle that represents a ball

gameCanvas = new MyCanvas();

// add a back Command to return to the menu screen

Trang 13

game, đoạn code sẽ vẽ hay vẽ lại các phần tử trên game Các giá trị của biến có thể được thay đổi bởi các tương tác của người dùng hay các hành vi của game bên trong.

Điều này được tạo ra bằng cách đặt đoạn code đó lặp đi lặp lại trong một vòng lặp liên tục Trước khi vào vòng lặp, một biến có thể sẽ được kiểm tra xem game còn chạy hay không Nếu không, vòng lặp có thể được thoát Các đoạn code trong vòng lặp nên cho phép thread thực thi hiện hành sleep vài giây để điều khiển tốc độ(rate) mỗi khi trạng thái game được cập nhật(đó là sau bao lâu thì màn hình game được refresh) Code có dạng sau:

publicclass MyCanvas extends GameCanvas implementsRunnable{

bị flick và các chuyển động mượt mà hơn

Trang 14

 Lưu trữ trạng thái phím trong một mảng: Thông qua phương thức getKeyStates(), bạn có thể truy cập vào một mảng bit tương ứng với trạng thái của mỗi phím sử dụng các giá trị hằng(constant) được định nghĩa trong Canvas.

Bên cạnh sử dụng GameCanvas, bạn cần sử dụng một Thread để giữ các chuyển động trong game độc lập với các event của MIDlet Bằng cách này, các animation sẽ không cần chờ các event của hệ thống vẽ lại chính nó Trong ví dụ này, game có 3 thực thể:

Pad: là một hình chữ nhật nhỏ di chuyển từ trái sang phải nằm phái dưới màn hình.

Ball: nằm trước Pad, khi bạn nhấn phím Fire, nó sẽ di chuyển với tốc độ theo chiều dọc

ngang của Pad

Brick: các khối tĩnh nằm phía trên màn hình, khi chúng trúng Ball thì chúng sẽ biến mất.

Mục đích của game là làm cho các Brick biến mất càng nhanh càng tốt, và không để cho Ball chạy ra khỏi phía dưới của màn hình Game cần theo dõi 3 biến:

 Điểm số của người chơi Người chơi sẽ nhận được 10 điểm mỗi lần làm một Brick biến mất

 Số lượt chơi: mỗi lần Ball chạy ra khỏi phía dưới màn hình, người chơi mất một lượt

 Thời gian chơi game: người chơi phải hoàn tất game trong khoảng thời gian cho phép haygiới hạn

Lớp Entity là supeclass của 3 thực thể trên, gồm có các thuộc tính và chức năng sau:

 x, y: Xác định vị trí hiện tại của thực thể

 speedX, speedY: Xác định tốc độ của thực thể

 width, height: Xác định kích thước của thực thể

 update(): Xác định hành vi của các thực thể

 paint(): phương thức được lớp Graphics sử dụng để vẽ các thực thể

 collided(): Kiểm tra va chạm giữa các thực thể

Tiếp theo, mở rộng lớp Entity cho mỗi phần tử game và cài đặt phương thức update() và paint() Đối với Ball:

publicclass Ball extendsEntity {

Trang 15

Đối với Pad:

publicclass Pad extendsEntity{

Trang 16

Đối với Brick:

publicclass Brick extendsEntity {

boolean active = true;

public Brick(int color){

Trang 17

// to allow to get out of screen

wallMaxY = getHeight() + 4 * ball.radium;

// create bricks

Brick brick;

bricks = newVector();

for (int i=0; (i*(BRICK_WIDTH+2))<getWidth(); i++){

brick = new Brick(Util.setColor(255,0,0));

Trang 18

for (int i=0; i < bricks.size(); i++){

Brick brick = (Brick)(bricks.elementAt(i));

Game cần tương tác trở lại với các sự kiện keypad để di chuyển pad của người chơi

// update game entities according to use presses on keypad

publicvoid checkUserInput() {

int state = getKeyStates();

if ( (state & GameCanvas.LEFT_PRESSED) > 0) {

Trang 19

Phát triển game đơn giãn trên Mobile(P4)

Trong bài trước, lớp GameCanvas được xây dựng với tất cả các tương tác giữa các element chính Bây giờ, tất cả các element gameplay được xây dựng, đây là lúc cải thiện giao diện trực quan của trò chơi bằng cách sử dụng các tập tin hình ảnh thay vì sử dụng phương thức draw/fill trên đối tượng graphics để biểu diễn các thực thể trò chơi Tôi đã tạo ra một số hình ảnh dựa trên các tài nguyên SpriteLib sẽ được sử dụng trong trò chơi

Image

Để truy cập và hiển thị các hình ảnh trong MIDlet, ta phải sử dụng một phần tử hay lớp Image trong giao diện người dùng cấp thấp Lớp này lưu trữ dữ liệu hình ảnh đồ họa độc lập với thiết bịhiển thị trong một bộ nhớ đệm off-screen Các hình ảnh hoặc ở dạng Mutable hay Immutable phụthuộc vào cách mà chúng được tạo ra Thông thường, các hình ảnh dạng Immutable được ta ra thông qua việc load hình ảnh từ tài nguyên như file Jar hay mạng Các hình ảnh dạng Immutable được tạo ra thông qua việc sử dụng phương thức tĩnh createImage() của lớp Image Tuy nhiên, một khi ảnh Immutable đã được tạo ra thì nó không thể được sửa đổi Các hình ảnh dạng

Mutable được tạo ra thông qua phương thức khởi dựng(Constructor) của lớp Image và lúc đó nó chỉ chứa các pixel trắng Ứng dụng có thể biểu diễn image Mutable bằng cách gọi phương thức getGraphics() trên Image để có được đối tượng Graphics cho mục đích này

Trong game này, các hình ảnh Immutable đại diện cho các thực thể game Bây giờ, ta hãy thay đổi lớp Pad và tạo ra đối tượng Image trong constructor của nó

Trang 20

Tiếp theo, ta sửa đổi lớp Ball như sau:

nó còn một hỗ trợ một lớp Sprite để ta làm điều này

Sprite

Một Sprite là một thuật ngữ chung trong game Nó tham chiếu đến một phần tử trực quan được tạo ra bởi các Image, thường chuyển động và di chuyển xung quanh các phần tử khác một cách độc lập trong game.Lớp Sprite trong MIDP 2.0 đại diện cho khái niệm này.Nó cho phép tạo ra các Sprite dựa trên các hình ảnh với nhiều frame.Nó có thể thay đổi frame, điều khiển chuyển động và kiểm tra va chạm với các phần tử khác

Ngày đăng: 21/08/2015, 13:01

HÌNH ẢNH LIÊN QUAN

Hình dưới đây cho biết nhiều trạng thái khác nhau và có thể chuyển tiếp giữa chúng: - Phát triển game đơn giãn trên máy tính nhanh nhất
Hình d ưới đây cho biết nhiều trạng thái khác nhau và có thể chuyển tiếp giữa chúng: (Trang 31)

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w