Skip to content

Instantly share code, notes, and snippets.

@robsbots
Created March 24, 2014 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robsbots/9739143 to your computer and use it in GitHub Desktop.
Save robsbots/9739143 to your computer and use it in GitHub Desktop.
GameThread as of week 5. Only one line needs chaning. This is for the soundpool setup
package uk.ac.reading.sis05kol.mooc;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
public abstract class GameThread extends Thread {
//Different mMode states
public static final int STATE_LOSE = 1;
public static final int STATE_PAUSE = 2;
public static final int STATE_READY = 3;
public static final int STATE_RUNNING = 4;
public static final int STATE_WIN = 5;
//Control variable for the mode of the game (e.g. STATE_WIN)
protected int mMode = 1;
//Control of the actual running inside run()
private boolean mRun = false;
//The surface this thread (and only this thread) writes upon
private SurfaceHolder mSurfaceHolder;
//the message handler to the View/Activity thread
private Handler mHandler;
//Android Context - this stores almost all we need to know
//private Context mContext;
// ####################################################################################
// # Changed to enable sound in the game. mContext needs to be available for SoundPool
protected Context mContext;
//The view
public GameView mGameView;
//We might want to extend this call - therefore protected
protected int mCanvasWidth = 1;
protected int mCanvasHeight = 1;
//Last time we updated the game physics
protected long mLastTime = 0;
protected Bitmap mBackgroundImage;
protected long score = 0;
private long now;
private float elapsed;
public GameThread(GameView gameView) {
mGameView = gameView;
mSurfaceHolder = gameView.getHolder();
mHandler = gameView.getmHandler();
mContext = gameView.getContext();
mBackgroundImage = BitmapFactory.decodeResource
(gameView.getContext().getResources(),
R.drawable.background);
}
/*
* Called when app is destroyed, so not really that important here
* But if (later) the game involves more thread, we might need to stop a thread, and then we would need this
* Dare I say memory leak...
*/
public void cleanup() {
this.mContext = null;
this.mGameView = null;
this.mHandler = null;
this.mSurfaceHolder = null;
}
//Pre-begin a game
abstract public void setupBeginning();
//Starting up the game
public void doStart() {
synchronized(mSurfaceHolder) {
setupBeginning();
mLastTime = System.currentTimeMillis() + 100;
setState(STATE_RUNNING);
setScore(0);
}
}
//The thread start
@Override
public void run() {
Canvas canvasRun;
while (mRun) {
canvasRun = null;
try {
canvasRun = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) {
updatePhysics();
}
doDraw(canvasRun);
}
}
finally {
if (canvasRun != null) {
if(mSurfaceHolder != null)
mSurfaceHolder.unlockCanvasAndPost(canvasRun);
}
}
}
}
/*
* Surfaces and drawing
*/
public void setSurfaceSize(int width, int height) {
synchronized (mSurfaceHolder) {
mCanvasWidth = width;
mCanvasHeight = height;
// don't forget to resize the background image
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, width, height, true);
}
}
protected void doDraw(Canvas canvas) {
if(canvas == null) return;
if(mBackgroundImage != null) canvas.drawBitmap(mBackgroundImage, 0, 0, null);
}
private void updatePhysics() {
now = System.currentTimeMillis();
elapsed = (now - mLastTime) / 1000.0f;
updateGame(elapsed);
mLastTime = now;
}
abstract protected void updateGame(float secondsElapsed);
/*
* Control functions
*/
//Finger touches the screen
public boolean onTouch(MotionEvent e) {
if(e.getAction() != MotionEvent.ACTION_DOWN) return false;
if(mMode == STATE_READY || mMode == STATE_LOSE || mMode == STATE_WIN) {
doStart();
return true;
}
if(mMode == STATE_PAUSE) {
unpause();
return true;
}
synchronized (mSurfaceHolder) {
this.actionOnTouch(e.getRawX(), e.getRawY());
}
return false;
}
protected void actionOnTouch(float x, float y) {
//Override to do something
}
//The Accellerometer has changed
@SuppressWarnings("deprecation")
public void onSensorChanged(SensorEvent event) {
synchronized (mSurfaceHolder) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
actionWhenPhoneMoved(event.values[2],event.values[1], event.values[0]);
}
}
}
protected void actionWhenPhoneMoved(float xDirection, float yDirection, float zDirection) {
//Override to do something
}
/*
* Game states
*/
public void pause() {
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING) setState(STATE_PAUSE);
}
}
public void unpause() {
// Move the real time clock up to now
synchronized (mSurfaceHolder) {
mLastTime = System.currentTimeMillis();
}
setState(STATE_RUNNING);
}
//Send messages to View/Activity thread
public void setState(int mode) {
synchronized (mSurfaceHolder) {
setState(mode, null);
}
}
public void setState(int mode, CharSequence message) {
synchronized (mSurfaceHolder) {
mMode = mode;
if (mMode == STATE_RUNNING) {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("text", "");
b.putInt("viz", View.INVISIBLE);
b.putBoolean("showAd", false);
msg.setData(b);
mHandler.sendMessage(msg);
}
else {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
Resources res = mContext.getResources();
CharSequence str = "";
if (mMode == STATE_READY)
str = res.getText(R.string.mode_ready);
else
if (mMode == STATE_PAUSE)
str = res.getText(R.string.mode_pause);
else
if (mMode == STATE_LOSE)
str = res.getText(R.string.mode_lose);
else
if (mMode == STATE_WIN) {
str = res.getText(R.string.mode_win);
}
if (message != null) {
str = message + "\n" + str;
}
b.putString("text", str.toString());
b.putInt("viz", View.VISIBLE);
msg.setData(b);
mHandler.sendMessage(msg);
}
}
}
/*
* Getter and setter
*/
public void setSurfaceHolder(SurfaceHolder h) {
mSurfaceHolder = h;
}
public boolean isRunning() {
return mRun;
}
public void setRunning(boolean running) {
mRun = running;
}
public int getMode() {
return mMode;
}
public void setMode(int mMode) {
this.mMode = mMode;
}
/* ALL ABOUT SCORES */
//Send a score to the View to view
//Would it be better to do this inside this thread writing it manually on the screen?
public void setScore(long score) {
this.score = score;
synchronized (mSurfaceHolder) {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putBoolean("score", true);
b.putString("text", getScoreString().toString());
msg.setData(b);
mHandler.sendMessage(msg);
}
}
public float getScore() {
return score;
}
public void updateScore(long score) {
this.setScore(this.score + score);
}
protected CharSequence getScoreString() {
return Long.toString(Math.round(this.score));
}
}
// This file is part of the course "Begin Programming: Build your first mobile game" from futurelearn.com
// Copyright: University of Reading and Karsten Lundqvist
// It is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// It is is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// You should have received a copy of the GNU General Public License
// along with it. If not, see <http://www.gnu.org/licenses/>.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment