Game score in Android (java) - java

So I'm doing an Android game for an assignment resit. This is not my first app but it is my first game. I've never been that much of an expert and quite frankly this is hard for me. I hope someone here can help.
I actually have two problems to add a score (I sincerely hope it's not too much). The thing is, I want to display it in a TextView. When the Sprite "bad" is hit, I want the score to increase by 1.
My first problem is that said TextView doesn't appear on my activity even when I'm not putting anything else than text in it. I tried to put it in LinearLayout, or change some parameters for its position, but I didn't find any other helpful thing on internet.
My second problem is for the score, which even if I can't see it, probably doesn't work. I found some helps saying to put a JPanel or JLabel but I don't think this is what I need. I tried a simple thing where I just made it an int that increases in the isHit and then displays it on the page. But it doesn't display anything, and the program took the bad habit of crashing before I can't even do anything when I have these written in the code.
I don't actually know which other page would be useful, so here is my GameView.java, if any other might be needed, please tell me.
package com.example.proprietaire.assignmentna2;
import com.example.proprietaire.assignmentna2.R;
import com.example.proprietaire.assignmentna2.Sprite;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class GameView extends SurfaceView implements Runnable {
private SurfaceHolder holder;
private int x = 0, xSpeed = 1;
private Bitmap bmp;
Thread thread = null;
volatile boolean running = false;
static final long FPS = 10;
private long lastClick;
private List<Sprite> sprites = new ArrayList<Sprite>();
private List<Sprite> sprites2 = new ArrayList<Sprite>();
private List<TempSprite> temps = new ArrayList<TempSprite>();
private Bitmap bmpSmoke;
int score = 0;
public GameView(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) {
createSprites();
running = true;
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmpSmoke = BitmapFactory.decodeResource(getResources(), R.drawable.smoke);
}
private void createSprites() {
sprites.add(createSprite(R.drawable.bad));
sprites2.add(createSprite(R.drawable.good));
}
private Sprite createSprite(int resource) {
bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
for (int i = temps.size() - 1; i>= 0; i--) {
temps.get(i).onDraw(canvas);
}
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
for (Sprite sprite : sprites2) {
sprite.onDraw(canvas);
}
}
#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()) {
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) {
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick> 300) {
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder()) {
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isHit(event.getX(), event.getY())) {
sprites.remove(sprite);
temps.add(new TempSprite(temps, this, x, y, bmpSmoke));
sprites.add(createSprite(R.drawable.bad));
sprites.add(createSprite(R.drawable.bad));
sprites2.add(createSprite(R.drawable.good));
score++;
break;
}
//TextView textView = (TextView)findViewById(R.id.textView);
//String s = "" + score;
//textView.setText((new Integer(score)).toString(Integer.parseInt(s)));
}
}
}
return true;
}
}
Here is GameActivity.java
package com.example.proprietaire.assignmentna2;
import android.app.Activity;
import android.os.Bundle;
public class GameActivity extends Activity {
GameView GV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GV = new GameView(this);
setContentView(GV);
}
}
The xml for the game is a simple TextView without any special thing added.
Thank you in advance.

