Back to project page BallDemo.
The source code is released under:
GNU General Public License
If you think the Android project BallDemo listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package uk.ac.reading.sis05kol.mooc; /* ww w . j a va 2s . c o m*/ 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; //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)); } }