public class GameView extends SurfaceView
{
private GameThread mThread;
SurfaceHolder holder;
Bitmap fon = BitmapFactory.decodeResource(getResources(), R.drawable.fon);
ArrayList<Integer> lasers = new ArrayList<Integer>();
ArrayList<Integer> coordYlasers = new ArrayList<Integer>();
ArrayList<Integer> coordXlasers = new ArrayList<Integer>();
Bitmap laser = BitmapFactory.decodeResource(getResources(), R.drawable.laser);
int touchX = 0;
int touchY = 0;
int coordX = 0;
int coordY = 600;
int _coordX = 0;
private boolean running = false;
ArrayList<Bitmap> blocks = new ArrayList<Bitmap>();
public class GameThread extends Thread
{
private GameView view;
public GameThread(GameView view)
{
this.view = view;
}
public void setRunning(boolean run)
{
running = run;
}
public void run()
{
int i = 0;
while (running)
{
Canvas canvas = null;
try
{
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder())
{
onDraw(canvas);
}
}
catch (Exception e) { }
finally
{
if (canvas != null)
{
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
public GameView(Context context)
{
super(context);
mThread = new GameThread(this);
getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
mThread.setRunning(true);
mThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
}
public boolean onTouchEvent(MotionEvent event)
{
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
_coordX = coordX;
X = (int) event.getX();
Y = (int) event.getY();
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
touchX = ((int) event.getX());
touchY = (int) event.getY();
//if (Math.abs(touchX - X) > 10){
coordX = _coordX + (touchX - X);
invalidate();
//}
}
if(event.getAction() == MotionEvent.ACTION_UP)
{
_coordX = coordX;
Y = touchY;
}
return true;
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setTextSize(20);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(fon, 0, 0, null);
canvas.drawBitmap(player, coordX, coordY, null);
canvas.drawBitmap(laser, coordLaserX, coordLaserY, null);
for (int i = 1; i<coordYlasers.size(); ++i){
canvas.drawBitmap(laser, coordXlasers.get(i), coordYlasers.get(i), null);
}
canvas.drawText("" + V, 10, 25, paint);
}
}
Application is worked excellent, but....
If I hide app, game crashes. Help, please.
Logcat error.
5553-5553/com.example.thetronuo.pregame E/AndroidRuntime﹕ FATAL
EXCEPTION: main
java.lang.IllegalThreadStateException: Thread already started.
at java.lang.Thread.start(Thread.java:1045)
at com.example.thetronuo.pregame.GameView$1.surfaceCreated(GameView.java:161)
at android.view.SurfaceView.updateWindow(SurfaceView.java:569)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:231)
at android.view.View.dispatchWindowVisibilityChanged(View.java:7618)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1211)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4356)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
at android.view.Choreographer.doCallbacks(Choreographer.java:562)
at android.view.Choreographer.doFrame(Choreographer.java:532)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5099)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:803)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:570)
at dalvik.system.NativeStart.main(Native Method)
It's activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new GameView(this));
}
"wait()" - unhandled exception.
Where to write "resumeThread()"?
public class GameThread extends Thread
{
private GameView view;
private boolean pause = false;
private synchronized void check(){
while(pause){
wait();
}
}
public void pauseThread(){
pause = true;
}
public void resumeThread(){
pause = false;
notify();
}
public GameThread(GameView view)
{
this.view = view;
}
I think I had the same problem. But i fixed it.
Put a this in your Thread class:
private boolean pause = false;
private synchronized void check(){
while(pause){
wait();
}
}
public void pauseThread(){
pause = true;
}
public void resumeThread(){
pause = false;
notify();
}
And when onSurfaceDestroyed is called you need to pause the thread with the method youve created: pauseThread();
also call the method check(); in the while-loop, so:
while(true){
check();
... other code ...
}
and create a onResume() method in the activity class, so whenever the user turns back to the app, it will call this method automatically, and put this code into the method:
resumeThread();
I hope this would help you, im not sure if it is all the code you need as im not at home at the moment, if it doesnt work ill have a look and edit when im at home.
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have been trying for some time now to get a variable from MySurfaceView to use in my Player class. I cant seem to make it work... I tried getting the touch information from my MainActivity class but it wasn't really where I wanted it and also couldn't seem to make it work. Any help is appreciated!
MySurfaceView.java
package com.Frenchie.SurfaceView;
import ...
public class MySurfaceView extends SurfaceView implements Runnable {
Bitmap bitmap;
SurfaceHolder surfaceHolder;
int LastTouchx;
Player player;
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
#Override
public void run() {
//TODO movement here when display is working
while (true){
Update();
DrawPlayer();
}
}
public void Update(){
player.Update();
}
public void DrawPlayer(){
Canvas canvas = surfaceHolder.lockCanvas();
if (surfaceHolder.getSurface().isValid()) {
canvas.drawColor(Color.BLUE);
canvas.drawBitmap(player.getBitmap(), player.getX(), player.getY(), null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
else{
Log.d("DrawPlayer", "Surface Not Valid");
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
LastTouchx = (int)event.getX();
//LastTouchy= (int)event.getY();
Log.d("Touch Value ",LastTouchx+"");
return false;
}
public int getLastTouchx() {
return LastTouchx;
}
}
Player.java
package com.Frenchie.SurfaceView;
import ...
public class Player {
//Bitmap to get character from image
private Bitmap bitmap;
//coordinates
private int x;
private int y;
//motion speed of the character
private int speed = 0;
MySurfaceView mySurfaceView;
//constructor
public Player(Context context) {
x = 75;
y = 500;
//Getting bitmap from drawable resource
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
}
//Method to update coordinate of character
public void Update(){
//updating x coordinate
if (x > mySurfaceView.getLastTouchx()){
x++;
}
else if (x < mySurfaceView.getLastTouchx()){
x--;
}
else{
Log.d("Update","Else triggered");
}
}
public Bitmap getBitmap() {
return bitmap;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Messages
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.Frenchie.SurfaceView, PID: 26348
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.Frenchie.SurfaceView.MySurfaceView.getLastTouchx()' on a null object reference
at com.Frenchie.SurfaceView.Player.Update(Player.java:36)
at com.Frenchie.SurfaceView.MySurfaceView.Update(MySurfaceView.java:68)
at com.Frenchie.SurfaceView.MySurfaceView.run(MySurfaceView.java:62)
at java.lang.Thread.run(Thread.java:762)
This was not a duplicate of the post suggested.
Override another constructor in your MySurfaceView:
public class MySurfaceView extends SurfaceView
...
public MySurfaceView(Context context) {
this(context, (AttributeSet)null)
}
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context, this);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
...
In your player in constructor you can pass a surfaceView: so no need to initialize:
MySurfaceView mySurfaceView;
//constructor
public Player(Context context, MySurfaceView surfaceView) {
this.mySurfaceView = surfaceView;
x = 75;
...
Try:
MySurfaceView mySurfaceView = new MySurfaceView();
My android app is crashing when using SharedPreferences to try and carry the final score over from when the game ends. The app crashes inside the onTouchEvent at the line.
SharedPreferences.Editor editor = mySharedPreferences.edit();
The idea is when the game ends it final score that is within the SVGameView to carry over into the SVGameOver class and display there. If anyone could give some advice that would be great!
SVGameView:
public class SVGameView extends SurfaceView implements Runnable {
private SurfaceHolder holder;
Thread thread = null;
volatile boolean running = false;
static final long FPS = 30;
private Sprite sprite;
private long lastClick;
private Bitmap ball, gameOver;
//private int x = 200, y = 200;
private int scorePosX = 100;
private int scorePosY = 100;
private int countScore = 0;
private int life = 1;
SharedPreferences mySharedPreferences;
public SVGameView(Context context) {
super(context);
thread = new Thread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
running = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
running = true;
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball2);
gameOver = BitmapFactory.decodeResource(getResources(),R.drawable.endscreen);
sprite = new Sprite(this, ball);
context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = getHolder().lockCanvas();
synchronized (getHolder()) {
update();
onDraw(c);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
thread.sleep(sleepTime);
else
thread.sleep(10);
} catch (Exception e) {}
}
}
private void update(){
sprite.update();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.drawPaint(paint);
paint.setColor(Color.WHITE);
paint.setTextSize(48);
canvas.drawText("Score: " + countScore, scorePosX, scorePosY, paint);
canvas.drawText("Lives: " + life, 500, 100, paint);
sprite.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(System.currentTimeMillis()-lastClick > 300){
lastClick = System.currentTimeMillis();
}
synchronized (getHolder()){
if(sprite.isHit(event.getX(), event.getY())){
countScore += 1;
sprite.increase();
}else{
life --;
}
}
if(life == 0) {
getContext().startActivity(new Intent(getContext(), SVGameOver.class));
//Intent intent;
//intent = new Intent(getContext(), SVGameView.class);
//intent.putExtra("scoreOutput", countScore);
//Crashes Here
SharedPreferences.Editor editor = mySharedPreferences.edit();
editor.putString("cScore", String.valueOf(countScore));
}
return super.onTouchEvent(event);
}
}
SVGameOver Class:
public class SVGameOver extends Activity implements View.OnClickListener{
Button btnBack;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
btnBack = (Button)findViewById(R.id.btnBack);
btnBack.setOnClickListener(this);
SharedPreferences mySharedPreferences = getSharedPreferences("myPrefsFile", 0);
String theScore = mySharedPreferences.getString("cScore","");
TextView textView = (TextView)findViewById(R.id.scoreOutput);
textView.setText(theScore);
//intent = getIntent();
//String uir = intent.getStringExtra("scoreOutput");
}
#Override
public void onClick(View v) {
}
}
XML Layout:
https://gyazo.com/8e49d02c66dde7ff0e7f09a4fa9eacd2
You're missing:
mySharedPreferences = context.getSharedPreferences("myPrefsFile", Context.MODE_PRIVATE);
in your SVGameView, so mySharedPreferences always null.
You missed assigning SharedPreferencesobject to your reference mySharedPreferences in SVGameView(Context context) -
context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
Change it to
mySharedPreferences = context.getSharedPreferences("myPrefsFile",Context.MODE_PRIVATE);
You are not initializing the SharedPreference object right.
Use this library, which simplifies the use of SharedPreferences and will make life simpler for you.
Android-SharedPreferences-Helper simplifies usage of the default Android SharedPreferences Class. The developer can do in a few lines
of code which otherwise would have required several. Simple to
understand as compared to the default class and easy to use.
I am trying to develop a game with a SurfaceView. The thing is that when I whant to destroy the thread with the method surfaceDestroyed() the application halts in thread.join(), but if don't
draw the canvas (canvas.drawColor(Color.GREEN);) in the onDraw() method everything works well.
How do I do to draw the canvas and call thread.join()??
(I tested many example games from the internet and they all have the same problem, when you hit the go back button for example, you get a FATAL EXCEPTION because the thread is still running)
Here is the code as simple as posible.
Thank you
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
public GameView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
if (gameLoopThread == null) {
gameLoopThread = new GameLoopThread(this);
gameLoopThread.setRunning(true);
gameLoopThread.start();
Log.e("thread", "iniciado");
}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
gameLoopThread.setRunning(false);
boolean retry = true;
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
Log.e("thread", "finalizado");
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
}
public static class GameLoopThread extends Thread {
private static final int FPS = 20;
private GameView view;
private boolean running;
public GameLoopThread(GameViwe gameView) {
this.view = gameView;
}
public void setRunning(boolean run) {
running = run;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {
}
}
}
}
}
So the solution I gave to this problem is to change where it says:
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
on the run() method of the GameLoopThread class with:
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
if(c != null)
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
To finish this activity and to call another one I added a method called GameOver which works well:
private void GameOver() {
gameLoopThread.setRunning(false);
Context c = getContext();
c.startActivity(intent); //intent must be declared
((Activity) Pruebas.this.getContext()).finish();
}
I hope this helps someone.
Disclaimer:
I started programming for the Android (phone) for the first time 2 days ago, so I'm not that experienced. I'm fairly good with C++, but I've only touched Java a few times.
The problem:
When I run my game in my emulator, the app works just as expected. However, when I press the Home button, I usually get some red lines in my LogCat, and in the emulator, the message "Unfortunatly, [app name] has stopped." pops up. If this doesn't happen, it will when I try to open the app again.
Some info that could be a help to find the problem:
I started off with this tutorial:
http://www.edu4java.com/androidgame.html
When I try to use the onDraw function, I have to add "#SuppressLint("WrongCall")" abow the function that uses "onDraw". The tutorial doesn't say anything about that, so I'm a little confused.
LogCat:
06-09 01:51:43.161: E/AndroidRuntime(23830): FATAL EXCEPTION: Thread-1173
06-09 01:51:43.161: E/AndroidRuntime(23830): java.lang.NullPointerException
06-09 01:51:43.161: E/AndroidRuntime(23830): at com.example.braincollect.Background.onDraw(Background.java:24)
06-09 01:51:43.161: E/AndroidRuntime(23830): at com.example.braincollect.GameView.onDraw(GameView.java:132)
06-09 01:51:43.161: E/AndroidRuntime(23830): at com.example.braincollect.GameLoopThread.run(GameLoopThread.java:37)
Code for Background.java:24:
canvas.drawBitmap(bmp, 0, 0, null);
Code for GameView.java:117
introBackground.onDraw(canvas);
Code for GameLoopThread.java:37:
view.getHolder().unlockCanvasAndPost(c);
I have 7 java classes im my project:
MainActivity(activity),
GameView(view),
GameLoopThread(handeling the game loop),
Background(image),
Brain(image),
Zombie(image),
Timer(just some number handeling)
MainActivity.java:
package com.example.braincollect;
import android.media.AudioManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Window;
public class MainActivity extends Activity {
private AudioManager am;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new GameView(this));
am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
return true;
case KeyEvent.KEYCODE_MENU:
return true;
case KeyEvent.KEYCODE_VOLUME_UP:
am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
return true;
default:
return false;
}
}
}
GameView.java:
package com.example.braincollect;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
private Bitmap bmp;
private Bitmap bmp2;
private Bitmap bmp3;
private Bitmap bmp4;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private Timer timer;
public Background introBackground;
public Background background;
private Zombie zombie;
private Brain brain;
private int score = 0;
MediaPlayer mTheme;
MediaPlayer mGameover;
MediaPlayer mBrain;
MediaPlayer mCollect;
Context myContext;
int pauseTimer;
boolean intro = true;
public GameView(Context context) {
super(context);
myContext = context;
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.setRunning(false);
mTheme.stop();
while (gameLoopThread != null) {
try {
gameLoopThread.join();
gameLoopThread = null;
} 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) {
}
});
timer = new Timer(context);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.zombie);
zombie = new Zombie(this, bmp);
bmp2 = BitmapFactory.decodeResource(getResources(), R.drawable.brain);
brain = new Brain(this, bmp2);
bmp3 = BitmapFactory.decodeResource(getResources(), R.drawable.background);
background = new Background(this, bmp3);
bmp4 = BitmapFactory.decodeResource(getResources(), R.drawable.intro);
introBackground = new Background(this, bmp4);
// Music
mTheme = MediaPlayer.create(context, R.raw.theme);
mTheme.setLooping(true);
mTheme.setVolume(0.99f, 0.99f);
mBrain = MediaPlayer.create(context, R.raw.brain);
mBrain.setVolume(0.9f, 0.9f);
mCollect = MediaPlayer.create(context, R.raw.getbrain);
mCollect.setVolume(0.2f, 0.2f);
mGameover = MediaPlayer.create(context, R.raw.gameover);
mGameover.setVolume(0.2f, 0.2f);
pauseTimer = 0;
}
#SuppressLint({ "WrongCall", "DrawAllocation" })
#Override
protected void onDraw(Canvas canvas) {
if(intro == true) {
introBackground.onDraw(canvas);
Paint paint;
paint = new Paint();
paint.setARGB(200, 255, 0, 0);
paint.setTextSize(30);
if(pauseTimer >= 20) {
canvas.drawText("Click to play!", 100, getHeight() - 200, paint);
}
pauseTimer += 1;
}
else if(gameLoopThread.pause == false) {
background.onDraw(canvas);
brain.onDraw(canvas);
zombie.onDraw(canvas);
timer.onDraw(canvas);
if(zombie.isWalking) {
timer.update();
}
Paint paint;
paint = new Paint();
paint.setARGB(200, 255, 0, 0);
paint.setTextSize(25);
canvas.drawText(Integer.toString(score), 10, 30, paint);
if(zombie.isCollition(brain.x, brain.y, brain.width, brain.height)) {
brain.changePos();
if(zombie.isWalking) {
score += 1;
mBrain.start();
}
timer.reset();
}
if(timer.width <= 0) {
mGameover.start();
pauseTimer = 0;
gameLoopThread.pause = true;
mTheme.setVolume(0.3f, 0.3f);
}
} else {
background.onDraw(canvas);
Paint paint;
paint = new Paint();
paint.setARGB(200, 255, 0, 0);
paint.setTextSize(30);
canvas.drawText("Your Score: " + Integer.toString(score), 100, (getHeight() / 2) - 40, paint);
if(pauseTimer >= 20) {
canvas.drawText("Click to play again!", 100, getHeight() / 2, paint);
}
pauseTimer += 1;
}
}
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
zombie.changeDir();
if(intro == true && pauseTimer >= 20) {
intro = false;
mTheme.start();
mCollect.start();
pauseTimer = 0;
gameLoopThread.pause = false;
mTheme.setVolume(0.99f, 0.99f);
mTheme.start();
timer.width = timer.widthMax;
score = 0;
zombie.x = zombie.xStart;
zombie.y = zombie.yStart;
zombie.isWalking = false;
zombie.xSpeed = 1;
zombie.ySpeed = 0;
zombie.currentFrame = 0;
brain.changePos();
}
if(gameLoopThread.pause == true && pauseTimer >= 20) {
pauseTimer = 0;
gameLoopThread.pause = false;
mTheme.setVolume(0.99f, 0.99f);
mTheme.start();
mCollect.start();
timer.width = timer.widthMax;
score = 0;
zombie.x = zombie.xStart;
zombie.y = zombie.yStart;
zombie.isWalking = false;
zombie.xSpeed = 1;
zombie.ySpeed = 0;
zombie.currentFrame = 0;
brain.changePos();
}
}
return super.onTouchEvent(event);
}
}
(The "bmp" names are just temporary, and all the sounds won't be a MediaPlayer object)
GameLoopThread.java:
package com.example.appname;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
public class GameLoopThread extends Thread {
static final long FPS = 10;
private GameView view;
public boolean running = false;
public boolean pause = false;
public GameLoopThread(GameView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
#SuppressLint("WrongCall") #Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
}
If you would need to see more code, just let me know. I have no idea where the fault lies.
I'm pretty sure that view is passing equal null to GameLoopThread constructor, so this line will throw a NPE when you call setRunning(true):
c = view.getHolder().lockCanvas();
You should post other pieces of code with calls to GameLoopThread(view), in order to get a better look at the problem.
Good Luck
That's so simple, in 24th line of your Grass.java file, you have a NullPointerException, so using breakpoints and Debug mode (instead of Run) easily check the values of that line and see which of the variables may be null and either put a null checker before that line or catch the exception:
1.
if(canvas != null) {
...
}
2.
try {
...
} catch (NullPointerException e) {
....
}
I've implemented an SlidingMenu, I set it up with SlidingMenu sm = getSlidingMenu() in the activity I want to use the menu. The problem I've got I want to toggle it via a button I've created on a canvas. If I click these area on the canvas it will stop drawing and open the sliding menu - works until here. But then I added some content with an linearlayout and a textview in it, on clicking the textview the text changes (kind of menu to change some options). And after it changed once the next click should toggle the sliding menu again.
I've created the behind view's in another class, and triggered a method in the activity containing the slidingmenu, it looks like this:
public void toggleSM() {
Thread splash = new Thread(new Runnable() {
#SuppressWarnings("static-access")
#Override
public void run() {
try {
Thread.currentThread().sleep(500);
getSlidingMenu().toggle(true);
Thread.currentThread().sleep(1000);
animateButton.setLeftState(false);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
splash.start();
}
I added the sleep to avoid any problems caused by the sm animation or changing content, the aninamteButton is to trigger the drawing of the canvas again. But it throws a nullpointer exception. With and without animation of the slidingmenu.
EDIT:
The two classes I'm using:
public class Ingame extends SlidingActivity implements OnTouchListener{
private LeftMenu lm;
private SlidingMenu sm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sh = new ScreenHandler(this);
fh = new FilesHandler(this);
animateMap = new AnimateMap(this);
ch = new CoordsHandler(this);
animateButton = new AnimateButton();
sched = new Schedule();
lm = new LeftMenu(this);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setupViews();
lm.setupLeftMenu();
setBehindContentView(lm.getLayout());
setupSlidingMenu();
}
#Override
protected void onPause() {
super.onPause();
gb.pause();
}
#Override
protected void onResume() {
super.onResume();
gb.resume();
}
#SuppressWarnings("deprecation")
public void setupViews() {
FrameLayout fl = new FrameLayout(getBaseContext());
LayoutParams sizeP = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
fl.setLayoutParams(sizeP);
fl.setBackgroundColor(Color.rgb(0, 153, 204));
gb = new GameBoard(getBaseContext());
LayoutParams fillP = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
gb.setLayoutParams(fillP);
gb.setOnTouchListener(Ingame.this);
fl.addView(gb);
setContentView(fl);
}
public void setupSlidingMenu() {
sm = getSlidingMenu();
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
sm.setMenu(lm.getLayout());
}
#SuppressWarnings("static-access")
#Override
public boolean onTouch(View v, MotionEvent e) {
float distX, distY;
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = e.getX();
startY = e.getY();
gb.movedDist.put("startX", startX);
gb.movedDist.put("startY", startY);
finX = finY = -1;
gb.movedDist.put("finX", finX);
gb.movedDist.put("finY", finY);
break;
case MotionEvent.ACTION_MOVE:
finX = e.getX();
finY = e.getY();
distX = startX - finX;
distY = startY - finY;
if(!checkUnvalidValues() && (Math.abs(distX) > sh.getTSize() || Math.abs(distY) > sh.getTSize())) {
int rectDistX = (int) (distX/sh.getTSize());
int rectDistY = (int) (distY/sh.getTSize());
noMove = false;
if(!checkEdges(rectDistX, rectDistY)) {
animateMap.animateXYDistance(rectDistX, rectDistY);
startX = e.getX();
startY = e.getY();
}
}
break;
case MotionEvent.ACTION_UP:
finX = e.getX();
finY = e.getY();
if(checkButton() == IngameButton.PP) {
animateButton.changePPState();
break;
}
if(checkButton() == IngameButton.LEFT) { //WHERE I TRIGGER THE SLIDINGMENU
animateButton.setLeftState(true);
if(!animateButton.getPPState())
animateButton.setPPState(true);
sm.toggle(true);
lm.openLeftMenu();
break;
}
if(noMove && !checkUnvalidValues())
animateMap.tellCoordinate(finX, finY);
noMove = true;
break;
}
return true;
}
private boolean checkUnvalidValues() {
if(startX <= sh.getSideSize()-1 || startX >= (sh.getScreenWidth()-sh.getSideSize()))
return true;
if(startY <= -1 || startY >= (sh.getScreenHeight()-sh.getBottomGUISize()))
return true;
if(finX <= sh.getSideSize()-1 || finX >= (sh.getScreenWidth()-sh.getSideSize()))
return true;
if(finY <= -1 || finY >= (sh.getScreenHeight()-sh.getBottomGUISize()))
return true;
return false;
}
public SlidingMenu getSM() {
return sm;
}
public void toggleSM() {
runOnUiThread(new Runnable() {
#SuppressWarnings("static-access")
#Override
public void run(){
getSlidingMenu().toggle(true);
SlidingMenu sm = getSlidingMenu();
sm.getAlpha();
try {
Thread.currentThread().sleep(1000);
animateButton.setLeftState(false);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});
}
LeftMenu:
public class LeftMenu {
private Context context;
private Ingame ingame;
private AnimateButton animateButton;
private LinearLayout ll;
private LinearLayout.LayoutParams llp;
private static LeftMenuPage page;
private static int buttonTextSize = 15;
public LeftMenu(Context context) {
this.context = context;
ingame = new Ingame();
animateButton = new AnimateButton();
}
public void setupLeftMenu() {
page = LeftMenuPage.OVERVIEW;
setupLinearLayout();
setupButtons();
}
#SuppressWarnings("deprecation")
private void setupLinearLayout() {
ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.VERTICAL);
ll.setBackgroundColor(0xff000000);
llp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT);
ll.setLayoutParams(llp);
}
public LinearLayout getLayout() {
return ll;
}
private void setupButtons() {
final TextView t1 = new TextView(context);
t1.setBackgroundColor(0xff000000);
t1.setTextColor(0xffffffff);
t1.setTypeface(null, Typeface.NORMAL);
t1.setTextSize(buttonTextSize);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.weight = 1.0f;
lp.gravity=1;
t1.setLayoutParams(lp);
String content = null;
if(page == LeftMenuPage.OVERVIEW) {
content = "Creation Mode";
}
else {
content = "Back";
}
t1.setText(content);
ll.addView(t1);
t1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
t1.setTextColor(0xffcccccc);
switch(page) {
case OVERVIEW:
page = LeftMenuPage.CREATE;
t1.setText("Create Dwarves");
ingame.toggleSM();
if(!animateButton.getPPState())
animateButton.setPPState(true);
break;
case CREATE:
ingame.toggleSM();
if(!animateButton.getPPState())
animateButton.setPPState(true);
break;
}
t1.setTextColor(0xffffffff);
}
});
}
public void openLeftMenu() {
page = LeftMenuPage.OVERVIEW;
}
}
EDIT 2:
05-10 15:14:53.535: E/AndroidRuntime(25064): FATAL EXCEPTION: main
05-10 15:14:53.535: E/AndroidRuntime(25064): java.lang.NullPointerException
05-10 15:14:53.535: E/AndroidRuntime(25064): at com.jeremyfeinstein.slidingmenu.lib.app.SlidingActivity.getSlidingMenu(SlidingActivity.java:104)
05-10 15:14:53.535: E/AndroidRuntime(25064): at me.G4meM0ment.DwarvenSkill.Ingame$1.run(Ingame.java:234)
05-10 15:14:53.535: E/AndroidRuntime(25064): at android.os.Handler.handleCallback(Handler.java:615)
05-10 15:14:53.535: E/AndroidRuntime(25064): at android.os.Handler.dispatchMessage(Handler.java:92)
05-10 15:14:53.535: E/AndroidRuntime(25064): at android.os.Looper.loop(Looper.java:137)
05-10 15:14:53.535: E/AndroidRuntime(25064): at android.app.ActivityThread.main(ActivityThread.java:4918)
05-10 15:14:53.535: E/AndroidRuntime(25064): at java.lang.reflect.Method.invokeNative(Native Method)
05-10 15:14:53.535: E/AndroidRuntime(25064): at java.lang.reflect.Method.invoke(Method.java:511)
05-10 15:14:53.535: E/AndroidRuntime(25064): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
05-10 15:14:53.535: E/AndroidRuntime(25064): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
05-10 15:14:53.535: E/AndroidRuntime(25064): at dalvik.system.NativeStart.main(Native Method)
StackTrace, as I already mentionen in some comments, getSlidingMenu returns null and mHelper (SlidingActivityHelper) causes this because it's null
getSlidingMenu().toggle(true);
has to run on the UI Thread. Move it inside and Handler or if your are inside an Activity use
runOnUiThread(new Runnable() {
public void run(){
getSlidingMenu().toggle(true);
}
});