サーチ…


前書き

Javaを使用したAndroidプラットフォームでのゲーム作成の簡単な紹介

備考

  • 最初の例は基本をカバーしています。目標はありませんが、SurfaceViewを使用して2Dゲームの基本部分を作成する方法を示しています。
  • ゲームを作成するときは、重要なデータを必ず保存してください。他のすべては失われます

CanvasとSurfaceViewを使用したゲーム

ここでは、SurfaceViewを使用して基本的な2Dゲームを作成する方法について説明します。


まず、活動が必要です。

public class GameLauncher extends AppCompatActivity {

    private Game game;
    @Override
    public void onCreate(Bundle sis){
        super.onCreate(sis);
        game = new Game(GameLauncher.this);//Initialize the game instance
        setContentView(game);//setContentView to the game surfaceview
        //Custom XML files can also be used, and then retrieve the game instance using findViewById.
    }

}

このアクティビティはAndroid Manifestで宣言する必要があります。


今ゲームそのもの。まず、ゲームスレッドを実装することから始めます。

public class Game extends SurfaceView implements SurfaceHolder.Callback, Runnable{

    /**
     * Holds the surface frame
     */
    private SurfaceHolder holder;

    /**
     * Draw thread
     */
    private Thread drawThread;

    /**
     * True when the surface is ready to draw
     */
    private boolean surfaceReady = false;


    /**
     * Drawing thread flag
     */

    private boolean drawingActive = false;

    /**
     * Time per frame for 60 FPS
     */
    private static final int MAX_FRAME_TIME = (int) (1000.0 / 60.0);

    private static final String LOGTAG = "surface";    

    /*
     * All the constructors are overridden to ensure functionality if one of the different constructors are used through an XML file or programmatically
     */
    public Game(Context context) {
        super(context);
        init();
    }
    public Game(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public Game(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    @TargetApi(21)
    public Game(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    public void init(Context c) {
        this.c = c;
        
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        setFocusable(true);
        //Initialize other stuff here later
    }

    public void render(Canvas c){
        //Game rendering here
    }

    public void tick(){
        //Game logic here
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
        if (width == 0 || height == 0){
            return;
        }

        // resize your UI
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder){
        this.holder = holder;

        if (drawThread != null){
            Log.d(LOGTAG, "draw thread still active..");
            drawingActive = false;
            try{
                drawThread.join();
            } catch (InterruptedException e){}
        }

        surfaceReady = true;
        startDrawThread();
        Log.d(LOGTAG, "Created");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder){
        // Surface is not used anymore - stop the drawing thread
        stopDrawThread();
        // and release the surface
        holder.getSurface().release();

        this.holder = null;
        surfaceReady = false;
        Log.d(LOGTAG, "Destroyed");
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        // Handle touch events
        return true;
    }

    /**
     * Stops the drawing thread
     */
    public void stopDrawThread(){
        if (drawThread == null){
            Log.d(LOGTAG, "DrawThread is null");
            return;
        }
        drawingActive = false;
        while (true){
            try{
                Log.d(LOGTAG, "Request last frame");
                drawThread.join(5000);
                break;
            } catch (Exception e) {
                Log.e(LOGTAG, "Could not join with draw thread");
            }
        }
        drawThread = null;
    }

    /**
     * Creates a new draw thread and starts it.
     */
    public void startDrawThread(){
        if (surfaceReady && drawThread == null){
            drawThread = new Thread(this, "Draw thread");
            drawingActive = true;
            drawThread.start();
        }
    }

    @Override
    public void run() {
        Log.d(LOGTAG, "Draw thread started");
        long frameStartTime;
        long frameTime;

        /*
         * In order to work reliable on Nexus 7, we place ~500ms delay at the start of drawing thread
         * (AOSP - Issue 58385)
         */
        if (android.os.Build.BRAND.equalsIgnoreCase("google") && android.os.Build.MANUFACTURER.equalsIgnoreCase("asus") && android.os.Build.MODEL.equalsIgnoreCase("Nexus 7")) {
            Log.w(LOGTAG, "Sleep 500ms (Device: Asus Nexus 7)");
            try {
                Thread.sleep(500);
            } catch (InterruptedException ignored) {}
        }

        while (drawing) {
            if (sf == null) {
                return;
            }

            frameStartTime = System.nanoTime();
            Canvas canvas = sf.lockCanvas();
            if (canvas != null) {
                try {
                    synchronized (sf) {
                        tick();
                        render(canvas);
                    }
                } finally {

                    sf.unlockCanvasAndPost(canvas);
                }
            }

            // calculate the time required to draw the frame in ms
            frameTime = (System.nanoTime() - frameStartTime) / 1000000;

            if (frameTime < MAX_FRAME_TIME){
                try {
                    Thread.sleep(MAX_FRAME_TIME - frameTime);
                } catch (InterruptedException e) {
                    // ignore
                }
            }

        }
        Log.d(LOGTAG, "Draw thread finished");
    }
}

それが基本的な部分です。これで、画面に描画することができます。

さて、整数に追加することから始めましょう:

public final int x = 100;//The reason for this being static will be shown when the game is runnable
public int y;
public int velY;

この次のパートでは、イメージが必要になります。それは約100x100でなければならないが、それは大きくても小さくてもよい。学習のために、Rectも使うことができます(ただし、コードを少し変更する必要があります)

次に、ビットマップを宣言します。

private Bitmap PLAYER_BMP = BitmapFactory.decodeResource(getResources(), R.drawable.my_player_drawable);

レンダリングでは、このビットマップを描画する必要があります。

...
c.drawBitmap(PLAYER_BMP, x, y, null);
...

打ち上げの前にまだいくつかのことがあります

最初にブール値が必要です。

boolean up = false;

onTouchEventでは、以下を追加します:

if(ev.getAction() == MotionEvent.ACTION_DOWN){
    up = true;
}else if(ev.getAction() == MotionEvent.ACTION_UP){
    up = false;
}

また、ティックでは、プレイヤーを移動するためにこれが必要です:

if(up){
    velY -=1;
}
else{
    velY +=1;
}
if(velY >14)velY = 14;
if(velY <-14)velY = -14;
y += velY *2;

これでinitでこれが必要になります:

WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
WIDTH = size.x;
HEIGHT = size.y;
y = HEIGHT/ 2 - PLAYER_BMP.getHeight();

変数には次のものが必要です。

public static int WIDTH, HEIGHT;

この時点で、ゲームは実行可能です。つまり、それを起動してテストすることができます。


今度は、プレーヤーの画像または矩形を画面の上下に移動させる必要があります。必要に応じて、プレーヤーをカスタムクラスとして作成することができます。その後、すべてのプレイヤー関連のものをそのクラスに移動し、そのクラスのインスタンスを使用して、移動、レンダリング、その他のロジックを実行できます。

さて、テストの下で見たように、画面から飛びます。だから我々はそれを制限する必要がある。

まず、Rectを宣言する必要があります。

private Rect screen;

initでは、幅と高さを初期化した後、画面である新しい矩形を作成します。

screen = new Rect(0,0,WIDTH,HEIGHT);

今度は、メソッドの形で別のrectを必要とします:

private Rect getPlayerBound(){
    return new Rect(x, y, x + PLAYER_BMP.getWidth(), y + PLAYER_BMP.getHeight();
}

そしてダニ:

if(!getPlayerBound().intersects(screen){
    gameOver = true;
}

gameOVerの実装は、ゲームの開始を示すためにも使用できます。


注目に値するゲームの他の側面:

保存(ドキュメントには現在ありません)



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow