Pham_loi
Chức vụ: 02:19:03, 27-05-2016 |
J2ME là một nền tảng phổ biến cho cho việc phát triển game cho các thiết bị không dây. Trong bài học này, tôi sẽ giới thiệu cho bạn gói Game API và giúp bạn phát triển một game đơn giản có sử dụng tất cả các lớp thuộc gói này như là một công cụ học tập. Gói này có tên là javax.microedition.lcdui.game, và nó được xây dựng dựa trên các khái niệm mà bạn đã học.
1.Tổng quan J2ME Game API
Chỉ có 5 class trong gói javax.microedition.lcdui.game: GameCanvas, Layer, Sprite, TiledLayer và LayerManager. 5 class này đủ để cung cấp một nền tảng hoàn hảo cho việc phát triển các trò chơi.
Lớp Layer là superclass của lớp Sprite và TiledLayer. Lớp Layer trừu tượng hành vi của một thành phần trực quan trong một game. Thành phần này có thể là một sprite – thể hiện một đồ họa độc lập (hay một tập hợp các hoạt hình) có thể di chuyển được quanh màn hình game, hay một tiled layer – thể hiện một đồ họa có thể được dùng để tạo ra nền game rộng chỉ với một ít image. Bạn sử dụng các lớp Layer cho việc định vị và khả năng nhìn thấy các đối tượng. Các subclass ghi đè phương thức paint(Graphics g) có nhiệm vụ render các thành phần lên màn hình.
Lớp LayerManager cung cấp một cơ chế tiện lợi cho quản lý nhiều thành phần trực quan của một game (các sprite và tiled layer) bằng cách render lớp thích hợp theo đúng trình tự thích hợp.
Lớp GameCanvas được tạo ra một cách hữu ích bằng cách mở rộng chức năng lớp Canvas. Lớp GameCanvas cung cấp một bộ đệm off-screen, để cho mọi thao tác render được thực hiện trước khi đẩy chúng lên màn hình thiết bị. Lớp GameCanvas cũng cung cấp. Nó cũng cung cấp một cơ chế dễ dùng để truy vấn các phím key hiện hành đang được nhấn bởi người dùng.
Cách tốt nhất để giới thiệu cho bạn những class này là đưa ra môt ví dụ, từ đó ta sẽ hiểu dần dần được mọi khía cạnh của một game.
2.Hướng dẫn vỡ lòng đầu tiên khi xây dựng Game
Một game hay hoạt hình được xây dựng dựa theo nguyên lý việc thực thi có tính chất lặp lại một đoạn mã. Đoạn mã này theo dõi giá trị các biến thể hiện và cập nhật trạng thái game một cách phù hợp. Dựa trên trạng thái game, đoạn mã sau đó draw/paint/repaint màn hình game với các thành phần tạo nên game. Giá trị các biến thể hiện có thể thay đổi bởi vì do tương tác của người dùng hoặc do hành vi bên trong của game.
Việc thực thi có tính lặp lại được tác động bằng cách đặt đoạn mã lặp trong một vòng lặp vô tận. Trước khi vào vòng lặp, một biến thể hiện có thể được kiểm tra kỹ lưỡng nếu game vẫn đang chạy, còn nếu không, vòng lặp có thể bị đẩy ra. Đoạn mã trong vòng lặp sẽ cho phép thread việc thực thi hiện hành ngủ đi một vài giây để kiểm soát tốc độ lúc cập nhật cho các biến thể hiện đã được thực hiện (thực vậy, game screen nhanh như thế nào tùy thuộc vào cách làm tươi).
Trong đoạn mã của bạn phải tuân theo một số điều kiện:
Ta sẽ sử dụng cấu trúc này để phát triển game trong các mục sau. 3.Xây dựng một J2ME Game: Bắt đầu với GameCanvas Một lớp GameCanvas là một subclass chuyên biệt hóa của lớp Canvas mà bạn đã biết trong bài trước. GameCanvas được tối ưu cho làm game bởi vì nó cung cấp một bộ đệm off-screen đặc biệt phục vụ mọi thao tác vẽ. Khi mọi công tác vẽ trên bộ đệm này hoàn thành, bộ đệm được render trên màn hình thiết bị bằng cách gọi phương thức flushGraphics(). Việc làm đệm kép này tận dụng lợi thế của việc đem lại các chuyển tiếp mượt mà của các thành phần chuyển động trên màn hình. Kích thước của bộ đệm bằng với kích thước của màn hình thiết bị, và chỉ có một bộ đệm trên mỗi thể hiện GameCanvas. Lớp GameCanvas cung cấp một cơ chế lưu trữ trạng thái các phím game, đó là một phương pháp có ích để lấy vế tương tác người dùng trong game. Cơ chế này cung cấp một cách đơn giản để theo dõi số lần người dùng đã nhấn một phím cụ thể nào đó. Việc gọi phương thức getKeyStates() trả về một dãy bit thể hiện tất cả các phím game vật lý, cụ thể là 1 cho các phím đã nhấn và 0 là cho các phím chưa được nhấn từ lần cuối cùng phương thức này được gọi. Chỉ những trạng thái game sau là được nhận diện, và được định nghĩa bởi lớp Canvas: DOWN_PRESSED, UP_PRESSED, RIGHT_PRESSED, LEFT_PRESSED, FIRE_PRESSED, GAME_A_PRESSED, GAME_B_PRESSED, GAME_C_PRESSED, và GAME_D_PRESSED. Hãy cùng tạo một game bằng cách kế thừa lớp GameCanvas. Code 1 cho thấy nỗ lực đầu tiên này, còn Code 2 cho thấy MIDlet sẽ được sử dụng để chạy các ví dụ. Code 1 – MyGameCanvas: Xây dựng một game canvas Code 2 cho thấy MIDlet sẽ sử dụng game canvas này: Code 2 – Lớp MIDlet thử nghiệm Sử dụng cả hai lớp này, tạo ra một dự án với Toolkit của bạn và sau đó build và chạy ứng dụng. Bạn sẽ cần file ảnh này: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-couple.gif?w=630[/img, tên là couple.gif, trong thư mục res của MIDlet, hoặc bạn có thể sử dụng một ảnh có kích thước tương tự. Hình 1 cho thấy kết xuất mong muốn. [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h1.gif?w=630[/img Hình 1 – Sử dụng GameCanvas Hình ảnh ở giữa màn hình có thể được di chuyển qua trái hay phải bằng các phím game trái phải tương ứng. Trong đoạn mã Code 1, điều này có thể thực hiện được bằng cách truy vấn trạng thái game trong phương thức checkUserInput)[ với trạng thái game này. Như bạn có thể thấy, theo phép so sánh bit OR trạng thái với các hằng được cung cấp trong lớp GameCanvas, bạn có thể dễ dàng quyết định người dùng đã nhấn phím nào và hành động tương ứng. Vị trí tọa độ x của ảnh được di chuyển qua trái hay phải vị trí hiện hành bằng cách cộng thêm hay trừ đi delta x dx[ từ vị trí hiện hành. Ảnh được render lên màn hình trong phương thức [bupdateGameScreen)[ và sau đó đẩy bộ đệm này lên màn hình thiết bị. Vòng lặp vô hạn trong phương thức [brun() theo cấu trúc game tôi đã mô tả ở trên. Vòng lặp này ngủ 30ms trước khi vào vòng lặp khác nhằm xác định user input và làm tươi bộ đệm. Bạn có thể thử nghiệm giá trị này làm chậm hay tăng tốc tỉ lệ làm tươi. Cuối cùng, chú ý rằng phương thức dựng MyGameCanvas gọi bộ dựng của lớp con GameCanvas với một giá trị tham số là true. Điều này cho biết rằng cơ chế sự kiện phím thông thường, được kế thừa từ lớp Canvas, sẽ bị chặn, vì mã này không yêu cầu các thông báo. Trạng thái được xử lý một cách thỏa đáng bởi thông tin trạng thái phím, được lấy về từ phương thức getKeyStates(). Bằng cách khử cơ chế thông báo cho “phím đã ấn”, “phím đã nhả ra”, và “phím lặp lại”, hiệu suất game được cải thiện. 4.Định rõ các đặc điểm của game Những gì bạn làm trong một game là phải di chuyển nhân vật chính cứ qua trái hay phải thì chả có gì là thú vị cả. Hãy thay đổi một vài thứ trong thân phát triển game trong Code 1 để cải thiện game tốt hơn một chút. Để bắt đầu, hãy chỉ rõ một giới hạn trong game của bạn. Đó là yếu tố cần thiết để thực hiện, bởi vì nó làm cho game của bạn có kích thước phù hợp qua các thiết bị khác nhau. Để làm điều này, bắt đầu bằng việc định nghĩa một số hằng như trong đoạn mã sau: (Chú ý rằng tôi đã giới thiệu một đặc điểm game cho biết hai nhân vật người có thể nhảy trên màn hình, với hỗ trợ của hằng MAX_HEIGHT). Trên màn hình, những hằng này giúp định nghĩa các giới hạn của game và các thành phần duy nhất của nó (hai nhân vật người), như minh họa trong hình sau: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h2.gif?w=630[/img Hình 2 – Định nghĩa các ranh giới bằng cách sử dụng các hằng game Dĩ nhiên, bây giờ bạn cần thay đổi phần còn lại của code để sử dụng được những hằng này. Thêm một phương thức mới vào Code 1 tên là buildGameScreen(Graphics g), như sau: Ta cũng thêm một lời gọi đến phương thức này trong phương thức updateGameScreen)[ bằng cách thiết lập coupleY=BASE;. Ảnh hai nhân vật người có thể di chuyển qua trái hay phải với các phím game trái hay phải, nhưng bây giờ chúng ta phải đảm bảo rằng không di chuyển qua ranh giới game. Đây là một vấn đề tồn tại trong Code 1, nhưng trong trường hợp đó, đơn giản là hình ảnh biến mất khỏi màn hình, và ranh giới là cạnh của màn hình. Có vẻ rất là kỳ cục nếu ảnh đi qua các ranh giới. Do đó, việc thay đổi các hành động nhấn phím trái và phải trong phương thức calculateCoupleX() giới hạn việc di chuyển quá các ranh giới. Phương thức được thay đổi như sau: Bây giờ phương thức này sử dụng các phương thức Math.max)[ để giới hạn ảnh hai nhân vật người trong phạm vi các ranh giới game. Chú ý rằng việc đó cũng kết hợp chặt chẽ với độ rộng của ảnh trong các tính toán này. Như đã nói trước đây về việc làm cho ảnh hai nhân vật người nhảy quanh màn hình. Hãy xem cách thực hiện việc này bằng cách thêm một phương thức để di chuyển ảnh theo trục Y, một cách độc lập với người chơi game. Thêm 3 biến thể hiện mới vào Code 1, gọi là up, jumpHeight, và random, như sau: Như bạn có thể thấy, jumpHeight được khởi tạo là MAX_HEIGHT. Biến jumpHeight sẽ được tính toán cho mỗi lần nhảy của hai nhân vật người đó và nó sẽ được thiết lập là một giát trị ngẫu nhiên mỗi lúc. Điều này được thể hiện trong phương thức calculateCoupleY() sau đây: Chú ý rằng vì phương thức này không phụ thuộc vào việc người dùng nhấn các phím lên hay xuống, nó không sử dụng thông tin keyState. Nhưng dù sao giá trị này đã được chuyển cho nó, để duy trì sự phù hợp với phương thức calculateCoupleX)[. Một khi phương thức chạm tới độ cao bước nhảy này, nó bắt đầu di chuyển hướng ngược lại cho đến khi nó chạm tới [bBASE. Tại vị trí này, một giá trị độ cao bước nhảy mới, giữa MAX_HEIGHT và độ cao ảnh hai nhân vật người, được tính toán một cách ngẫu nhiên và hai nhân vật người lại tiếp tục nhảy. Toàn bộ tác động có thể được thực hiện bằng cách ấn phím trái hay phải từ phía người dùng. Một snapshot minh họa: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h3.gif?w=630[/img Hình 3 – Một game snapshot 5.Xây dựng một J2ME Game: Tạo các nền sau sử dụng lớp TiledLayer Trong mục này, bạn sẽ thêm một số màu sắc vào game bằng cách tạo ra một nền sau (background) sử dụng lớp TiledLayer. Game được chia ra thành 3 phần: phần đầu có thể tưởng tượng là bầu trời, phần giữa là hình hai nhân vật người nhảy trên mặt đất, và phần dưới là biển. Ba phần này có thể được thiết kế dễ dàng bằng việc sử dụng 3 ảnh kích thước 32×32 pixel, mỗi ảnh cho mỗi phần. Tuy nhiên, mỗi vùng thường lớn hơn 32×32 pixel, và lớp TiledLayer được dùng để định nghĩa các vùng rộng như thế với các bức ảnh nhỏ. Để bắt đầu, chia màn hình game thành các ô vuông 32×32 px và đánh số các hàng và cột, bắt đầu từ chỉ số index là 0. Hình sau cho thấy một nền sau 5×5 ô: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h4.gif?w=630[/img Hình 4 – Chia màn hình game thành các ô riêng biệt Vì vậy, các ô (0, 0) đến (1, 4) được vẽ bằng ảnh bầu trời; các ô (2, 0) đến (2, 4) vẽ mặt đất, và các ô (3, 0) đến (4, 4) vẽ biển. Bạn sẽ làm việc này với các ảnh sau: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h5.gif?w=630[/img Hình 5 – Các ảnh nền sau Ô 32×32 px đầu tiên thể hiện ảnh mặt đất, ô thứ hai thể hiện biển, và ô thứ 3 thể hiện bầu trời. Khi bạn sử dụng lớp TiledLayer, ba ảnh được đánh số từ index 1 (không phải 0; vì thế, mặt đất là 1, biển là 2, và bầu trời là 3). Lớp TiledLayer sẽ sử dụng một bức ảnh này và chia nó ra thành 3 ảnh riêng biệt dùng cho việc render nền sau của game. Trong trường hợp của chúng ta, ta muốn TiledLayer render một ô nền sau 5×5 bằng việc sử dụng các ô 32×32 px. Ta làm điều đó như sau: Như bạn có thể thấy, hai tham số đầu tiên cho phương thức dựng TiledLayer thể hiện kích thước tổng của nền sau, tham số tiếp theo là ảnh bạn dùng để cắt, và hai tham số cuối cùng thể hiện kích thước cho mỗi ô. Kích thước này sẽ được sử dụng bởi lớp TiledLayer để cắt ảnh thành các ô nền sau độc lập. Việc còn lại bây giờ là đặt vào mỗi ô với ảnh tương ứng của nó. Mã thực hiện tạo nền sau được cho bên dưới trong một phương thức tên là createBackground)[ thuộc lớp MyGameCanvas. Một khi thực hiện xong, thêm một lời gọi để vẽ background này sử dụng background.paint(g) ở cuối phương thức buildGameScreen(). Kết quả cuối cùng như sau: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h6.gif?w=630[/img Hình 6 – Game với background đã được thêm vào 6.Xây dựng một J2ME Game: Sprite và lớp LayerManager Cho đến lúc này tôi đã sử dụng một ảnh hình hai nhân vật người để cho bạn thấy một thành phần điển hình của game. Thành phần này được render hiện hành như là một ảnh; nhưng ta có cảm giác như nó được render ra một hình sprite. Một sprite là một thuật ngữ theo cách nói của game nói đến bất kỳ thành phần trực quan nào, thường là một ảnh hoạt hình, có thể được di chuyển quanh màn hình một cách độc lập với các thành phần khác. Lớp Sprite được dùng để thể hiện các sprite trên các game MIDP 2.0 API. Lớp này cung cấp các phương thức để làm hoạt hình sprite dựa trên một số ảnh, tương tự với cách các background được tạo ra khi sử dụng lớp TiledLayer. Quan trọng hơn, nó cung cấp các phương thức kiểm tra các va chạm với các thành phần game khác, bao gồm các ảnh, các sprite hay các lớp tiledlayer. Hãy cùng bắt đầu bằng cách chuyển đổi đoạn mã có ảnh hình hai nhân vật người có sẵn thành một sprite. Để thấy được hoạt hình, tôi sẽ sử dụng ảnh trong Hình 7, là ảnh hai nhân vật người được sao chép với một màu khác thành 2 frame khác nhau, mỗi frame 10×10 px. [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h7.gif?w=630[/img Hình 7 – Các frame cho hoạt hình Sprite Tương tự với lớp TiledLayer, lớp Sprite yêu cầu kích thước cho mỗi frame, được chuyển vào phương thức khởi tạo của nó: Đoạn mã này được thêm vào sau đoạn mã tạo ra ảnh hai nhân vật người, tạo ra một sprite hai nhân vật người với 2 frame 10x10px, được đánh số từ 0. Vì vậy, để luân phiên giữa các ảnh sprite, bạn có thể gọi phương thức nextFrame)[. Trong trường hợp này, thêm coupleSprite.nextFrame)[. Bây giờ bạn không muốn ảnh hai nhân vật người được vẽ ra trên màn hình. Trước khi sprite hai nhân vật người có thể được vẽ ra trên màn hình, bạn cần định nghĩa một điểm pixel tham chiếu đến nó. Hãy nghĩ rằng đó là một điểm bắt đầu – điểm gốc, mà mọi thao tác vẽ được thực hiện. Theo mặc định, sprite được vẽ ra có góc trên bên trái đóng vai trò là điểm bắt đầu của nó. Tương tự với cách bạn thiết lập tham chiếu đến ảnh hai nhân vật người khi sử dụng mã Graphics.HCENTER | Graphics.BOTTOM, bạn cần định nghĩa một điểm pixel tham chiếu cho sprite, như sau: Thêm dòng mã này vào sau mã tạo ra sprite như đã nói ở trước. Bây giờ, thay vì định vị sprite dựa trên điểm gốc, bạn sẽ định vị nó dựa trên pixel tham chiếu này, như sau: Dòng cuối cùng của đoạn mã trên vẽ ra sprite trên đối tượng đồ họa được chuyển cho nó g[. Như mong đợi, bạn sẽ cần chèn hai dòng mã này vào phương thức [bupdateGameScreen() thay thế vào dòng mã vẽ hình hai nhân vật người. Kết quả cuối cùng sẽ gần giống với kết quả trước, ngoại trừ hai nhân vật người nhảy trên màn hình sẽ được thay thế với hai nhân vật người nhấp nháy lung linh! Trước khi tiếp tục, hãy đảm bảo rằng tất cả những thay đổi của bạn cho biến coupleImg vào coupleSprite trong các phương thức calculateX)[. Quản lý các Layer sử dụng lớp LayerManager Nhớ lại cả hai lớp Sprite và TiledLayer kế thừa từ lớp Layer. Một lớp chỉ có thể chứa ít nhất một lớp TiledLayer và vài lớp Sprite. Khi có quá nhiều layer để kiểm soát, lớp LayerManager xuất hiện lúc cần thiết. Lớp này cung cấp các phương thức thêm, xóa, hay chèn các layer trong một game, và cũng cung cấp một phương thức đơn để vẽ tất cả những layer này vào đối tượng Graphics bên dưới. Điều này có nghĩa là bạn không cần gọi phương thức paint() một cách độc lập cho mỗi layer của một game. Một thể hiện của lớp LayerManager được tạo ra sử dụng bộ khởi tạo không đối số của nó. Các layer sau đó được thêm vào, loại bỏ đi, hoặc chèn vào bằng các sử dụng phương thức append(Layer layer), remove(Layer layer), và insert(Layer layer, int index). Thứ tự mà các layer được thêm vào rất quan trọng, bởi vì thứ tự này quyết định layer nào được vẽ ra đầu tiên, và thứ tự này theo thứ tự trục z-order. Layer ở index 0 được vẽ ra trên hết các layer khác, và từ đó, layer này là nằm gần người dùng nhất, và cứ tiếp tục như thế. Trong game của chúng ta, phương thức start() bây giờ cần được thay đổi, như sau: Như bạn có thể thấy, coupleSprite sẽ là layer gần người dùng nhất và layer background sẽ là layer xa người dùng nhất, dựa theo chỉ số của chúng. Phương thức buildGameScreen)[, và vì thế dòng lệnh [bbackground.paint(g) cần được loại bỏ từ phương thức này. Cuối cùng, như trong mục trước, bạn đã dùng coupleSprite để vẽ ra màn hình thay vì coupleImage. Bây giờ dù điều đó không được yêu cầu, vì LayerManager sẽ làm điều đó cho bạn. Loại bỏ coupleSprite.paint(g) ra khỏi phương thức updateGameScreen)[. Như bạn có thể thấy, tất cả các lời gọi đến các phương thức paint)[ của LayerManager. Hai tham số cuối cùng thể hiện vị trí mà manage sẽ vẽ. Khi đó background và carSprite chịu trách nhiệm cho vị trí của riêng chúng, bạn có thể bỏ qua những tham số này nếu có (tức là, vẽ từ vị trí gốc thiết bị). Code 3 cho thấy phương thức updateGameScreen() đã được sửa lại. Các dòng bị loại bỏ vẫn được giữ lại trong các comment để dễ dàng nhận thấy các thay đổi: Code 3 – Cập nhật lại phương thức updateGameScreen() 7.Thêm nhiều Sprite hơn nữa và nhận diện va chạm Một sprite mà chỉ có nhảy qua nhảy lại thì đâu có vui phải không các bạn? Đã đến lúc thêm một sprite khác, ví dụ như là một chiếc xe xuất hiện vài nơi trên màn hình. Hai nhân vật người cần va chạm vào chiếc xe này! Càng nhiều xe bị hai người này chạm vào từng lượt, điểm số càng cao hơn. Với các mục tiêu game đã rõ ràng, trước tiên hãy tạo một class sẽ theo dõi thời gian để game có thể dừng lại một khi hết thời gian. Code 4 cho thấy mã cho lớp Clock: Code 4 – Lớp Clock sẽ theo dõi thời gian game Lớp Clock kế thừa lớp TimerTask, có phương thức run() được thực hiện sau mỗi khoảng thời gian định trước. Ở đây, phương thức này giảm bớt biến maxTime qua mỗi giây đồng hồ, nhằm giúp chúng ta theo dõi thời gian. Để sử dụng lớp Clock, tạo ra và khởi động nó trước vòng lặp vô tận bên trong phương thức run() của lớp MyGameCanvas khi được thực thi, như sau: Dĩ nhiên, bây giờ vòng lặp vô tận phải được kiểm soát với một flag nhằm dừng vòng lặp khi đang chạy khi hết thời gian. Để làm điều này, định nghĩa một flag có tên là stop, như dưới đây: Đưa nó vào vòng lặp while với while(!stop) và nhập các dòng mã đầu tiên trong phương thức verifyGameState(): Cuối cùng, người dùng cần được biết thời gian còn lại trong game. Để làm điều này, thêm một phương thức tên là showTimeLeft(Graphics g) như dưới đây: Phương thức này được gọi ở cuối phương thức buildGameSreen(). Hình 8 cho thấy một snapshot của game: [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h8.gif?w=630[/img Hình 8 – Game có thông báo thời gian còn lại Giờ là lúc thêm một vài sprite mới vào trong game. Code 5 là đoạn mã cho chiếc xe trong một class tên là CarSprite. Đoạn mã này sử dụng bức ảnh một chiếc xe trong hình 9. [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h9.gif?w=630[/img Hình 9 – Hình ảnh một car sprite Code 5 – Đoạn mã tạo thêm vài car sprite Lớp CarSprite cài đặt giao diện Runnable, để sinh ra vài car sprite mới cứ mỗi nửa giây. Phương thức run)[ sau khi chờ 500ms. Phương thức randomCar() kiểm tra nếu số car sprite đang có không được vượt quá giới hạn, sau đó tạo ra một sprite mới sử dụng hình ảnh được nạp lên trước đó. Sau đó nó tính toán một vị trí ngẫu nhiên cho sprite này xuất hiện, và đảm bảo rằng vị trí ngẫu nhiên này ở trong phạm vi của game. Nó còn thiết lập sprite vào LayerManager ở mức index là 0, vì thế làm cho sprite đó gần với người dùng nhất. Lớp này cũng cung cấp một phương thức để kiểm tra va chạm của hai nhân vật người với các chiếc xe ngẫu nhiên. Phương thức checkForCollision)[ trong lớp Sprite để kiểm tra va chạm. Phương thức này trả về true khi va chạm xảy ra, và chấp nhận một layer, một hình ảnh, hoặc một thứ khác khi có va chạm. Phương thức này cũng chấp nhận một flag cho biết nếu có nhận ra va chạm thì sẽ chú ý tới các pixel trong suốt quanh một hình ảnh, hay chỉ cho các pixel mờ. Khi một va chạm được nhận diện, số car bị chạm vào được tăng lên và số car thấy bị giảm đi. Để sử dụng lớp CarSprite, chèn các dòng mã sau vào cuối phương thức start() trong lớp MyGameCanvas. Và cũng thêm dòng mã sau vào cuối phương thức verifyGameState(): Như thế, thread CarSprite bắt đầu đẻ ra nhiều car mới, với tối đa là MAX_CARS chiếc xe. Một khi người dùng chạm vào một chiếc xe bằng cách di chuyển hai nhân vật người đến chiếc xe đó, thì chiếc xe biến mất. Điều này được kiểm tra trong phương thức verifyGameState)[ trên thread CarSprite. Nhiều chiếc xe hơn vẫn cứ xuất hiện trong khi thời gian hết dần. Hình 10 cho thấy một game đang trong quá trình như vậy. [imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h10.gif?w=630[/img Hình 10 – Một game điển hình đang chạy sau khi thêm một số sprite Những gì còn lại bây giờ là thông báo cho người dùng số chiếc xe mà họ đã phá được. Sau khi vòng lặp while() thoát ra, thêm một lời gọi vào một phương thức mới tên là showGameScore(getGraphics()) như dưới đây:
Phương thức này vẽ một hình chữ nhật nhỏ ở giữa màn hình lúc kết thúc game, hiện ra số xe đã bị phá bởi người chơi. Một game điển hình kết thúc như sau:
[imghttps://huetoday.files.wordpress.com/2010/05/j2me-s1-b3-h11.gif?w=630[/img
Hình 11 – Một kết thúc điển hình và thông điệp hiển thị cuối cùng
Dĩ nhiên bạn có thể hiển thị thông tin này theo định dạng và vị trí bất kỳ mà bạn muốn.
8.Kết luận
Tuy bài 3 này hơi dài, nhưng bạn đã học được cách sử dụng các lớp MIDP 2.0 API với một ví dụ tương đối tổng quan nhất và game đã chạy thành công. Bạn cũng học được những cơ bản về quá trình xây dựng game qua ví dụ đó.
Trong phần tiếp theo của series này, bạn sẽ học cách thêm multimedia vào MIDlet của bạn,thậm chí một số thứ có thể hữu ích trong J2ME game. Bạn cũng sẽ được học cách sử dụng record-store management API để lưu trữ thông tin vào thiết bị.
Dịch từ today.java.net
: 0 ♥
Trực Tuyến:
Khách: 1