I know my title is quite confusing but have no idea how I can ask this question in the most understandable. Hope you understand.
In my game there are 2 classes
"mainActivity" the game view.
"Game" extends the SurfaceView and implements Runnable (the game loop).
First screen displays with the button "Start New Game" and once you click on the button setContentView replaces its display view game.class.
So far everything is working properly. Now, suppose that the player lost I want to return to the main screen and as soon as he clicks the "Start New Game" game starts from beginning.
Currently clicking the back button "restart the game from the 0"
Here are my classes:
MainActivity:
public class MainActivity extends Activity implements OnTouchListener {
DialogPause pauseDialog;
public MyPreferences pref;
private TextView txCoins;
public Game game;
public static Music music;
ViewAnimator viewAnimator;
#SuppressLint("ClickableViewAccessibility")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pref = new MyPreferences(this);
music = new Music(this);
pauseDialog = new DialogPause(this);
setContentView(R.layout.menu);
view();
}
public void view(){
txCoins = (TextView)findViewById(R.id.txCoins);
txCoins.setText("Coins "+pref.getInt("coins"));
}
public void newGame(){
if(game != null){
game.destroyed();
}
game = new Game(this);
game.start();
game.setOnTouchListener(this);
setContentView(game);
}
public void click(View v){
newGame();
}
protected void onStart() {
super.onStart();
}
#Override
protected void onStop() {
music.StopBackgroundMusic();
super.onStop();
}
#Override
public void onBackPressed() {
newGame();
}
Game loop class:
public class Game extends SurfaceView implements Runnable{
public static MyPreferences pref;
public static Levels level;
public static int SCREEN_W;
public static int SCREEN_H;
public static boolean running;
public static boolean pause = false;
private Thread thread = null;
private SurfaceHolder holder;
private Canvas canvas;
private Paint p = new Paint();
public static Handler handler = new Handler();
public static Resources res;
public Timer timer;
public Game(Context context) {
super(context);
res = getResources();
holder = getHolder();
level = new Levels();
timer = new Timer();
pref = new MyPreferences(context);
System.out.println("Create Game instance");
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0;
double ns = 1000000000.0 / 30.0;
System.out.println("Run method" + running);
//Start looping...
while (running) {
//If it's not pause
long now = System.nanoTime();
delta+=(now - lastTime) / ns;
lastTime = now;
if(!holder.getSurface().isValid()){continue;}
canvas = holder.lockCanvas();
SCREEN_W = canvas.getWidth();
SCREEN_H= canvas.getHeight();
while (delta >-1) {
if(!pause)tick();
delta--;
}
level.level1();
render(canvas);
holder.unlockCanvasAndPost(canvas);
if(ControlPanel.PLAYER_POWER <=0){
System.out.println("Loose!");
ControlPanel.PLAYER_POWER = 100;
stop();
start();
}
}
}
private void render(Canvas c) {
handler.render(c);
textOnScreen(c);
}
public void tick(){
handler.tick();
}
public void init(){
ControlPanel.COINS = pref.getInt("coins");
MainActivity.music.backgroundMusic();
handler.addSpaceShip(new Player(500, 500, 10, 10, handler, Sprite.getSprite(0)));
// handler.addKing(new King(Game.SCREEN_W / 2, 100,
// 40, 40, handler, Sprite.getSprite(18), 0));
}
public void start() {
//If the tread are new one
if(thread==null){
thread = new Thread(this);
thread.start();
timer.start();
}
//if it not running
if(!running) {
pause = false;
running =true;
}
}
public void stop() {
pause = true;
running = false;
timer.stop();
pref.putInt("coins", ControlPanel.COINS);
}
public void pause() {
pause = true;
}
public void destroyed() {
System.out.println("Stop");
running = false;
this.stop();
}
public void textOnScreen(Canvas c){
p = new Paint();
p.setColor(Color.YELLOW);
p.setTextSize(50);
c.drawText("POWER = " + ControlPanel.PLAYER_POWER, SCREEN_W / 2 ,50 , p);
c.drawText("Time = " + timer.timeFormat(), 100 ,50 , p);
c.drawText("Coins = " + ControlPanel.COINS, 10 ,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText("Bullets = " +ControlPanel.BULLET, SCREEN_W - 390,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText(ControlPanel.Distance + " km ", SCREEN_W /2 - 200,SCREEN_H - 10 , p);
}
}
Please help!! I've been a week and a half and can not solve it :((
I suppose that you want to return to your first menu when it reaches System.out.println("Loose!"); because you said it already works quite well now. I donnot have time to read all the code but if it is what you want then you can try this solution. I added handler variable in each class to restart the program.
public class MainActivity extends Activity implements OnTouchListener {
DialogPause pauseDialog;
public MyPreferences pref;
private TextView txCoins;
public Game game;
public static Music music;
ViewAnimator viewAnimator;
Handler uiHandler = new Handler(){
#override
public void handleMessage (Message msg){
restart();
}
}
#SuppressLint("ClickableViewAccessibility")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pref = new MyPreferences(this);
music = new Music(this);
pauseDialog = new DialogPause(this);
setContentView(R.layout.menu);
view();
}
private void restart(){
setContentView(R.layout.menu);
view();
}
public void view(){
txCoins = (TextView)findViewById(R.id.txCoins);
txCoins.setText("Coins "+pref.getInt("coins"));
}
public void newGame(){
if(game != null){
game.destroyed();
}
game = new Game(this, handler);
game.start();
game.setOnTouchListener(this);
setContentView(game);
}
public void click(View v){
newGame();
}
protected void onStart() {
super.onStart();
}
#Override
protected void onStop() {
music.StopBackgroundMusic();
super.onStop();
}
#Override
public void onBackPressed() {
//newGame(); //comment out this
}
And Game class:
public class Game extends SurfaceView implements Runnable{
private Handler handler;
public static MyPreferences pref;
public static Levels level;
public static int SCREEN_W;
public static int SCREEN_H;
public static boolean running;
public static boolean pause = false;
private Thread thread = null;
private SurfaceHolder holder;
private Canvas canvas;
private Paint p = new Paint();
public static Handler handler = new Handler();
public static Resources res;
public Timer timer;
public Game(Context context, Handler handler) {
super(context);
this.handler = handler;
res = getResources();
holder = getHolder();
level = new Levels();
timer = new Timer();
pref = new MyPreferences(context);
System.out.println("Create Game instance");
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0;
double ns = 1000000000.0 / 30.0;
System.out.println("Run method" + running);
//Start looping...
while (running) {
//If it's not pause
long now = System.nanoTime();
delta+=(now - lastTime) / ns;
lastTime = now;
if(!holder.getSurface().isValid()){continue;}
canvas = holder.lockCanvas();
SCREEN_W = canvas.getWidth();
SCREEN_H= canvas.getHeight();
while (delta >-1) {
if(!pause)tick();
delta--;
}
level.level1();
render(canvas);
holder.unlockCanvasAndPost(canvas);
if(ControlPanel.PLAYER_POWER <=0){
System.out.println("Loose!");
ControlPanel.PLAYER_POWER = 100;
stop();
handler.sendEmptyMessage(0);//restart the game menu as u want
//start();//Comment out this
}
}
}
private void render(Canvas c) {
handler.render(c);
textOnScreen(c);
}
public void tick(){
handler.tick();
}
public void init(){
ControlPanel.COINS = pref.getInt("coins");
MainActivity.music.backgroundMusic();
handler.addSpaceShip(new Player(500, 500, 10, 10, handler, Sprite.getSprite(0)));
// handler.addKing(new King(Game.SCREEN_W / 2, 100,
// 40, 40, handler, Sprite.getSprite(18), 0));
}
public void start() {
//If the tread are new one
if(thread==null){
thread = new Thread(this);
thread.start();
timer.start();
}
//if it not running
if(!running) {
pause = false;
running =true;
}
}
public void stop() {
pause = true;
running = false;
timer.stop();
pref.putInt("coins", ControlPanel.COINS);
}
public void pause() {
pause = true;
}
public void destroyed() {
System.out.println("Stop");
running = false;
this.stop();
}
public void textOnScreen(Canvas c){
p = new Paint();
p.setColor(Color.YELLOW);
p.setTextSize(50);
c.drawText("POWER = " + ControlPanel.PLAYER_POWER, SCREEN_W / 2 ,50 , p);
c.drawText("Time = " + timer.timeFormat(), 100 ,50 , p);
c.drawText("Coins = " + ControlPanel.COINS, 10 ,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText("Bullets = " +ControlPanel.BULLET, SCREEN_W - 390,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText(ControlPanel.Distance + " km ", SCREEN_W /2 - 200,SCREEN_H - 10 , p);
}
}
Related
I'm trying to get more than one sprite on screen (two for now to see if I can get it going) but all it does is just display the one still.
My code is as follows (it's all in one class:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
/* Member (state) fields */
private GameLoopThread gameLoopThread;
private Paint paint; //Reference a paint object
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
// For creating the game Sprite
private Sprite sprite;
//For multiple sprites
private ArrayList<Sprite> spritesArrayList;
// For recording the number of hits
private int hitCount;
// For displaying the highest score
//private int highScore;
// To track if a game is over
private boolean gameOver;
// To play sound
private SoundPool mySound;
// Zap sound when sprite hit
int zapSoundId;
int count = 2;
int arraySize;
public GameView(Context context) {
super(context);
// Focus must be on GameView so that events can be handled.
this.setFocusable(true);
// For intercepting events on the surface.
this.getHolder().addCallback(this);
// Background image added
mBackgroundImage = BitmapFactory.decodeResource(this.getResources(), R.drawable.castle);
// Initialise sprites object
spritesArrayList = new ArrayList<Sprite>();
}
/* Called immediately after the surface created */
public void surfaceCreated(SurfaceHolder holder) {
for (int i = 0; i < count; i++) {
spritesArrayList.add(sprite);
}
// We can now safely setup the game start the game loop.
ResetGame();//Set up a new game up - could be called by a 'play again option'
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage, getWidth(), getHeight(), true);
gameLoopThread = new GameLoopThread(this.getHolder(), this);
gameLoopThread.running = true;
gameLoopThread.start();
}
// For the countdown timer
private long startTime; // Timer to count down from
private final long interval = 1 * 1000; // 1 sec interval
private CountDownTimer countDownTimer; // Reference to the class
private boolean timerRunning = false;
private String displayTime; // To display the time on the screen
public void getArrayListSize() {
if (spritesArrayList.isEmpty()) {
// nothing
} else {
arraySize = spritesArrayList.size();
}
}
//To initialise/reset game
private void ResetGame() {
/* Set paint details */
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
sprite = new Sprite(this);
hitCount = 0;
// Set timer
startTime = 10; // Start at 10s to count down
// Create new object - convert startTime to milliseconds
countDownTimer = new MyCountDownTimer(startTime * 1000, interval);
countDownTimer.start(); // Start the time running
timerRunning = true;
gameOver = false;
}
// Countdown Timer - private class
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer (long startTime, long interval) {
super(startTime, interval);
}
public void onFinish() {
//displayTime = "Time is up!";
timerRunning = false;
countDownTimer.cancel();
gameOver = true;
}
public void onTick (long millisUntilFinished) {
displayTime = " " + millisUntilFinished / 1000;
}
}
//This class updates and manages the assets prior to drawing - called from the Thread
public void update() {
if (gameOver != true) {
spritesArrayList.clear();
sprite.update();
}
for (int i = 0; i < spritesArrayList(); i++) {
sprite = new Sprite(this);
spritesArrayList.add(sprite);
}
}
private int spritesArrayList() {
return 0;
}
/*private void createSprites() {
sprites.add(createSprite(R.drawable.bad3));
sprites.add(createSprite(R.drawable.bad4));
sprites.add(createSprite(R.drawable.good2));
sprites.add(createSprite(R.drawable.good5));
}*/
/*private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}*/
/**
* To draw the game to the screen
* This is called from Thread, so synchronisation can be done
*/
#SuppressWarnings("ResourceAsColor")
public void doDraw(Canvas canvas) {
//Draw all the objects on the canvas
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
getArrayListSize();
for (int i = 0; i < arraySize; i++)
{
Sprite sprite = spritesArrayList.get(i);
sprite.draw(canvas);
}
if (!gameOver) {
sprite.draw(canvas);
paint.setColor(R.color.red);
canvas.drawText("Time Remaining: " + displayTime, 35, 50, paint);
canvas.drawText("Number of hits: " + hitCount, 250, 50, paint);
} else {
canvas.drawText("Game Over!", 185, 100, paint);
canvas.drawText("To go back to the main menu, press the 'back' key", 15, 150, paint);
}
}
//To be used if we need to find where screen was touched
public boolean onTouchEvent(MotionEvent event) {
if (sprite.wasItTouched(event.getX(), event.getY())) {
sprite = new Sprite(this);
hitCount++;
return true;
} else {
return true;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.running = false;
// Shut down the game loop thread cleanly.
boolean retry = true;
while(retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
public int getHitCount() {
return hitCount;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
}
If anyone would like me to clarify any of the code, please let me know.
Thanks
This question already has answers here:
Can I start a thread again after it has died?
(5 answers)
Closed 6 years ago.
I am creating a demo game in Android for learning purposes. In the game, when a collision is detected between two objects - I want to show a "game over" dialog. Inside the dialog box there is a play again button. When pressed, the thread should be started again.
I am getting the following error java.lang.IllegalThreadStateException: Thread already started .
Here is my code:
public class GamePanel extends SurfaceView implements Runnable {
private Thread thread = null;
private Ball ball;
private SurfaceHolder surfaceHolder;
private Paint paint;
private Canvas canvas;
volatile boolean playing = true;
private int hurdleCount = 3;
private Hurdles[] hurdles;
private int screenX, screenY;
private Rect ball_detectCollision;
public GamePanel(Context context, final int screenX, final int screenY) {
super(context);
ball = new Ball(context, screenX, screenY);
surfaceHolder = getHolder();
this.screenX = screenX;
this.screenY = screenY;
paint = new Paint();
canvas = new Canvas();
hurdles = new Hurdles[hurdleCount];
for (int i = 0; i < hurdleCount; i++) {
hurdles[i] = new Hurdles(context, screenX, screenY);
}
ball_detectCollision = new Rect(ball.getBall_x(), ball.getBall_y(), ball.getBitmap().getWidth(), ball.getBitmap().getHeight());
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("Surface Created");
setUpdated_x(ball.getBall_x());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("Surface Changed");
thread = new Thread(GamePanel.this);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("Surface Destroyed");
}
});
}
public int getUpdated_x() {
return updated_x;
}
public void setUpdated_x(int updated_x) {
this.updated_x = updated_x;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
setUpdated_x((int) event.getX());
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
initial_X = getUpdated_x();
break;
case MotionEvent.ACTION_MOVE:
if (getUpdated_x() < screenX - ball.getBitmap().getWidth() || getUpdated_x() > screenX - ball.getBitmap().getWidth()) {
draw(getUpdated_x());
}
break;
}
return true;
}
private void draw(int updatedValue) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.RED);
canvas.drawBitmap(ball.getBitmap(), updatedValue, ball.getBall_y(), paint);
ball.setBall_x(updatedValue);
ball_detectCollision.left = ball.getBall_x();
ball_detectCollision.top = screenY - ball.getBitmap().getHeight() - 260;
ball_detectCollision.right = ball.getBall_x() + ball.getBitmap().getWidth();
ball_detectCollision.bottom = screenY - ball.getBitmap().getHeight() - 260 + ball.getBitmap().getHeight();
for (int i = 0; i < hurdleCount; i++) {
canvas.drawBitmap(hurdles[i].getBitmap(), hurdles[i].getX(), hurdles[i].getY(), paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
#Override
public void run() {
while (playing) {
update();
draw(getUpdated_x());
control();
}
}
private void update() {
for (int i = 0; i < hurdleCount; i++) {
hurdles[i].update();
if (Rect.intersects(getBall_detectCollision(), hurdles[i].getDetectCollision())) {
System.out.println("Collision Detected");
playing = false;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
showGameOverMessage();
}
});
}
}
}
public void pause() {
playing = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void showGameOverMessage() {
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();
Dialog showDialog = new Dialog(getContext());
showDialog.setContentView(R.layout.dialog_game_over);
Button playAgainButton = (Button) showDialog.findViewById(R.id.playAgainButton);
playAgainButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
playing = true;
thread.start();
}
});
showDialog.show();
}
}
You can't restart a stopped thread. The solution is to simply instantiate a new one and start it.
When the game is over, just stop the thread and play again button should kick a new thread.
If you need to save any instance of your previous thread, do save them in external variables. There are plenty of options in this case anyway.
Edit
You stopped your thread perfectly. You just have to start a new thread when you want the new game to be started.
I would suggest to keep a function like this and remove implements Runnable.
private void startGame() {
// Start a new game
playing = true;
Thread thread = new Thread() {
#Override
public void run() {
try {
while (playing) {
update();
draw(getUpdated_x());
control();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
I know similar questions have been asked before but none of those solutions worked for me.
I'm trying to create a small 2D game for Android and I am having some problems using SurfaceView.
My main activity currently looks like this:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private DrawingSurface drawingsurface;
private Game game;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
setFullscreen();
game = new Game();
drawingsurface = new DrawingSurface(this, game);
setContentView(drawingsurface);
}
private void setFullscreen() {
// ...
}
}
As you can see, I set my activity to fullscreen, create a new SurfaceView (called drawingSurface) and create a new game instance.
My SurfaceView (called DrawingSurface) looks like this:
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
private GameThread thread;
private static final String TAG = "DrawingSurface";
public DrawingSurface(Context context, Game game) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
// create a new game rendering thread and pass it game so it can call the update() and render() functions of game:
thread = new GameThread(getHolder(), this, game);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated()");
// start the rendering thread:
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.v(TAG, "surfaceChanged()");
// do I need to do anything in here?
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// stop the rendering thread:
Log.v(TAG, "surfaceDestroyed()");
thread.setRunning(false);
boolean retry = true;
while (retry) {
try {
thread.join();
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// pass the touch event to the Game instance (to keep everything in on place)
thread.game.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
// I don't use onDraw(), instead I have my own update() and render() functions in my game thread
super.onDraw(canvas);
}
}
This is my game thread:
public class GameThread extends Thread {
private boolean running;
private SurfaceHolder surfaceHolder;
private DrawingSurface drawingSurface;
private static final String TAG = GameThread.class.getSimpleName();
protected Game game;
public GameThread(SurfaceHolder surfaceHolder, DrawingSurface drawingSurface, Game game) {
super();
this.surfaceHolder = surfaceHolder;
this.drawingSurface = drawingSurface;
this.game = game;
}
public void setRunning(boolean running) {
this.running = running;
}
#SuppressLint("WrongCall")
#Override
public void run() {
Log.d(TAG, "Starting game loop");
long now;
long dt;
long last = System.currentTimeMillis();
Canvas canvas;
while (running) {
Log.v(TAG, "GameThread running");
canvas = null;
/* try locking the canvas for exclusive
pixel editing in the surface */
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
now = System.currentTimeMillis();
dt = (now - last);
this.game.update(dt);
if(canvas != null)
this.game.render(canvas, dt);
last = now;
}
} finally {
/*in case of an exception the surface
is not left in an inconsistent state */
if (canvas != null) {
this.surfaceHolder.unlockCanvasAndPost(canvas);
}
}
if (dt < 16) {
try {
Thread.sleep(16 - dt);
} catch (InterruptedException e) {
}
}
}
}
}
And this is the Game class:
public class Game {
private static final String TAG = "Game";
private static int playerRefPosX = 40;
private int playerY = 0;
private int playerVelY = 1;
public Game() {
Log.v(TAG, "Game instance created");
}
public void update(long dt) {
playerY += playerVelY * dt;
if (playerY > 1800) {
playerVelY = -playerVelY;
}
if (playerY < 0) {
playerVelY = -playerVelY;
}
}
public void render(Canvas canvas, long dt) {
canvas.drawColor(Color.BLACK);
// draw Player
Paint paint = new Paint();
paint.setTextSize(100);
paint.setColor(new Color().rgb(255, 0, 0));
canvas.drawRect(playerRefPosX, playerY + 100, playerRefPosX + 200, playerY - 100, paint);
canvas.drawText(String.valueOf(1000/dt), canvas.getWidth()/2, canvas.getWidth()/2, paint);
}
public void onTouchEvent(MotionEvent event) {
Log.v(TAG, "received touch event..");
}
}
The problems I am have right now:
When I press the home button and reenter the app OR rotate my device it calls surfaceDestroyed() but doesn't recreate it afterwards (the canvas doesn't get repainted)
The game rendering thread never stops (as indicated by the log messages)
I am new in developing games, i trying to develop a simple shooting space game and everything works perfect. now, i want to create a Dialog popup when the user click on the back button and the game should pause until the user press resume. the game is paused but when i click the resume button the game still on pause here is my game Loop class:
public class Game extends SurfaceView implements Runnable , SurfaceHolder.Callback {
public static MyPreferences pref;
public static Levels level;
public static int SCREEN_W;
public static int SCREEN_H;
public static boolean running;
private static Thread thread = null;
private SurfaceHolder holder;
private Canvas canvas;
private Paint p = new Paint();
public static Handler handler = new Handler();
public static Resources res;
public static Timer timer;
public Game(Context context) {
super(context);
res = getResources();
holder = getHolder();
holder.addCallback(this);
level = new Levels();
timer = new Timer();
pref = new MyPreferences(context);
System.out.println("Create Game instance");
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0;
double ns = 1000000000.0 / 30.0;
System.out.println("Run method" + running);
while (running) {
System.out.println("+++++++++++++++++++++++++++++++++++");
long now = System.nanoTime();
delta+=(now - lastTime) / ns;
lastTime = now;
if(!holder.getSurface().isValid()){continue;}
canvas = holder.lockCanvas();
SCREEN_W = canvas.getWidth();
SCREEN_H= canvas.getHeight();
while (delta >-1) {
tick();
delta--;
}
level.level1();
render(canvas);
holder.unlockCanvasAndPost(canvas);
if(ControlPanel.PLAYER_POWER <=0){
System.out.println("Loose!");
ControlPanel.PLAYER_POWER = 100;
stop();
start();
}
}
}
private void render(Canvas c) {
handler.render(c);
textOnScreen(c);
}
public void tick(){
handler.tick();
}
public void init(){
System.out.println("Init game...");
ControlPanel.COINS = pref.getInt("coins");
MainActivity.music.backgroundMusic();
handler.addSpaceShip(new Player(500, 500, 10, 10, handler, Sprite.getSprite(0)));
// handler.addKing(new King(Game.SCREEN_W / 2, 100,
// 40, 40, handler, Sprite.getSprite(18), 0));
}
public void start() {
if(thread==null){
System.out.println("Start thread");
thread = new Thread(this);
thread.start();
timer.start();
}
if(!running) running = true;
System.out.println("Running = " + running);
}
public static void stop() {
System.out.println("Stop thread");
running = false;
timer.stop();
pref.putInt("coins", ControlPanel.COINS);
System.out.println("Running = " + running);
}
public void destroyed() {
System.out.println("Stop");
running = false;
try {
thread.join(300);
thread.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void textOnScreen(Canvas c){
p = new Paint();
p.setColor(Color.YELLOW);
p.setTextSize(50);
c.drawText("POWER = " + ControlPanel.PLAYER_POWER, SCREEN_W / 2 ,50 , p);
c.drawText("Time = " + timer.timeFormat(), 100 ,50 , p);
c.drawText("Coins = " + ControlPanel.COINS, 10 ,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText("Bullets = " +ControlPanel.BULLET, SCREEN_W - 390,SCREEN_H - 10 , p);
p.setColor(Color.WHITE);
c.drawText(ControlPanel.Distance + " km ", SCREEN_W /2 - 200,SCREEN_H - 10 , p);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("###surface created!");
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
System.out.println("###surface Changed!");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("###surface Destroid!");
}
}
and here is my Dialog class:
public class DialogPause extends Dialog implements android.view.View.OnClickListener{
Button btn;
public DialogPause(Context context) {
super(context);
setContentView(R.layout.pause_game);
Game.running = false;
btn = (Button) findViewById(R.id.resume);
btn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.resume){
Game.running = true;
this.dismiss();
}
}
}
and my MainActivity class:
public class MainActivity extends Activity implements OnTouchListener {
public Game game;
public static Music music;
#SuppressLint("ClickableViewAccessibility")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Full screen
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
music = new Music(this);
game = new Game(this);
game.setOnTouchListener(this);
setContentView(game);
}
protected void onStart() {
game.start();
super.onStart();
}
#Override
protected void onStop() {
music.StopBackgroundMusic();
game.destroyed();
super.onStop();
}
#Override
public void onBackPressed() {
new DialogPause(this).show();
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
try {
//the x and y point
float x = event.getX();
float y = event.getY();
//The w and h of the space ship
int spaceShipW = Game.handler.spaceShip.get(0).getSprite().getWidth();
int spaceShipH = Game.handler.spaceShip.get(0).getSprite().getWidth();
//Moving
if( x > 10 || x > Game.SCREEN_W - spaceShipW ){
Game.handler.spaceShip.get(0).setX((int) x - (spaceShipW / 2) - 64);
Game.handler.spaceShip.get(0).setY((int) y - (spaceShipH +200) );
}
//Shooting
Bullet.shoot(y, x);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
//Change sprite image when click
Game.handler.spaceShip.get(0).getSprite().setWhatColumnX(0);
Game.handler.spaceShip.get(0).getSprite().setFramesToAnimate(2);
case MotionEvent.ACTION_MOVE :
break;
case MotionEvent.ACTION_UP :
//Change sprite image when release
Game.handler.spaceShip.get(0).getSprite().setWhatColumnX(1);
Game.handler.spaceShip.get(0).getSprite().setFramesToAnimate(0);
break;
default:
break;
}
} catch (Exception e) {
}
return true;
}
}
By the way i will like to hear more opinions of my game loop code I created because I have sometimes crashes when I exit the game.
and how can i use some asyncTask when the game is finished to load because it's take a 4 sec until the game is load.
Thanks to all who help me I am very appreciate it!
Add a boolean value paused and whenever the back button is pressed toggle the value (paused = !paused;)
And in you loop before you call tick add a condition:
if(!paused) tick();
It's better to simply not mess with the thread.
How might I draw a graph of a function (for example, y = x^2 or y = (x +1)/(2*x +3)) on a Canvas in an Android app?
Here you have an example code ;D (plots the f(x)=x^3 function)
A sample thread that plots the function.
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;
private Paint paintRed;
private Paint paintBlue;
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.paintRed = new Paint();
this.paintRed.setColor(Color.RED);
this.paintRed.setStrokeWidth(1);
this.paintBlue = new Paint();
this.paintBlue.setColor(Color.BLUE);
this.paintBlue.setStrokeWidth(1);
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
class MeasuredAxis {
public static final int X_GAP = 1;
public static final int Y_GAP = 1;
int _realHeight;
int _realWidth;
public MeasuredAxis(int width, int height) {
_realWidth = width;
_realHeight = height;
}
public int getXAxisNegLimit() {
return (_realWidth / 2)*(-1);
}
public int getXAxisLimit() {
return (_realWidth / 2);
}
public float getXMeasured(int x) {
return ((_realWidth / 2) + x);
}
public float getYMeasured(float y) {
return ((_realHeight / 2) - y);
}
}
private float function(float x) {
return new Double(Math.pow(x, 3)).floatValue();
}
#Override
public void run() {
long fps = 0L;
Log.d(TAG, "Starting game loop");
Canvas canvas = surfaceHolder.lockCanvas();
MeasuredAxis measured = new MeasuredAxis(canvas.getWidth(), canvas.getHeight());
synchronized (canvas) {
int x = measured.getXAxisNegLimit();
//from -x to +x evaluate and plot the function
while (x++ < measured.getXAxisLimit()) {
canvas.drawLine(
measured.getXMeasured(x),
measured.getYMeasured(function(x)),
measured.getXMeasured(x+MeasuredAxis.X_GAP),
measured.getYMeasured(function(x+MeasuredAxis.Y_GAP)),
paintRed);
}
canvas.save();
canvas.translate(0, 0);
canvas.scale(canvas.getWidth(), canvas.getHeight());
canvas.restore();
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
A sample surface view where the function is drawn.
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private MainThread thread;
public MainGamePanel(Context context) {
super(context);
getHolder().addCallback(this);
// create the game loop thread
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
}
}
And an example activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MainGamePanel(this));
}
}
Hope this helps you!