III.Phát triển Game sử dụng Game API

Giả sử chúng ta phát triển một game đơn giản bằng cách sử dụng Game API. Và ta có thể phát triển một màn hình trò chơi mà nhân vật di chuyển theo chiều ngang tức là dọc theo trục x từ một điểm đến điểm cuối của màn hình. Để tránh va chạm, nhân vật cần nhảy qua các trở ngại trở ngại. Bạn có thể download code của nó vào cuối bài.

1.Bắt đầu với GameCanvas

Phát triển game trong JavaME xoay quanh:

  • Lưu vết và cập nhật trạng thái game.
  • Vẽ, hay vẽ lại màn hình game dựa trên trạng thái game.
  • Nhận dữ liệu đầu vào thông qua các sự kiện keyPressed, keyRealeased.
  • Số lượng các thread.

Tất cả các giai đoạn rất quan trọng để phát triển. Với 1,0 MIDP, trên 3 bước được thực hiện bởi chủ đề khác nhau.

Ví dụ dưới đây mô tả cấu trúc game MIDP 1.0:

public class MyCanvas extends Canvas implements Runnable {

public void run() {

while (true) {

/*Game Thread

*Update the game state.  Painting*/

repaint();

// Thread sleep delay

}

}

public void paint(Graphics g) {

/*your game painting code*/

}

protected void keyPressed(int keyCode) {

/*System Calls response to keyPressed*/

}

}

Vấn đề với game trong MIDP 1.0, đó là tất cả mọi thứ đều được lan truyền trên các phương thức khác nhau. Cụ thể là:

  • Không có cách để biết khi nào hệ thống sẽ gọi paint ().
  • Không có cách để biết khi hệ thống gọi các sự kiện keypressed, phương thức paint() sẽ biểu diễn màn hình dựa trên các yếu tố đầu vào mới nhất.
  • Chuyển động trông như kerky.
  • Vấn đề nhấp nháy.

GameCanvas giải quyết việc xử lý việc vẽ lại màn hình và các sự kiện phím bằng cách thực hiện logic trò chơi trong vòng lặp. Bằng cách đó, nó cung cấp:

  • Bộ đệm đôi(Double Buffering).
  • Truy vấn trạng thái phím.

Cấu trúc game MIDP 2.0 được biểu diễn dưới dạng sau:

public class MyGameCanvas extends GameCanvas implements Runnable {
  ...
  public void run() {
    Graphics g = getGraphics();
    while (true) {
      /*your game code updating state*/
      int keyState = getKeyStates();
      /*your key press code */
      /*your Painting code*/
      flushGraphics();
      /*Thread sleep
   }
  }
  ...
}

GameCanvas cung cấp một bộ đệm off-screen mà tất cả các thao tác paint được thực hiện và sau đó bộ đệm này được biểu diễn trên màn hình thiết bị. Đối tượng Graphics thu được thông qua sử dụng phương thức getGraphics(). Bây giờ, bất kỳ việc biểu diễn nào trên đối tượng Graphics đều thực hiện thông qua bộ đệm off-screen.

Việc biểu diễn bộ đệm off-screen trên màn hình được thực hiện thông qua phương thức flushGraphics(). Và chính bộ đệm off-screen khắc phục được vấn đề nhấp nháy và làm cho các chuyển động trong game trơn tru hơn.

GameCanvas còn cung cấp phương thức getKeyStates() để thu được trạng thái phím hiện tại trên thiết bị. Và bạn có thể xác định một cách trực tiếp các phím được nhấn bằng cách sử dụng phương thức getKeyStates().

Cấu trúc GameCanvas được biểu diễn trong ví dụ dưới đây. Và các lớp khác cũng được giới thiệu trong lớp MyGameCanvas.

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import java.io.IOException;

public class MyGameCanvas extends GameCanvas implements Runnable {
    /*character image*/
    private Image charImg;
    /*character coordinates*/
    private int charX;
    private int charY;
    /*character movement along x axis*/
    private final int dx = 1;
    /*screen Boundary*/
    private final int screenWidth = 160;
    private final int screenHeight = 160;
    /*define tile size*/
    Private final int tileSize = 16;
    /*screen refresh value*/
    private final int frameDelay = 30;

    /*MyGameMidlet*/
    private MyGameMidlet midlet;
    /*MyGameThread */
    private Thread myGameThread;

    public MyGameCanvas(MyGameMidlet midlet) { 
        super(true);
        this.midlet = midlet;
        loadCharImg();
        setFullScreenMode(true);
        initialiseNewGame();
        myGameThread = new Thread(this);
        myGameThread.start();
    }

    private void loadCharImg()
    {
        try {
            /* load character image from resource*/
            charImg = Image.createImage("/charImg.png");          
        } catch (IOException ioex) {
            ioex.printStackTrace();
        }
    }

    public void initialiseNewGame() {       
        charX = 0;
        charY = getHeight()-charImg.getHeight();       
    }

    public void run() {
        /* get graphics object for this canvas */
        Graphics g = getGraphics();
        /*infinite loop*/
        while (true) {
            /*Check for user key presses*/
            getUserInput();           
            /*render screen*/
            renderScreen(g);
            /*controls refresh rate*/
            try {
                Thread.sleep(frameDelay);
            } catch (Exception e) {
            }
        }
    }

    private void getUserInput() {
        /*get keys state*/
        int keyState = getKeyStates();
        /*calculate the position for x axis*/
        calculateCharMovement(keyState);
    }

    private void renderScreen(Graphics g) {
        /*clear the background*/
        g.setColor(0xffffff);
        g.fillRect(0, 0, screenWidth, screenHeight);
        /*draw character image*/
        g.drawImage(charImg,charX,charY, Graphics.TOP | Graphics.LEFT);
        /*paint off-screen buffer to screen*/
        flushGraphics();
    }

    private void calculateCharMovement(int keyState) {
        /*check which way to move and change direction*/
        if ((keyState & LEFT_PRESSED) != 0) {
            charX = Math.max(0,charX-dx);
        } else if ((keyState & RIGHT_PRESSED) != 0) {
            charX = Math.min(screenWidth - charImg.getWidth(), charX+dx);
         }
    } 
}

Các bài liên quan:
Game API – Phần 1
Game API – Phần 3
Game API – Phần cuối