I just checked some of my old code when I was making my own game, I made a dummy .xml file with nothing but a RelativeLayout in it. So your `GameActivity would look something like this:
private TextView tv;
private GameView gv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dummyXml);
initializeGameView();
}
From this point on, you can play around with your GameView and your TextView. I will give an example of the start:
private void initializeGameView(){
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl_dummy_xml);
LinearLayout ll = new LinearLayout(this);
//Layout stuff
ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
ll.setOrientation(LinearLayout.VERTICAL);
ll.setGravity(Gravity.CENTER_HORIZONTAL);
//add more stuff, play around with whatever you want to do here
gv = new GameView();
ll.addView(gv);
tv = new TextView(this);
tv.setText(gv.getScore());
ll.addView(tv);
//Finally, don't forget to add the linear layout to the relative layout
rl.addView(ll);
}
Add a getScore() method to your GameView class or alternatively in a more elegant location :P
If you still have questions (after you've tried and tried and tried), feel free to ask ahead! =)
EDIT:
Updated code example with init of the TextView tv. If you want to update the textview you added at any point, add a method toughly similar to this one:
public void updateTextViewScore(){
tv.setText(gv.getScore());
}
I made the GameView and TextView variables global, therefore you can access them in any method you wish.
You probably want to call this method (thus update the textview) inside the game loop e.g. whenever the score changes.
Good luck! Hope this clears it up a bit.

Related

Hide element when AutoCompleteTextView gain focus

I have 3 AutoCompleteTextView and I want to make a simple function to detect whenever it gain/loses focus so I'll hide an imageView.
Or maybe, whenever the keyboard is UP I want to hide my logo (imageView). When the keyboard is down, show the imageView again.
Code so far:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
RelativeLayout layout = (RelativeLayout)findViewById(R.id.mainLayout);
for(int i=0; i< layout.getChildCount(); i++) {
View v = layout.getChildAt(i);
if(v instanceof AutoCompleteTextView) {
v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
// if(hasWindowFocus()) {
// ImageView logo = findViewById(R.id.imgLogo);
// logo.setVisibility(View.GONE);
// }
Toast.makeText(getApplicationContext(), "pimba", Toast.LENGTH_LONG).show();
}
});
}
}
}
Also, is it possible to create listeners outside this onCreate() ? Or creating everything inside this function is the right way to go?
Try this
Solution 1
Call this method in onCreate()
private void initKeyBoardListener() {
//Threshold for minimal keyboard height.
final int MIN_KEYBOARD_HEIGHT_PX = 150;
//Top-level window decor view.
final View decorView = getWindow().getDecorView();
// Register global layout listener.
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
// Retrieve visible rectangle inside window.
private final Rect windowVisibleDisplayFrame = new Rect();
private int lastVisibleDecorViewHeight;
#Override
public void onGlobalLayout() {
decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();
if (lastVisibleDecorViewHeight != 0) {
if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
Log.d("Keyboard", "SHOW");
// Hide imageview
} else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
// Show imageview
Log.d("Keyboard", "HIDE");
}
}
// Save current decor view height for the next call.
lastVisibleDecorViewHeight = visibleDecorViewHeight;
}
});
}
Solution 2
Use this Util class
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import java.util.HashMap;
/**
* Created by Raman on 2/10/2017.
*/
public class KeyboardUtils implements ViewTreeObserver.OnGlobalLayoutListener {
private static HashMap<SoftKeyboardToggleListener, KeyboardUtils> sListenerMap = new HashMap<>();
private SoftKeyboardToggleListener mCallback;
private View mRootView;
private float mScreenDensity = 1;
private KeyboardUtils(Activity act, SoftKeyboardToggleListener listener) {
mCallback = listener;
mRootView = ((ViewGroup) act.findViewById(android.R.id.content)).getChildAt(0);
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
mScreenDensity = act.getResources().getDisplayMetrics().density;
}
public static void addKeyboardToggleListener(Activity act, SoftKeyboardToggleListener listener) {
removeKeyboardToggleListener(listener);
sListenerMap.put(listener, new KeyboardUtils(act, listener));
}
public static void removeKeyboardToggleListener(SoftKeyboardToggleListener listener) {
if (sListenerMap.containsKey(listener)) {
KeyboardUtils k = sListenerMap.get(listener);
k.removeListener();
sListenerMap.remove(listener);
}
}
public static void removeAllKeyboardToggleListeners() {
for (SoftKeyboardToggleListener l : sListenerMap.keySet())
sListenerMap.get(l).removeListener();
sListenerMap.clear();
}
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
mRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = mRootView.getRootView().getHeight() - (r.bottom - r.top);
float dp = heightDiff / mScreenDensity;
if (mCallback != null)
mCallback.onToggleSoftKeyboard(dp > 200);
}
private void removeListener() {
mCallback = null;
mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
public interface SoftKeyboardToggleListener {
void onToggleSoftKeyboard(boolean isVisible);
}
}
And its usage
Call this in onCreate()
KeyboardUtils.addKeyboardToggleListener(getActivity(), new KeyboardUtils.SoftKeyboardToggleListener() {
#Override
public void onToggleSoftKeyboard(boolean isVisible) {
Log.d("keyboard", "keyboard visible: " + isVisible);
if (!isVisible) {
// show imageview
}
else
{
// hide imageview
}
}
});

Not able to use handler properly in Android

I am learning the android development which now I am making a simple timer which I needs a handler to keep it running. If I put the handler inside the main activity, everything goods but I would like to put the method outside the main activity so I can reuse the codes and should be more flexible if I would like to change anything.
here is my code:
*public class Timer{
public void runTimer(TextView view, int seconds, boolean running){
TextView timerTextView = (TextView) view;
Handler handler = new Handler();
MyRunnable r = new MyRunnable(handler,view,seconds,running);
handler.post(r);
}
}
class MyRunnable implements Runnable {
private TextView view;
private int seconds;
private boolean running;
private Handler handler;
public MyRunnable(Handler handler, TextView view, int seconds, boolean running){
this.handler= handler;
this.view =view;
this.seconds = seconds;
this.running = running;
}
public void run(){
TextView timerTextView = (TextView) view;
int hours = seconds/3600;
int minutes = (seconds%3600)/60;
int secs = seconds%60;
String time = String.format("%d:%02d:%02d",hours,minutes,secs);
timerTextView.setText(time);
if (running){
seconds++;
}
handler.postDelayed(this,100);
}
}*
And I created an object in the main activity to call this function. The app can run but the timer doesn't work properly. It only runs the first time but then stop at all. It doesn't keep running. Do you know where is the problem? thanks for your help first!
Main code:
*package com.mad.chapter4;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class StopWatchActivity extends AppCompatActivity {
private Timer timer = new Timer();
private int seconds = 0;
private boolean running = false;
private boolean wasRunning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_watch);
TextView ttv = (TextView) findViewById(R.id.timerTextView);
if(savedInstanceState!=null){
seconds = savedInstanceState.getInt("seconds");
running = savedInstanceState.getBoolean("running");
wasRunning = savedInstanceState.getBoolean("wasRunning");
}
seconds = timer.runTimer(ttv,seconds,running);
}
public void onSaveInstanceState (Bundle savedInstanceState){
savedInstanceState.putInt("seconds",seconds);
savedInstanceState.putBoolean("running",running);
savedInstanceState.putBoolean("wasRunning",wasRunning);
}
protected void onStop(){
super.onStop();
wasRunning = running;
running = false;
}
protected void onStart(){
super.onStart();
if(wasRunning){
running = true;
}
}
public void onClickStartButton(View view){
running = true;
}
public void onClickStopButton (View view){
running = false;
}
public void onClickResetButton (View view){
seconds = 0;
running = false;
}
// public void runTimer(){
//
// final TextView timerTextView = (TextView) findViewById(R.id.timerTextView);
// final Handler handler = new Handler();
//
// Runnable r = new Runnable(){
// #Override
// public void run(){
// int hours = seconds/3600;
// int minutes = (seconds%3600)/60;
// int secs = seconds%60;
// String time = String.format("%d:%02d:%02d",hours,minutes,secs);
// timerTextView.setText(time);
// if (running){
// seconds++;
// }
// handler.postDelayed(this,100);
// }
// };
//
// handler.post(r);
//
//
// }
}*
From the way I see it your running and wasRunning are never set to true which in turn is not updating your UI only first time but not after that. Try setting running and wasRunning to true before you call timer.runTimer(ttv, seconds, running) in onCreate. I think when you were calling this code in activity you were making call to onClickStartButton(View view) which did set the running flag to true and was updating your UI correctly.
Also, your runTimer functions does not return anything but you in your code you are assigning this function result to an int. Is that a copy/paste error?

SurfaceView frame rate very low

When using SurfaceView I am getting around 6 FPS, when I'm drawing pretty much nothing.
I am only drawing a color. So with pretty much NO drawing operations, I'm getting 6 fps, which is extremely horrible.
One thing to note however is that I am using an emulator(genymotion emulator) and have not tried on a real device. However even WITH an emulator when I am drawing nothing I should be getting way more than 6 fps..
So here's my code (import statements not included):
//Activity class which starts the SurfaceView
public class MainActivity extends Activity {
SView surfaceView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView = new SView(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(surfaceView);
}
}
//SurfaceView class which draws everything in another thread
class SView extends SurfaceView implements SurfaceHolder.Callback{
SurfaceHolder holder;
Canvas mainCanvas;
Paint mainPaint;
int width;
long start, end, fps;
public SView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
mainPaint = new Paint();
mainPaint.setColor(Color.BLACK);
fps = 0;
}
public void surfaceCreated(SurfaceHolder holder) {
new Thread(){
public void run() {
start = System.currentTimeMillis();
while (true) {
end = System.currentTimeMillis();
if ((end - start) >= 1000) {
Log.d("PERSONAL", "FPS: " + fps + " milliseconds " + Long.toString(end - start));
start = System.currentTimeMillis();
fps = 0;
}
customDraw();
}
}
}.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void customDraw(){
mainCanvas = holder.lockCanvas();
mainCanvas.drawRGB(0,150,0);
fps++;
holder.unlockCanvasAndPost(mainCanvas);
}
}
So my question is how can I solve this problem of having such a horrible fps?

My Android app crashes at exit/second time opened

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) {
....
}

Unable to Interact with Android Custom Dialog

Ok, bear with me because I haven't worked with custom Dialogs (or Android programming at all really) that much, and I'm sure I've made a stupid beginner mistake.
So I have a simple dice rolling app that I'm trying to incorporate into my existing app, but I want to do it as essentially a popup. The solution I found thus far was to extend a dialog class and use the xml from the app as a custom layout. This actually displays the expected output, but doesn't allow me to interact with it (i.e. it shows dice on screen but I can't roll them!).
The java class I'm calling is this:
import java.io.IOException;
import java.util.Random;
import com.zeldar.scanner.R;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class RollDice extends Activity implements SensorEventListener {
private final int rollAnimations = 50;
private final int delayTime = 15;
private Resources res;
private final int[] diceImages = new int[] { R.drawable.d1, R.drawable.d2, R.drawable.d3, R.drawable.d4, R.drawable.d5, R.drawable.d6 };
private Drawable dice[] = new Drawable[6];
private final Random randomGen = new Random();
#SuppressWarnings("unused")
private int diceSum;
private int roll[] = new int[] { 6, 6 };
private ImageView die1;
private ImageView die2;
private LinearLayout diceContainer;
private SensorManager sensorMgr;
private Handler animationHandler;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private boolean paused = false;
private static final int UPDATE_DELAY = 50;
private static final int SHAKE_THRESHOLD = 400;
#Override
public void onCreate(Bundle savedInstanceState) {
paused = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.dice);
setTitle(getString(R.string.app_name));
res = getResources();
for (int i = 0; i < 6; i++) {
dice[i] = res.getDrawable(diceImages[i]);
}
diceContainer = (LinearLayout) findViewById(R.id.diceContainer);
diceContainer.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
rollDice();
} catch (Exception e) {};
}
});
die1 = (ImageView) findViewById(R.id.die1);
die2 = (ImageView) findViewById(R.id.die2);
animationHandler = new Handler() {
public void handleMessage(Message msg) {
die1.setImageDrawable(dice[roll[0]]);
die2.setImageDrawable(dice[roll[1]]);
}
};
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
sensorMgr.getDefaultSensor(SensorManager.SENSOR_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
if (!accelSupported) sensorMgr.unregisterListener(this); //no accelerometer on the device
rollDice();
}
private void rollDice() {
if (paused) return;
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < rollAnimations; i++) {
doRoll();
}
}
}).start();
MediaPlayer mp = MediaPlayer.create(this, R.raw.roll);
try {
mp.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
private void doRoll() { // only does a single roll
roll[0] = randomGen.nextInt(6);
roll[1] = randomGen.nextInt(6);
diceSum = roll[0] + roll[1] + 2; // 2 is added because the values of the rolls start with 0 not 1
synchronized (getLayoutInflater()) {
animationHandler.sendEmptyMessage(0);
}
try { // delay to alloy for smooth animation
Thread.sleep(delayTime);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void onResume() {
super.onResume();
paused = false;
}
public void onPause() {
super.onPause();
paused = true;
}
#Override
public void onSensorChanged(SensorEvent event) {
Sensor mySensor = event.sensor;
if (mySensor.getType() == SensorManager.SENSOR_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
if ((curTime - lastUpdate) > UPDATE_DELAY) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
x = event.values[SensorManager.DATA_X];
y = event.values[SensorManager.DATA_Y];
z = event.values[SensorManager.DATA_Z];
float speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
if (speed > SHAKE_THRESHOLD) { //the screen was shaked
rollDice();
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
return; //this method isn't used
}
}
And this is the layout xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/diceContainer"
android:orientation="vertical"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp" >
<ImageView
android:id="#+id/die1"
android:src="#drawable/d6"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginBottom="15dp"
android:contentDescription="#string/content_dice" />
<ImageView
android:id="#+id/die2"
android:src="#drawable/d6"
android:layout_width="150dp"
android:layout_height="150dp"
android:contentDescription="#string/content_dice" />
</LinearLayout>
Finally, the call I'm using to create the dialog:
private Dialog rollDice;
rollDice = new Dialog(ScanActivity.this);
rollDice.setContentView(R.layout.dice);
rollDice.setTitle("Roll Dice");
rollDice.setCancelable(true);
rollDice.show();
To clarify: the most confusing part is that I'm not getting an error, either on compile or run time, it just pops up the window and won't let me do anything with it (except dismiss)!
I would suggest using an activity with a dialog theme if you are wanting something like a dialog. This will allow it to "pop-up" like a dialog but give you more flexibility and easier to manipulate, IMHO. Create a separate activity to open up and add this to your manifest for the activity
<activity android:theme="#android:style/Theme.Dialog">
Themes
There may be a better way to do this but I think this might work well for you.

Categories