Created
February 2, 2018 12:20
-
-
Save glennismade/6c5053f046d6bde8da3737830960fb17 to your computer and use it in GitHub Desktop.
Simple Android Based Infinite runner style racing game
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//import android.graphics.Bitmap; | |
//import android.graphics.Canvas; | |
// | |
//import uk.ac.reading.sis05kol.mooc.MainActivity; | |
// | |
//public class Background { | |
// | |
// private Bitmap image; | |
// private int x, y, dx; | |
// | |
// public Background(Bitmap res) | |
// { | |
// image = res; | |
// } | |
// public void update() | |
// { | |
// x+=dx; | |
// if(x<-MainActivity.HEIGHT){ | |
// x=0; | |
// } | |
// } | |
// public void draw(Canvas canvas) | |
// { | |
// canvas.drawBitmap(image, x, y,null); | |
// if(x<0) | |
// { | |
// canvas.drawBitmap(image, x+MainActivity.HEIGHT, y, null); | |
// } | |
// } | |
// public void setVector(int dx) | |
// { | |
// this.dx = dx; | |
// } | |
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//package uk.ac.reading.sis05kol.mooc; | |
// | |
//import java.util.Vector; | |
// | |
///** | |
// * Created by glennhealy on 17/04/2016. | |
// */ | |
//public class Box { | |
// | |
// public Vector position; | |
// private float width; | |
// private float height; | |
// private float halfWidth; | |
// private float halfHeight; | |
// private int x = 0; | |
// private int y = 0; | |
// | |
// | |
// public Box(Vector position, float width, float height) { | |
// this.position = position; | |
// this.width = width; | |
// this.height = height; | |
// halfWidth = width/2; | |
// halfHeight = height/2; | |
// | |
// | |
// } | |
// | |
//// public boolean intersects(Box box) { | |
//// return (position + halfWidth() >= box.position.x = box.halfWidth() && position.y + halfHeight() >= box.position.y - box.halfHeight() ) && (box.position.x + box.halfWidth() >= position.x - halfWidth() && box.position.y + box.halfHeight() >= position.y - halfHeight() ); | |
//// | |
//// | |
//// | |
//// } | |
// | |
// | |
// public float getWidth() { | |
// | |
// return width; | |
// } | |
// | |
// public void setWidth(float width) { | |
// this.width = width; | |
// halfHeight = width /2; | |
// } | |
// | |
// public float getHeight() { | |
// return height; | |
// } | |
// | |
// public void setHeight(float height) { | |
// this.height = height; | |
// halfHeight = height /2; | |
// } | |
// | |
// | |
//} | |
// | |
// public boolean isIntersecting(Box box) { | |
// boolean test1 = false; | |
// boolean test2 = false; | |
// | |
// test1 = (position.x + halfWidth() >= box.position.y = box.halfHeight() ) | |
// && | |
// | |
// position.y + halfHeight() >= box.position.y = box.halfHeight() ); | |
// | |
// test2 = (box.position.x + box.halfWidth() >= position.x - halfWidth() ) | |
// | |
// && | |
// | |
// box.position.y + box.halfHeight() >= position.y - halfHeight() ); | |
// | |
// return test1 && test2; | |
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.hardware.SensorManager; | |
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; | |
protected int dx; | |
//Last time we updated the game physics | |
protected long mLastTime = 0; | |
protected Bitmap mBackgroundImage; | |
protected long score = 0; | |
//Used for time keeping | |
private long now; | |
private float elapsed; | |
//Rotation vectors used to calculate orientation | |
float[] mGravity; | |
float[] mGeomagnetic; | |
//Used to ensure appropriate threading | |
static final Integer monitor = 1; | |
public GameThread(GameView gameView) { | |
mGameView = gameView; | |
mSurfaceHolder = gameView.getHolder(); | |
mHandler = gameView.getmHandler(); | |
mContext = gameView.getContext(); | |
//public Bitmap gb = mBackgroundImage; | |
mBackgroundImage = BitmapFactory.decodeResource | |
(gameView.getContext().getResources(), | |
R.drawable.track5); | |
//mBackgroundImage.setVector(-5); | |
} | |
// public void setVector(int dx){ | |
// this.dx = dx; | |
// } | |
/* | |
* 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(monitor) { | |
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 (monitor) { | |
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 (monitor) { | |
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 (monitor) { | |
this.actionOnTouch(e.getRawX(), e.getRawY()); | |
} | |
return false; | |
} | |
protected void actionOnTouch(float x, float y) { | |
//Override to do something | |
} | |
//The Orientation has changed | |
@SuppressWarnings("deprecation") | |
public void onSensorChanged(SensorEvent event) { | |
synchronized (monitor) { | |
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) | |
mGravity = event.values; | |
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) | |
mGeomagnetic = event.values; | |
if (mGravity != null && mGeomagnetic != null) { | |
float R[] = new float[9]; | |
float I[] = new float[9]; | |
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic); | |
if (success) { | |
float orientation[] = new float[3]; | |
SensorManager.getOrientation(R, orientation); | |
actionWhenPhoneMoved(orientation[2],orientation[1],orientation[0]); | |
} | |
} | |
} | |
} | |
protected void actionWhenPhoneMoved(float xDirection, float yDirection, float zDirection) { | |
//Override to do something | |
} | |
/* | |
* Game states | |
*/ | |
public void pause() { | |
synchronized (monitor) { | |
if (mMode == STATE_RUNNING) setState(STATE_PAUSE); | |
} | |
} | |
public void unpause() { | |
// Move the real time clock up to now | |
synchronized (monitor) { | |
mLastTime = System.currentTimeMillis(); | |
} | |
setState(STATE_RUNNING); | |
} | |
//Send messages to View/Activity thread | |
public void setState(int mode) { | |
synchronized (monitor) { | |
setState(mode, null); | |
} | |
} | |
public void setState(int mode, CharSequence message) { | |
synchronized (monitor) { | |
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 (monitor) { | |
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/>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
import android.content.Context; | |
import android.graphics.Bitmap; | |
import android.graphics.Color; | |
import android.hardware.Sensor; | |
import android.hardware.SensorEvent; | |
import android.hardware.SensorEventListener; | |
import android.hardware.SensorManager; | |
import android.os.Handler; | |
import android.os.Message; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.SurfaceHolder; | |
import android.view.SurfaceView; | |
import android.view.View; | |
import android.widget.TextView; | |
public class GameView extends SurfaceView implements SurfaceHolder.Callback, SensorEventListener { | |
private volatile GameThread thread; | |
//private SensorEventListener sensorAccelerometer; | |
//Handle communication from the GameThread to the View/Activity Thread | |
private Handler mHandler; | |
//Pointers to the views | |
private TextView mScoreView; | |
private TextView mStatusView; | |
Sensor accelerometer; | |
Sensor magnetometer; | |
public GameView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
//Get the holder of the screen and register interest | |
SurfaceHolder holder = getHolder(); | |
holder.addCallback(this); | |
//Set up a handler for messages from GameThread | |
mHandler = new Handler() { | |
@Override | |
public void handleMessage(Message m) { | |
if(m.getData().getBoolean("score")) { | |
mScoreView.setText(m.getData().getString("text")); | |
} | |
else { | |
//So it is a status | |
int i = m.getData().getInt("viz"); | |
switch(i) { | |
case View.VISIBLE: | |
mStatusView.setVisibility(View.VISIBLE); | |
break; | |
case View.INVISIBLE: | |
mStatusView.setVisibility(View.INVISIBLE); | |
break; | |
case View.GONE: | |
mStatusView.setVisibility(View.GONE); | |
break; | |
} | |
mStatusView.setText(m.getData().getString("text")); | |
} | |
} | |
}; | |
} | |
//Used to release any resources. | |
public void cleanup() { | |
this.thread.setRunning(false); | |
this.thread.cleanup(); | |
this.removeCallbacks(thread); | |
thread = null; | |
this.setOnTouchListener(null); | |
SurfaceHolder holder = getHolder(); | |
holder.removeCallback(this); | |
} | |
/* | |
* Setters and Getters | |
*/ | |
public void setThread(GameThread newThread) { | |
thread = newThread; | |
setOnTouchListener(new View.OnTouchListener() { | |
public boolean onTouch(View v, MotionEvent event) { | |
return thread != null && thread.onTouch(event); | |
} | |
}); | |
setClickable(true); | |
setFocusable(true); | |
} | |
public GameThread getThread() { | |
return thread; | |
} | |
public TextView getStatusView() { | |
return mStatusView; | |
} | |
public void setStatusView(TextView mStatusView) { | |
this.mStatusView = mStatusView; | |
} | |
public TextView getScoreView() { | |
return mScoreView; | |
} | |
public void setScoreView(TextView mScoreView) { | |
this.mScoreView = mScoreView; | |
} | |
public Handler getmHandler() { | |
return mHandler; | |
} | |
public void setmHandler(Handler mHandler) { | |
this.mHandler = mHandler; | |
} | |
/* | |
* Screen functions | |
*/ | |
//ensure that we go into pause state if we go out of focus | |
@Override | |
public void onWindowFocusChanged(boolean hasWindowFocus) { | |
if(thread!=null) { | |
if (!hasWindowFocus) | |
thread.pause(); | |
} | |
} | |
public void surfaceCreated(SurfaceHolder holder) { | |
if(thread!=null) { | |
thread.setRunning(true); | |
if(thread.getState() == Thread.State.NEW){ | |
//Just start the new thread | |
thread.start(); | |
} | |
else { | |
if(thread.getState() == Thread.State.TERMINATED){ | |
//Start a new thread | |
//Should be this to update screen with old game: new GameThread(this, thread); | |
//The method should set all fields in new thread to the value of old thread's fields | |
thread = new TheGame(this); | |
thread.setRunning(true); | |
thread.start(); | |
} | |
} | |
} | |
} | |
//Always called once after surfaceCreated. Tell the GameThread the actual size | |
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | |
if(thread!=null) { | |
thread.setSurfaceSize(width, height); | |
} | |
} | |
/* | |
* Need to stop the GameThread if the surface is destroyed | |
* Remember this doesn't need to happen when app is paused on even stopped. | |
*/ | |
public void surfaceDestroyed(SurfaceHolder arg0) { | |
boolean retry = true; | |
if(thread!=null) { | |
thread.setRunning(false); | |
} | |
//join the thread with this thread | |
while (retry) { | |
try { | |
if(thread!=null) { | |
thread.join(); | |
} | |
retry = false; | |
} | |
catch (InterruptedException e) { | |
//naugthy, ought to do something... | |
} | |
} | |
} | |
/* | |
* Accelerometer | |
*/ | |
public void startSensor(SensorManager sm) { | |
accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); | |
magnetometer = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); | |
sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI); | |
sm.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI); | |
} | |
public void removeSensor(SensorManager sm) { | |
sm.unregisterListener(this); | |
accelerometer = null; | |
magnetometer = null; | |
} | |
//A sensor has changed, let the thread take care of it | |
@Override | |
public void onSensorChanged(SensorEvent event) { | |
if(thread!=null) { | |
thread.onSensorChanged(event); | |
} | |
} | |
@Override | |
public void onAccuracyChanged(Sensor sensor, int accuracy) { | |
} | |
public void setVisibility(Bitmap mSpeedBoost) { | |
mSpeedBoost.eraseColor(Color.TRANSPARENT); | |
} | |
} | |
// 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/>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
import android.app.Activity; | |
import android.content.Intent; | |
import android.content.Context; | |
import android.hardware.SensorManager; | |
import android.os.Bundle; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.view.View; | |
import android.view.Window; | |
import android.view.WindowManager; | |
import android.view.animation.TranslateAnimation; | |
import android.widget.AdapterView; | |
import android.widget.Button; | |
import android.widget.EditText; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import java.util.Date; | |
public class MainActivity extends Activity { | |
private static final int MENU_RESUME = 1; | |
private static final int MENU_START = 2; | |
private static final int MENU_STOP = 3; | |
public static final int WIDTH = 200; | |
public static final int HEIGHT = 300; | |
private GameThread mGameThread; | |
private GameView mGameView; | |
/** Called when the activity is first created. */ | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
requestWindowFeature(Window.FEATURE_NO_TITLE); | |
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | |
setContentView(R.layout.activity_main); | |
mGameView = (GameView) findViewById(R.id.gamearea); | |
mGameView.setStatusView((TextView) findViewById(R.id.text)); | |
mGameView.setScoreView((TextView) findViewById(R.id.score)); | |
this.startGame(mGameView, null, savedInstanceState); | |
Button HomeButton = (Button) findViewById(R.id.btnHome); | |
HomeButton.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View view) { | |
System.exit(0); | |
startActivity(new Intent(MainActivity.this, mainmenu.class)); | |
} | |
}); | |
// Intent menuIntent = new Intent(getApplicationContext(), mainmenu.class); | |
// startActivityForResult(menuIntent, 100); | |
// | |
// protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
// super.onActivityResult(requestCode, resultCode, data); | |
// if(resultCode == 100){ | |
// startActivity(menuIntent); | |
// } | |
// finish(); | |
// | |
// } | |
// ImageView img_animation = (ImageView) findViewById(R.id.imgTrack); | |
// | |
// TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f, | |
// 100.0f, 100.0f); | |
// animation.setDuration(5000); | |
// animation.setRepeatCount(5); | |
// animation.setRepeatMode(2); | |
// | |
// img_animation.startAnimation(animation); | |
} | |
private void startGame(GameView gView, GameThread gThread, Bundle savedInstanceState) { | |
//Set up a new game, we don't care about previous states | |
mGameThread = new TheGame(mGameView); | |
mGameView.setThread(mGameThread); | |
mGameThread.setState(GameThread.STATE_READY); | |
mGameView.startSensor((SensorManager)getSystemService(Context.SENSOR_SERVICE)); | |
} | |
// @Override | |
public void onRunning(View v){ | |
//super.onRunning(); | |
if(mGameThread.getMode() == GameThread.STATE_RUNNING) { //pause the game if its running | |
mGameThread.pause(); | |
} | |
else if(mGameThread.getMode() == GameThread.STATE_PAUSE) { //unpause the game if its running | |
mGameThread.unpause(); | |
} | |
} | |
/* | |
* Activity state functions | |
*/ | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
if(mGameThread.getMode() == GameThread.STATE_RUNNING) { | |
mGameThread.setState(GameThread.STATE_PAUSE); | |
} | |
} | |
@Override | |
protected void onDestroy() { | |
super.onDestroy(); | |
mGameView.cleanup(); | |
mGameView.removeSensor((SensorManager)getSystemService(Context.SENSOR_SERVICE)); | |
mGameThread = null; | |
mGameView = null; | |
} | |
/* | |
* UI Functions | |
*/ | |
@Override | |
public boolean onCreateOptionsMenu(Menu menu) { | |
super.onCreateOptionsMenu(menu); | |
menu.add(0, MENU_START, 0, R.string.menu_start); | |
menu.add(0, MENU_STOP, 0, R.string.menu_stop); | |
menu.add(0, MENU_RESUME, 0, R.string.menu_resume); | |
return true; | |
} | |
@Override | |
public boolean onOptionsItemSelected(MenuItem item) { | |
switch (item.getItemId()) { | |
case MENU_START: | |
mGameThread.doStart(); | |
return true; | |
case MENU_STOP: | |
mGameThread.setState(GameThread.STATE_LOSE, getText(R.string.message_stopped)); | |
return true; | |
case MENU_RESUME: | |
mGameThread.unpause(); | |
return true; | |
} | |
return false; | |
} | |
public void onNothingSelected(AdapterView<?> arg0) { | |
// Do nothing if nothing is selected | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="uk.ac.reading.sis05kol.mooc" > | |
<application | |
android:allowBackup="true" | |
android:icon="@drawable/ic_launcher" | |
android:label="@string/app_name" | |
android:theme="@style/AppTheme" > | |
<activity | |
android:name=".mainmenu" | |
android:label="@string/app_name" | |
android:screenOrientation="portrait" | |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<activity | |
android:name=".MainActivity" | |
android:label="@string/app_name" | |
android:screenOrientation="portrait" | |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > | |
</activity> | |
<activity | |
android:name=".SettingsActivity" | |
android:label="@string/app_name" | |
android:screenOrientation="portrait" | |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > | |
</activity> | |
<activity | |
android:name=".ScoreActivity" | |
android:label="@string/app_name" | |
android:screenOrientation="portrait" | |
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > | |
</activity> | |
</application> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
import java.util.Timer; | |
import java.util.TimerTask; | |
/** | |
* Created by glennhealy on 18/04/2016. | |
*/ | |
public class myTimer extends Object { | |
Timer timer = new Timer(); | |
int secondsPassed =0; | |
TimerTask mytask = new TimerTask() { | |
@Override | |
public void run() { | |
secondsPassed++; | |
} | |
}; | |
public void startTimer(){ | |
timer.scheduleAtFixedRate(mytask, 1000, 1000); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.content.Intent; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.TextView; | |
import java.io.BufferedReader; | |
import java.io.FileReader; | |
import uk.ac.reading.sis05kol.mooc.TheGame; | |
/** | |
* Created by glennhealy on 18/04/2016. | |
*/ | |
public class ScoreActivity extends Activity { | |
private GameThread myGameThread; | |
private GameView myGameView; | |
// BufferedReader fileReader = new BufferedReader(new FileReader("score.txt")); | |
// | |
// StringBuilder strBuilder = new StringBuilder(); | |
// | |
// public String line; | |
// | |
// while((line = fileReader.readLine()) != null) | |
// { | |
// strBuilder.append(line); | |
// } | |
// | |
// fileReader.close(); | |
// | |
// strBuilder.trimToSize(); | |
// | |
// String contentsOfFile = strBuilder.toString(); | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_score); | |
TextView Score1 = (TextView) findViewById(R.id.txtScore1); | |
// Score1.setText(contentsOfFile); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
import android.app.Activity; | |
import android.app.AlertDialog; | |
import android.content.DialogInterface; | |
import android.content.Intent; | |
import android.content.SharedPreferences; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.CheckBox; | |
import android.widget.CompoundButton; | |
import javax.xml.transform.Source; | |
/** | |
* Created by glennhealy on 09/04/2016. | |
*/ | |
public class SettingsActivity extends Activity { | |
private GameThread myGameThread; | |
private GameView myGameView; | |
public final boolean audio = true; | |
MediaPlayer Music; | |
// public final boolean Checked = false; | |
// public int ON, OFF; | |
//this method doesnt work currenly. need to figure out how to enable sound files. | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_settings); | |
final CheckBox Sound = (CheckBox) findViewById(R.id.chbxSound); | |
Sound.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
if (Sound.isChecked()) { | |
// mediaplayer is already muted, so needs be to unmuted | |
Music.setVolume(1, 1); | |
} else { | |
// mute media player | |
Music.setVolume(0, 0); | |
} | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.ac.reading.sis05kol.mooc; | |
//Other parts of the android libraries that we use | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Canvas; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.FileWriter; | |
import java.io.Writer; | |
import java.util.Random; | |
import java.util.Timer; | |
public class TheGame extends GameThread{ | |
public String ScoreFile = "scores.txt"; | |
// public FileOutputStream files = openFileOutput(); | |
//bitmaps for all the objects on the screen | |
private Bitmap mBall; | |
private Bitmap mEnemy; | |
private Bitmap mSpeedBoost; | |
private Bitmap mBomb; | |
/////////////////// | |
public static int i; | |
public boolean collide = false; | |
public boolean collected = false; | |
public float BackgroundY = 0, BackgroundX = 0; | |
// public float globalScore = score; | |
// private Background bg; | |
private float Ewidth = 150; | |
private float Eheight = 300; | |
private float Mwidth = 128; | |
private float Mheight = 128; | |
private float Bwidth = 85; | |
private float Bheight = 85; | |
//The X and Y position of the ball on the screen (middle of ball) | |
private float mBallX = mCanvasWidth /2; | |
private float mBallY = mCanvasHeight /2; | |
private float mEnemyX = mCanvasWidth /2; | |
private float mEnemyY = mCanvasHeight /2; | |
private float mSpeedBoostX = mCanvasWidth /2; | |
private float mSpeedBoostY = mCanvasHeight /2; | |
private float mBombX = mCanvasWidth /2; | |
private float mBombY = mCanvasHeight /2; | |
//The speed (pixel/second) of the ball in direction X and Y | |
private float mBallSpeedX = 0; | |
private float mBallSpeedY = 0; | |
private float mEnemySpeedX = 0; | |
private float mEnemySpeedY = 1; | |
private float mBombSpeedX = 0; | |
private float mBombSpeedY = 0; | |
//This is run before anything else, so we can prepare things here | |
public TheGame(GameView gameView) { | |
//House keeping | |
super(gameView); | |
//Prepare the image so we can draw it on the screen (using a canvas) | |
mBall = BitmapFactory.decodeResource (gameView.getContext().getResources(), R.drawable.car); //player car | |
mEnemy = BitmapFactory.decodeResource (gameView.getContext().getResources(), R.drawable.car2); //enemy car | |
mSpeedBoost = BitmapFactory.decodeResource (gameView.getContext().getResources(), R.drawable.speedboost); //speed boost image | |
mBomb = BitmapFactory.decodeResource (gameView.getContext().getResources(), R.drawable.sad_ball); // bomb | |
// mBackgroundImage.setVector(-5); | |
} | |
//This is run before a new game (also after an old game) | |
@Override | |
public void setupBeginning() { | |
//Initialise speeds | |
mBallSpeedX = 0; | |
mBallSpeedY = 0; | |
mEnemySpeedY =-500; | |
mEnemySpeedX =1; | |
mBombSpeedY = 5; | |
mBombSpeedX = 0; | |
//Place the ball in the middle of the screen. | |
//mBall.Width() and mBall.getHeigh() gives us the height and width of the image of the ball | |
mBallX = mCanvasWidth / 2; | |
mBallY = mCanvasHeight / 2; | |
mEnemyX = mCanvasWidth /7; | |
mEnemyY = mCanvasHeight /2; | |
mSpeedBoostY =mCanvasHeight /5; | |
mSpeedBoostX = mCanvasWidth /2; | |
mBombX = mCanvasWidth /2; | |
mBombY = mCanvasHeight /5; | |
} | |
@Override | |
protected void doDraw(Canvas canvas) { | |
//If there isn't a canvas to draw on do nothing | |
//It is ok not understanding what is happening here | |
if(canvas == null) return; | |
super.doDraw(canvas); | |
canvas.drawBitmap(mBackgroundImage, BackgroundX, BackgroundY, null); //background image | |
//draw the image of the ball using the X and Y of the ball | |
//drawBitmap uses top left corner as reference, we use middle of picture | |
//null means that we will use the image without any extra features (called Paint) | |
canvas.drawBitmap(mBall, mBallX - mBall.getWidth() / 2, mBallY - mBall.getHeight() / 2, null); // drawing the car | |
canvas.drawBitmap(mEnemy, mEnemyX - mEnemy.getWidth() /4, mEnemyY - mEnemy.getHeight() /7, null); //drawing the AI car | |
canvas.drawBitmap(mBomb, mBombX - mBomb.getWidth() /6, mBombY - mBomb.getHeight() /randomPos(), null); // drawing the sad Face | |
//if(!collide){ | |
canvas.drawBitmap(mSpeedBoost, mSpeedBoostX - mSpeedBoost.getWidth() /2, mSpeedBoostY - mSpeedBoost.getHeight() /6, null); //drawing the point bonus | |
//} | |
// if (mCanvasHeight <0) { | |
// canvas.drawBitmap(mBackgroundImage, mCanvasHeight+MainActivity.HEIGHT, mCanvasWidth, null); | |
// } | |
if(mEnemyY <-5){ //this resets the AI cars Y position to below the screen | |
mEnemyY = mCanvasHeight; | |
mEnemyX = randomEnemyX(); | |
canvas.drawBitmap(mEnemy, mEnemyX - mEnemy.getWidth() /randomEnemyX(), mEnemyY -mEnemy.getHeight() /7, null); | |
} | |
float scrollFactor = 0.5f; //Moves the background 0.5 pixels up per call of the draw method | |
this.mCanvasHeight += scrollFactor; // this checks the canvas height and add the scroll factor to it. | |
} | |
//This is run whenever the phone is touched by the user | |
@Override | |
protected void actionOnTouch(float x, float y) { | |
//Increase/decrease the speed of the ball making the ball move towards the touch | |
mBallSpeedX = x - mBallX; // user car left and right controlls | |
//mBallSpeedY = y - mBallY; // disables to prevent user car from leavign screen | |
} | |
// This is run whenever the phone moves around its axises | |
// @Override | |
// protected void actionWhenPhoneMoved(float xDirection, float yDirection, float zDirection) { | |
// /* | |
// Increase/decrease the speed of the ball. | |
// If the ball moves too fast try and decrease 70f | |
// If the ball moves too slow try and increase 70f | |
// */ | |
// | |
// mBallSpeedX = mBallSpeedX + 72f * xDirection; | |
// mBallSpeedY = mBallSpeedY - 72f * yDirection; | |
// } | |
public float randomPos(){ // random method to generate random x value for point bonus and sad face | |
Random r = new Random(); | |
return r.nextInt(mCanvasWidth-1)+1; | |
} | |
public float randomEnemyX(){ // random method to generate random x value for AI car | |
Random r = new Random(); | |
return r.nextInt(mCanvasWidth-2)+2; | |
} | |
public float randomSpeed(){ | |
Random Speed = new Random(); | |
return Speed.nextInt((int) (mEnemySpeedY-1))+1; | |
} | |
//This is run just before the game "scenario" is printed on the screen | |
@Override | |
protected void updateGame(float secondsElapsed) { | |
//Move the ball's X and Y using the speed (pixel/sec) | |
mBallX = mBallX + secondsElapsed * mBallSpeedX; //sets the user car's speed | |
mBallY = mBallY + secondsElapsed * mBallSpeedY; // this does the same but for Y | |
//mEnemyY = mEnemyY * mEnemySpeedY; | |
mEnemyY = mEnemyY + secondsElapsed * mEnemySpeedY; // sets the AI car speed x | |
mBombY = mBombY + secondsElapsed * mBombSpeedY; // sets the AI car speed Y | |
if (getMode() == GameThread.STATE_RUNNING) { // method to check if the game is currently in a running state (something happening) if so the following happens | |
mEnemyY --;//oponent car is moved up the screen towards the top | |
mSpeedBoostY += 5; //point bonus (bolt) is moved down the screen at 5 speed | |
BackgroundY += 5; // the background image is moved down the screen at +5 | |
mBombY += 5; // the sad face is moved down the screen at +5 | |
if (mSpeedBoostY > mCanvasHeight) { // used to check is AI cars Y pos is above screen | |
mSpeedBoostY = 0; // if so resets it | |
} | |
if (mBombY > mCanvasHeight) { // checks sad face's Y pos | |
mBombY = 0; // if below screen reset | |
mBombX = randomPos(); // set X pos to random value | |
} | |
for (i = 0; i < secondsElapsed; i++) { | |
updateScore(1); // calls the update score method to update the score every second that player is alive. | |
} | |
} | |
if (BackgroundY > mCanvasHeight) { // checks the backgroung images y pos (from top left of image) | |
BackgroundY = 0; // if below screen top (top of canvas) reset to 0 | |
} | |
if (isCollide(mSpeedBoostX, mSpeedBoostY // used to check for collision, if the method isCollide == true, set collide to true, and add points | |
)) { | |
collide = true; | |
if (!collected) { // if true, score gets updated + 2000 | |
updateScore(2000); | |
collected = true; | |
mSpeedBoostY = 0; //reset point bonus Y pos | |
mSpeedBoostX = randomPos();// reset point bonus X pos to random value | |
//collide = false; | |
} | |
} | |
if (isCollide(mBombX, mBombY)) { | |
setState(GameThread.STATE_LOSE); // ends the game if the player contacts sad face | |
setScore(score); //updates the score. | |
} | |
if (collected) { // if point bonus = colected, reprint it to defailt X&Y pos | |
mSpeedBoostY = mCanvasHeight; | |
mSpeedBoostX = mCanvasWidth; | |
} | |
if (isCollide(mEnemyX, mEnemyY)) { | |
setState(GameThread.STATE_LOSE); //if player and AI car collide end game | |
collide = false; | |
} | |
// | |
// if(mBallX > mCanvasWidth) { | |
// setState(GameThread.STATE_LOSE); | |
// } | |
// if(mBallX < mCanvasWidth) { | |
// setState(GameThread.STATE_LOSE); | |
// } | |
} | |
public void getSize() { | |
mSpeedBoost.getHeight(); | |
mSpeedBoost.getWidth(); | |
// float size = mSpeedBoost.getHeight() * mSpeedBoost.getWidth(); //doesnt work. | |
} | |
public boolean ballCollide(){ | |
return mBallX >= mSpeedBoostX && mBallX <= mSpeedBoostX + Bwidth && mBallY >= mSpeedBoostY && mBallY <= mSpeedBoostY + Bheight; | |
} | |
public boolean bombCollide(){ | |
return mBallX > mBombX && mBallX < mBombX + Mwidth && mBallY > mBombY && mBallY < mBombY + Mheight; | |
} | |
public boolean isCollide(float x2, float y2) { | |
return mBallX +64 >= x2 && mBallX +64 <= x2 + Bwidth + 64 && mBallY +64 >= y2 && mBallY +64 <= y2 + Bheight +64; //generic collision detection boolean for all objects. | |
} | |
public void setVector(int dx) { | |
this.dx=dx; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment