Issues with my Android custom sprite Class - java

I am currently designing a basic sprite class for java for android because for I don't wish to use a 2d engine and Google doesn't provide any sprite APIs for some reason...
Anyways, my question is in regards to my Classes I have designed. I have a Sprite Class that takes a bitmap and turns it into a "sprite". This sprite can then be passed to a custom view I have created when the user creates a new "SpriteContainer"
My code for the DynamicSpriteContainer is as follows:
package com.me.spriteGraphics;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class DynamicSpriteContainer extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
public int x, y;
private Bitmap b;
public Sprite sprite;
private Canvas c = new Canvas();
private boolean bool = false;
public DynamicSpriteContainer(Context context, Sprite spriteImage) {
//public ImageView(Context context) {
super(context);
//get sprite
b = spriteImage.getBitmap();
//set holder
holder = getHolder();
holder.addCallback(this);
//set position
x = y = 0;
update();
}
public void surfaceCreated(SurfaceHolder holder) {
c = holder.lockCanvas();
c.drawARGB(255, 150, 150, 10);
//set up bitmap image
c.drawBitmap(b, x, y, null);
holder.unlockCanvasAndPost(c);
update();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
private void update() {
//this code will alter the character in the way the developer specifies (per frame)
Thread repeat = new Thread( new Runnable() {
public void run() {
try {
//move sprite in constant motion
while (bool) {
//redraw
c = holder.lockCanvas();
c.drawARGB(255, 150, 150, 10);
//set up bitmap image
c.drawBitmap(b, x, y, null);
holder.unlockCanvasAndPost(c);
}
} catch (Error e) {
e.printStackTrace();
bool = false;
}
}
});
repeat.start();
}
public void setX(int x) {
//notice how this same code above has the holder, the holder is recognized above, not here.
c = holder.lockCanvas();
c.drawARGB(255, 150, 150, 10);
//set up bitmap image
c.drawBitmap(b, x, y, null);
holder.unlockCanvasAndPost(c);
}
//set the info on pause, resume, stop...
//this data is for error stopping, so the app can resume and stop without passing an error to the user!
public void passInfo(boolean isPaused, boolean isResumed, boolean isStopped) {
if (isPaused && sprite.auto) {
bool = false;
}
if (isResumed && sprite.auto) {
bool = true;
}
if (isStopped && sprite.auto) {
bool = false;
}
}
}
Sorry for the long code excerpt.
The main issue is that inside the update() function, the holder is recognized, but inside the setX(), it's not...
How can I have the setX() recognize the holder?
Thank you soo much in advance!!!

Related

Array list for sprites in android game/app

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

Android: SurfaceView stops repainting after surfaceDestroyed()

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)

Make a sprite jump

I want to make a sprite\bitmap jump using only android (no game engines). I wasn't able to find tutorials on how to do so in android using only canvas and views, but I did find a tutorial for xna(http://www.xnadevelopment.com/tutorials/thewizardjumping/thewizardjumping.shtml), and I tried to recreate it with the tools android offers. I was able to make the character move left and right using the tutorial code but making it jump just won't work.
this is my sprite class:
package com.example.spiceup;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.view.KeyEvent;
import android.widget.Toast;
public class Sprite {
enum State
{
Walking, Standing, Jumping
}
State mCurrentState = State.Standing;
Point mDirection;
int mSpeed = 0;
Context cc;
int mPreviousKeyboardState;
private String spriteName;
Bitmap sprite;
private int rows;
private int rows2;
int START_POSITION_X = 125;
int START_POSITION_Y = 245;
int SPRITE_SPEED = 6;
int MOVE_UP = -1;
int MOVE_DOWN = 1;
int MOVE_LEFT = -1;
int MOVE_RIGHT = 1;
Point mStartingPosition;
int aCurrentKeyboardState;
private float mScale = 1.0f;
Point Position;
public Sprite(String name,Bitmap sprite) {
this.sprite=sprite;
this.spriteName=name;
Position=new Point(150,150);
mStartingPosition=new Point(150,150);
mDirection=new Point(0,0);
}
public void Update()
{
UpdateMovement(aCurrentKeyboardState);
UpdateJump(aCurrentKeyboardState);
}
public void setkeyboard(int keyboard){
aCurrentKeyboardState = keyboard;
}
public void setLastKeyboard(int keyboard){
mPreviousKeyboardState = keyboard;
}
private void UpdateMovement(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
mSpeed = 0;
mDirection.x = 0;
if (aCurrentKeyboardState==KeyEvent.KEYCODE_A)
{
mSpeed = SPRITE_SPEED;
mDirection.x = MOVE_LEFT;
}
else if(aCurrentKeyboardState==KeyEvent.KEYCODE_D)
{
mSpeed = SPRITE_SPEED;
mDirection.x= MOVE_RIGHT;
}
Position.x += mDirection.x * mSpeed;
}
}
private void UpdateJump(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
if (aCurrentKeyboardState==KeyEvent.KEYCODE_SPACE && mPreviousKeyboardState!=KeyEvent.KEYCODE_SPACE)
{
Jump();
}
}
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
Position.y += mDirection.y * mSpeed;
mDirection.y = MOVE_DOWN;
}
if (Position.y > mStartingPosition.y)
{
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
}
private void Jump()
{
if (mCurrentState != State.Jumping)
{
mCurrentState = State.Jumping;
mStartingPosition = Position;
mDirection.y = MOVE_UP;
mSpeed = 6;
Position.y += mDirection.y * mSpeed;
}
}
public void Draw(Canvas c)
{
c.drawBitmap(sprite, Position.x,Position.y, null);
}
public void setmCurrentState(State mCurrentState) {
this.mCurrentState = mCurrentState;
}
}
this is the surfaceview:
import com.example.spiceup.Sprite.State;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
Context cc;
Bitmap Sprite;
Sprite sprite2;
Handler handlerAnimation100;
private GameLoopThread gameLoopThread;
private SurfaceHolder holder;
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
gameLoopThread = new GameLoopThread(this);
this.cc=c;
this.Sprite=BitmapFactory.decodeResource(getResources(), R.drawable.walk1);
this.Sprite=Bitmap.createScaledBitmap(Sprite, Sprite.getWidth()*2, Sprite.getHeight()*2, false);
sprite2=new Sprite("Spicy",Sprite);
this.requestFocus();
this.setFocusableInTouchMode(true);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
sprite2.Update();
sprite2.Draw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
sprite2.setkeyboard(keyCode);
sprite2.setmCurrentState(State.Walking);
return false;
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
sprite2.setmCurrentState(State.Standing);
sprite2.setLastKeyboard(keyCode);
return false;
}
}
if anyone knows where is my error or has a better code to show me I'll be happy, all I'm trying to do is to create a bitmap that moves around and can jump (but also jump while walking)
So I think what is happening in your code is that it's hitting the max height in the game loop and adding back to the y of the sprite. Second game loop run it is no longer above or near the max height distance therefore you stop going down and your start position becomes that position in the air. On a third loop through you hit spacebar again and your sprite starts the whole jumping processes over and the same thing happens on the next to loops through or however many it takes to trigger that if statement to get the sprite to start falling.
Good place to start is have a persistent boolean that determines whether or not the sprite is actually done climbing and jumping state should stay true while climbing and falling. See below.
boolean maxJumpAchieved = false;
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
maxJumpAchieved = true;
}
if (maxJumpAchieved) {
mDirection.y = MOVE_DOWN;
Position.y += mDirection.y * mSpeed;
}
if (Position.y > mStartingPosition.y)
{
maxJumpAchieved = false;
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
I think this should get you in the right direction but if you have issues let me know and I can edit my answer.
Another thing to note is don't set the mCurrentState to State.Walking until you know for sure you're on the ground otherwise you could double jump for days.

Android: How can I multiply a class and create different instances of its variables?

I'm new to Java, so I hope it's not a silly question. I have a class called "Enemy".
I know how to multiply the class, I use the "for" loop. Now, the problem is that the variables x and y (the one's that move the bitmap) have the same values for every instance of the class. And I want them to be different in order to create some "randomness".
The main class:
public class MainActivity extends Activity{
Player ourView;
#SuppressLint("ClickableViewAccessibility") protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
ourView = new Player(this);
setContentView(ourView);
}
protected void onPause() {
super.onPause();
ourView.pause();
}
protected void onResume() {
super.onResume();
ourView.resume();
}
}
Here's the "Player" class:
public class Player extends SurfaceView implements Runnable {
Canvas canvas = new Canvas();
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = true;
public Player(Context context) {
super(context);
ourHolder = getHolder();
ourThread = new Thread(this);
ourThread.start();
}
public void pause() {
isRunning = false;
while(true){
try{
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume() {
isRunning = true;
}
public void run() {
while(isRunning) {
if(!ourHolder.getSurface().isValid())
continue;
canvas = ourHolder.lockCanvas();
canvas.drawRGB(30, 30, 200);
Enemy[] enemy = new Enemy[3];
for(int i = 0; i<enemy.length; i++){
enemy[i] = new Enemy(null);
enemy[i].draw();
}
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
And here's the "Enemy" class:
public class Enemy extends Player{
public Enemy(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
float x,y = (float) (Math.random()*200);
public void draw(){
Bitmap bitmap = (Bitmap) BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, x, y, null);
}
}
I've also tried to declare those variables inside the "Enemy" class, but they just don't work. The bitmap stays in (0,0).
NOTE: The "Player" and "Enemy" class are declared inside the "MainActivity" class.
Your Enemy class should not extend the Player class since they don't share any similarities except the canvas and the context.
A possible implementation of your Enemy could look like this:
public class Enemy {
private Bitmap bitmap;
private Canvas canvas;
private Context context;
private float x, y;
public Enemy(Canvas canvas, Context context) {
bitmap = BitmapFactory.decodeResource(
context.getResources(), R.drawable.ic_launcher);
x = (float) (Math.random() * 200);
y = (float) (Math.random() * 200);
}
public void draw() {
canvas.drawBitmap(bitmap, x, y, null);
}
public void printCoordinates() { // just used for printing
System.out.println("x = " + x + " / y = "+ y);
}
}
Your Player class just need a minor adjustment to create proper Enemy classes:
Enemy[] enemy = new Enemy[3];
for(int i = 0; i < enemy.length; i++){
enemy[i] = new Enemy(canvas, context);
enemy[i].printCoordinates(); // just used for printing the generated coordinates
enemy[i].draw();
}
You just have to provide proper canvas and context instances for the new Enemy instance. You may also drop the context instance since you (currently) don't use it anythere in that class.
This is an example print of above code:
x = 27.236885 / y = 7.8905525
x = 61.842735 / y = 158.4654
x = 186.16629 / y = 20.208426
If you really want to extend the Player class, then you can still do that. This won't change much in your Enemy class.

Android nothing being drawn when onDraw is called?

Ok, so I've been working on a little game, and there's a problem in the rendering code. So, I tried to follow a tutorial for working with the SurfaceView, and so this is what I have so far:
GameSurface.java
package com.spng453.afirelitroom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
private GameThread thread;
public SurfaceHolder surfaceHolder;
DisplayMetrics metrics = GameActivity.metrics;
final private int sX = metrics.widthPixels;
final private int sY = metrics.heightPixels;
private Paint mainBTheme = new Paint();
Rect fireButton = new Rect(0, sY/2+50, sX, sY/2-50);
public GameSurface(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
this.setWillNotDraw(false);
thread = new GameThread(surfaceHolder, this);
this.setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.run();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean done = false;
while(!done) {
try {
thread.join();
done = true;
}
catch (InterruptedException e) {
}
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 0);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return true;
}
}
and the code in
GameThread.java:
package com.spng453.afirelitroom;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
public class GameThread extends Thread {
DisplayMetrics metrics = GameActivity.metrics;
final private int sX = metrics.widthPixels;
final private int sY = metrics.heightPixels;
private int FPS = 30;
private boolean running;
public SurfaceHolder surfaceHolder;
public GameSurface gameSurface;
public Canvas canvas;
private long firstTime = 0L, secondTime = 0L; //fps stuff
private Paint mainBTheme = new Paint();
//fire page
Rect fireButton = new Rect(0, sY/2+50, sX, sY/2-50);
Rect leftButton = new Rect();
Rect rightButton = new Rect();
//city/resources page
public void setRunning(boolean running) {
this.running = running;
}
public GameThread(SurfaceHolder surfaceHolder, GameSurface gameSurface) {
super();
this.surfaceHolder = surfaceHolder;
this.gameSurface = gameSurface;
mainBTheme.setColor(Color.BLACK);
}
#Override
public void run() {
while (running) {
//hey i guess i have to cap fps :(
firstTime = System.nanoTime();
//do the game here
canvas = null;
canvas = surfaceHolder.lockCanvas();
gameSurface.onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
secondTime = System.nanoTime();
if (secondTime/1000000 - firstTime/1000000 < 1000/FPS) { //the if the lag is less than the distance between frames at 30 fps
try {
Thread.sleep(1000/FPS - (secondTime/1000000 - firstTime/1000000));
} catch (InterruptedException e) {
}
}
}
}
}
So, my problem is that when I try to call onDraw in the GameThread here:
canvas = null;
canvas = surfaceHolder.lockCanvas();
gameSurface.onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
it does absolutely nothing. It doesn't draw whatever I put in onDraw, though if I put a Log call in the onDraw I know it executes. It doesn't produce an error message, either. Thanks for help in advanced!
Try this:
Change your method:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 0);
}
By this:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 0);
super.onDraw(canvas);
}
Also, try change this lines:
//do the game here
canvas = null;
canvas = surfaceHolder.lockCanvas();
gameSurface.onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
By this ones:
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
gameSurface.onDraw(canvas);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
Also keep note that the while loop it's running really fast no giving chance to draw the canvas. The thread sleep isn't working very well. Look at this resources, there is explained how do the game loop properly. And if you wanna test it right now, just erase the while.
Android game loop explained
Android game basic structure
Hope this helps :]
Okay, so it turns out that it was a problem with the FPS code executing too fast. I solved it by doing this:
#Override
public void run() {
// TODO Auto-generated method stub
final int fps = 30;
Timer fpsTimer = new Timer();
fpsTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Canvas canvas;
canvas = null;
try {
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}, 0, 1000/fps);
}

Categories

Resources