Den Dialog anzeigen lassen & onBackPressed()
Ersteinmal legen wir in unserer GameActivity folgende Variable global an:
private boolean firstStart=true;
private boolean dialogIsActive=false;
Außerdem benötigen wir zwei Methoden in unserer GameView Klasse die unseren Canvas anhalten und den Thread anhalten, sobald das Spiel pausiert wurde. Ihn wieder starten, sobald wir auf Continue klicken.
public void pauseThread() {
theGameLoopThread.setRunning(false);
}
public void resumeThread() {
theGameLoopThread = new GameLoopThread(this);
theGameLoopThread.setRunning(true);
theGameLoopThread.start();
}
Nun müssen wir diese beiden Methoden, die den Thread der auf den Canvas malt anhalten bzw weiterlaufen lassen nurnoch aufrufen. Das tun wir in unserer GameActivity Klasse, wenn das spiel angehalten wird bzw fortgesetzt wird. Angehalten wird er, wenn die Activity pausiert oder zerstört wird. Fortgesetzt muss der Thread werden wenn man auf den Button continue drückt, oder im Falle, dass der PausenDialog geöffnet ist, beim Klicken der Zurücktaste. Wenn ihr nicht genau wisst wo, dann schaut weiter Unten auf dieser Seite in die GameActivity Klasse.
Also müssen wir die Methoden onPause(), onResume() und onDestroy() anlegen. Die Methode onResume() brauchen wir für den fall, dass ein Spieler wieder in Spiel zurückkehrt. In dieser Methode müssen wir dialog.show(); aufrufen, wenn die Activity nicht gerade erst erstellt wurde, also:
@Override
protected void onResume() {
super.onResume();
if(!firstStart){
dialog.show();
dialogIsActive=true;
}
}
Außerdem müssen wir in diesem Fall dialogIsActive auf true setzen. Und wir müssen in der onPause() Methode zusätzlich zu theGameView.pauseThread();
folgendes einfügen
firstStart=false;
Um überhaupt in den Zustand zu kommen, indem wir unseren Dialog sehen, benötigen wir ersteinmal eine Methode um dorthin zu kommen. Dafür habe ich die onBackPressed() Methode von Android überschrieben. Auf diese Weise kann man beeinflussen was passieren soll, wenn der User die Zurücktaste auf seinem Smartphone verwendet. Ich habe sie mit folgendem Inhalt überschrieben:
@Override
public void onBackPressed() {
dialogState();
}
public void dialogState() {
if (dialogIsActive) {
dialog.hide();
dialogIsActive = false;
theGameView.resumeThread();
} else if (!dialogIsActive) {
theGameView.pauseThread();
dialog.show();
dialogIsActive = true;
}
}
Die boolsche Variable dialogIsActive soll hierbei dafür sorgen, dass wenn der Spieler auf die Zurücktaste das erste Mal drückt, der Dialog angezeigt, wenn er sie zum zweiten Mal drückt, ausgeblendet wird.
Wenn der Dialog versteckt wird, soll dialogState aufgerufen werden, das erreichen wir mit folgender Methode:
public void onDismiss(DialogInterface dialog) {
dialogState();
}
Damit diese Methode wie gewünscht aufgerufen wird, müssen wir noch den OnDismissListener implementieren.
public class GameActivity extends Activity implements OnClickListener, OnDismissListener {
// KlassenInhalt
}
Nun dürfen wir in der onCreate Methode nicht vergessen an den Dialog noch den OnDismissListener zu setzen.
dialog.setOnDismissListener(this);
Außerdem müssen wir in unserem Konstruktor der GameView Klasse noch ein paar Änderungen vornehmen, damit der User in dem Fall, dass ein Anruf reinkommt und er zurück zum Spiel will, keine fehler auftreten. Dazu überschreiben wir einfach die drei Methoden: surfaceDestroyed(), surfaceCreated() und surfaceChanged().
public void surfaceDestroyed(SurfaceHolder holder) {
theGameLoopThread.setRunning(false);
boolean retry = true;
while (retry) {
try {
theGameLoopThread.interrupt();
theGameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
theGameLoopThread.setRunning(true);
if (theGameLoopThread.getState() == theGameLoopThread.getState().NEW) {
theGameLoopThread.start();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
In Zeile 6 unterbrechen wir den Thread.
In Zeile 18 starten wir den Thread wenn die Bedingung erfüllt ist, dass der Thread gerade neu erstellt wurde. Das soll dafür sorgen, dass keine zwei Threads aktiv sind. Das würde sonst zu Konflikten führen, wenn wir das Spiel aus einem pausierten Zustand starten.
Wenn ihr am Ende des Tutorials angelangt seid, sollte eure GameActivity folgendermaßen aussehen:
GameActivity
package com.panjutorials.lazypudding;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ToggleButton;
public class GameActivity extends Activity implements OnClickListener, OnDismissListener {
private Button resume, menu, exit, newTry, pause;
private ToggleButton vibrationToggle, soundToggle;
private Dialog dialog;
private GameView theGameView;
private GameLoopThread theGameLoopThread;
private boolean firstStart = true;
private boolean dialogIsActive = false;
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
theGameView.pauseThread();
firstStart=false;
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (!firstStart) {
dialog.show();
dialogIsActive = true;
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
theGameView = new GameView(this);
setContentView(theGameView);
dialog = new Dialog(this,
android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
dialog.setContentView(R.layout.pausescreen);
dialog.hide();
dialog.setOnDismissListener(this);
initialize();
}
public void onGameOver() {
compareScore();
Intent theNextIntent = new Intent(getApplicationContext(),
GameOverActivity.class);
theNextIntent.putExtra("score", theGameView.getScore());
startActivity(theNextIntent);
this.finish();
}
public int readHighscore() {
SharedPreferences pref = getSharedPreferences("GAME", 0);
return pref.getInt("HIGHSCORE", 0);
}
public void writeHighscore(int highscore) {
SharedPreferences pref = getSharedPreferences("GAME", 0);
SharedPreferences.Editor editor = pref.edit();
editor.putInt("HIGHSCORE", highscore);
editor.commit();
}
public void compareScore() {
if (theGameView.getScore() > readHighscore()) {
writeHighscore(theGameView.getScore());
}
}
private void initialize() {
resume = (Button) dialog.findViewById(R.id.bContinue);
menu = (Button) dialog.findViewById(R.id.bMainMenu);
newTry = (Button) dialog.findViewById(R.id.bNewTry);
resume.setOnClickListener(this);
menu.setOnClickListener(this);
newTry.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.bContinue:
dialogState();
break;
case R.id.bMainMenu:
compareScore();
dialog.dismiss();
Intent menuIntent = new Intent(getApplicationContext(),
MenuActivity.class);
startActivity(menuIntent);
finish();
break;
case R.id.bNewTry:
compareScore();
Intent newGameScreen = new Intent(this, GameActivity.class);
startActivity(newGameScreen);
dialog.dismiss();
finish();
}
}
@Override
public void onBackPressed() {
dialogState();
}
public void dialogState() {
if (dialogIsActive) {
dialog.hide();
dialogIsActive = false;
theGameView.resumeThread();
} else if (!dialogIsActive) {
theGameView.pauseThread();
dialog.show();
dialogIsActive = true;
}
}
public void onDismiss(DialogInterface dialog) {
dialogState();
}
}
Und die GameView Klasse folgendermaßen:
GameView
package com.panjutorials.lazypudding;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
private List<Sprite> spriteList = new ArrayList<Sprite>();
private List<Integer> spriteListNum = new ArrayList<Integer>();
private SurfaceHolder surfaceHolder;
private Bitmap bmp;
private Bitmap livesPicture;
private GameLoopThread theGameLoopThread;
private boolean createSprites = true;
private long lastClick;
private int currentColorNum;
private int lives = 4;
private int score = 0;
private Paint paintRed, paintBlue, paintGreen, paintYellow;
private Paint currentColor;
private String scoreString;
private String livesString;
private float density;
private GameActivity theGameActivity = new GameActivity();
private boolean transparency = false;
public GameView(Context context) {
super(context);
livesPicture = BitmapFactory.decodeResource(getResources(),
R.drawable.lives);
Random rnd = new Random();
theGameActivity = (GameActivity) context;
setColors();
currentColorNum = rnd.nextInt(4);
theGameLoopThread = new GameLoopThread(this);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
theGameLoopThread.setRunning(false);
boolean retry = true;
while (retry) {
try {
theGameLoopThread.interrupt();
theGameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
theGameLoopThread.setRunning(true);
if (theGameLoopThread.getState() == theGameLoopThread
.getState().NEW) {
theGameLoopThread.start();
}
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
@Override
protected void draw(Canvas canvas) {
canvas.drawColor(Color.DKGRAY);
if (createSprites == true) {
initialSprites();
}
for (Sprite sprite : spriteList) {
sprite.draw(canvas);
}
if (currentColorNum == 0) {
drawLines(paintBlue, canvas);
} else if (currentColorNum == 1) {
drawLines(paintRed, canvas);
} else if (currentColorNum == 2) {
drawLines(paintGreen, canvas);
} else if (currentColorNum == 3) {
drawLines(paintYellow, canvas);
}
final int fontSize = (int) (25 * density);
int yTextPos = (int) (25 * density);
Typeface font = Typeface.create("Arial", Typeface.NORMAL);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTypeface(font);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
scoreString = String.valueOf(score);
int x = (canvas.getWidth() * 5 / 7);
final String text = "Score: " + scoreString;
canvas.drawText(text, x, yTextPos, paint);
drawLives(canvas, paint);
}
private void createSprite(int index) {
Bitmap bmp = null;
switch (index) {
case 0:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspriteblue);
break;
case 1:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspritered);
break;
case 2:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspritegreen);
break;
case 3:
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.alienspriteyellow);
break;
}
Sprite sprite = new Sprite(this, bmp);
spriteList.add(sprite);
spriteListNum.add(index);
}
private void initialSprites() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++)
createSprite(i);
}
createSprites = false;
}
private void rndCreateSprite() {
Random rnd = new Random(System.currentTimeMillis());
int i = rnd.nextInt(4);
createSprite(i);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 300) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
for (int i = spriteList.size() - 1; i >= 0; i--) {
Sprite sprite = spriteList.get(i);
if (sprite.isTouched(event.getX(), event.getY())) {
if (currentColorNum == spriteListNum.get(i)) {
score++;
} else {
lives--;
if (lives == 0) {
theGameActivity.onGameOver();
}
}
if (score == 3)
lives++;
rndCreateSprite();
removeSprite(i);
changeColor();
break;
}
}
}
}
return true;
}
private void removeSprite(int index) {
spriteList.remove(index);
spriteListNum.remove(index);
}
public void setColors() {
Paint paintRed = new Paint();
paintRed.setARGB(255, 236, 27, 36);
this.paintRed = paintRed;
Paint paintBlue = new Paint();
paintBlue.setARGB(255, 36, 72, 204);
this.paintBlue = paintBlue;
Paint paintGreen = new Paint();
paintGreen.setARGB(255, 34, 177, 76);
this.paintGreen = paintGreen;
Paint paintYellow = new Paint();
paintYellow.setARGB(255, 255, 242, 0);
this.paintYellow = paintYellow;
}
public void drawLines(Paint lineColor, Canvas canvas) {
int lineWidth = (int) (10 * density);
int screenHeight = getHeight();
int screenWidth = getWidth();
canvas.drawRect(0, 0, lineWidth, getHeight(), lineColor);
canvas.drawRect(0, getHeight() - lineWidth, screenWidth, screenHeight,
lineColor);
canvas.drawRect(screenWidth - lineWidth, 0, screenWidth, screenHeight,
lineColor);
currentColor = lineColor;
}
public void changeColor() {
Random rnd = new Random();
int index = rnd.nextInt(spriteListNum.size());
this.currentColorNum = spriteListNum.get(index);
switch (index) {
case 0:
currentColor = paintBlue;
break;
case 1:
currentColor = paintRed;
break;
case 2:
currentColor = paintGreen;
break;
case 3:
currentColor = paintYellow;
break;
}
}
public float getDensity() {
density = getResources().getDisplayMetrics().density;
return density;
}
private void drawLives(Canvas canvas, Paint paint) {
int xHeart = (int) (15 * density);
int yHeart = (int) (12 * density);
if (lives == 3) {
canvas.drawBitmap(livesPicture, xHeart, yHeart, paint);
canvas.drawBitmap(livesPicture, xHeart + livesPicture.getWidth()
+ 3 * density, yHeart, paint);
canvas.drawBitmap(livesPicture,
xHeart + 2 * livesPicture.getWidth() + 6 * density, yHeart,
paint);
}
if (lives == 2) {
canvas.drawBitmap(livesPicture, xHeart, yHeart, paint);
canvas.drawBitmap(livesPicture, xHeart + livesPicture.getWidth()
+ 3, yHeart, paint);
}
if (lives == 1) {
canvas.drawBitmap(livesPicture, xHeart, yHeart, paint);
}
if (lives > 3) {
livesString = String.valueOf(lives);
final String lives = livesString + "x";
canvas.drawText(lives, 35 * getDensity(), 30 * getDensity(), paint);
canvas.drawBitmap(livesPicture, 15 * getDensity() + 2
* livesPicture.getWidth() + 6, 12 * getDensity(), paint);
}
}
public int getScore() {
return this.score;
}
public void pauseThread() {
theGameLoopThread.setRunning(false);
}
public void resumeThread() {
theGameLoopThread = new GameLoopThread(this);
theGameLoopThread.setRunning(true);
theGameLoopThread.start();
}
}