android – mover bolinha

android move ball

Na minha opinão o hello world para desenvolver jogos eh mover um desenho primitivo na tela junto com a informação de FPS (frames por segundo) até porque logo logo perguntamos : tah rodando a quantos FPS ? :) assim sendo já posso dizer que fiz o meu hello world para o android.

Alguns links que ajudaram bastante foram estes :

Uma apresentação da google sobre o desenvolvimento para de jogos para o Android
Writing-Real-Time-Games-for-Android

Os exemplos de cógigo citados na apresentação
C2B 2 GameView

Com certeza este exemplo que escrevi eh extremamente simples, mas exemplifica alguns elementos básicos :

  • main loop
  • chamada de update
  • atualização da area de vizualização
  • input do usuário

O ambiente que tenho eh o Eclipse com o plugin para desenvolvimento do android instalado, para os testes eu prefiro usar o telefone porque o emulador demora muito para inicializar :) e este exemplo tem basicamento 3 classes :

GameActivity – que eh a entrada da aplicação, nela eu solicito o uso fullscreen para o jogo, e determino que a visualização será realizada por uma instancia da classe GameView.

package com.athanazio.android.moveball2;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class GameActivity extends Activity {
	private GameView view;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);

		view = new GameView(this);
		setContentView(view);
	}

	protected void onPause() {
		super.onPause();
		view.pause();
	}
}

GameView – nesta classe reside o loop principal do jogo que é iniciado no final do construtor, note que na verdade eh criado um Thread com baixa prioridade, que passará a realizar as atividades de atualização e principalmente executar o método postupdate() notficando a interface que pode ser exibida.

além do loop principal o input direcional é tratado pelo método onKeyDown() e o tocar na tela pelo método onTouchEvent()

package com.athanazio.android.moveball2;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

public class GameView extends View implements Runnable {

	private static final String TAG = "GAMEVIEW";

	private static final int INTERVAL = 10;
	private Paint cPaint;

	private float x = 50;

	private float y = 50;

	private boolean running = true;

	FPSCounter fps;

	public GameView(Context context) {
		super(context);
		cPaint = new Paint();
		setFocusable(true);
		setClickable(true);
		setLongClickable(true);

		fps = new FPSCounter();

		// Set the background
		this.setBackgroundColor(Color.WHITE);
		Log.i(TAG, "game view created");

		Thread monitorThread = new Thread(this);
		monitorThread.setPriority(Thread.MIN_PRIORITY);
		monitorThread.start();
	}

	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return super.onKeyUp(keyCode, event);
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		boolean handled = false;
		Log.i(TAG, "key down");

		if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
			y = y - 5;
			handled = true;
		} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
			y = y + 5;
			handled = true;
		} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
			x = x - 5;
			handled = true;
		} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
			x = x + 5;
			handled = true;
		}
		return handled;
	}

	public boolean onTouchEvent(MotionEvent event) {
		x = event.getRawX();
		y = event.getRawY();
		Log.i(TAG, "on touch");

		return super.onTouchEvent(event);
	}

	public void draw(Canvas canvas) {
		super.draw(canvas);

		cPaint.setColor(Color.BLUE);
		canvas.drawCircle(x, y, 15, cPaint);

		cPaint.setColor(Color.BLACK);
		canvas.drawText(fps.getFPS(), 20, 20, cPaint);

	}

	public void run() {
		while (running) {
			try {
				Thread.sleep(INTERVAL);
			} catch (InterruptedException e) {
				Log.e(TAG, "main loop finished");
			}
			update();
			postInvalidate();
		}
	}

	private void update() {
		fps.update();

	}

	public void pause() {
		running = false;
	}

}

FPSCounter – nesta classe é feita uma contagem de frames que o jogo consegue exibir por segundo, vi algumas implementações interessantes disto, mas acabei fazendo o mais simples e mais econômico, contar frames e ver se jah passou o tempo :) note que algumas variáveis eu criei fora dos métodos para evitar que o Garbage collector tivesse que trabalhar, querendo ou não isto economiza alguns milisegundos :)

package com.athanazio.android.moveball2;

import java.text.DecimalFormat;

import android.os.SystemClock;

public class FPSCounter {

	public static final DecimalFormat format = new DecimalFormat("###0.00");

	private float frames;
	private String fps;
	private long start;
	private long current;

	public FPSCounter() {
		start = SystemClock.uptimeMillis();
		frames = 0;
		fps = "???";
	}

	public void update() {
		frames ++;
		current = SystemClock.uptimeMillis();
		if( current - start > 1000 ){
			fps = format.format(frames);
			frames = 0;
			start = current;
		}
	}

	public String getFPS() {
		return fps;
	}
}

a propósito o fps esta em torno de 90 e poucos, vamos ver o que acontece quando tiver de desenhar uma imagem no fundo e varias outras na tela hehehehe.

Leave a Reply