Collision detection between a circle and 2 rectangles? - java

The way I have set up my code is I have 3 white rectangles that are as tall as the screen and each 1/9 of the screen wide. Each are equally spaced out accross the screen. I also have 3 other black rectangles, 1 on top of each white...same left and right as the white rectangles so to the user it looks like there is a gap in the white rectangle when in reality it is just a black rectangle of lesser height over a white rectangle as tall as the screen. Anyway, the player has to pass a ball through this "gap" in the white rectangle as the rectangles move across the screen. I was wondering how I would detect collision with the "only white region". By that I mean have code where the ball is safe if it is touching both the black and white rectangle but not safe if the player doesn't hit both the black and white rectangle (If I said not safe if it only hit the white rectangle the player would die every time since like I said the white rectangle is as tall as the screen overlapped by a shorter black rectangle). Here is the code for my mainactivity:
public class GameScreen extends ActionBarActivity {
public static final String TAG = "BallActivity";
BallView mBallView = null;
Rectangle rectWhite1 = null
, rectBlack1= null
, rectWhite2 = null
, rectBlack2= null
, rectWhite3 = null
, rectBlack3= null
,collisionRectangle = null;
int mPointMargin = 5; //specifies width of point adding zone when ball passes rectangle's right side
Handler RedrawHandler = new Handler(); //so redraw occurs in main thread
Handler RedrawHandler2 = new Handler();
Timer mTmr , mTmr2 = null;
TimerTask mTsk , mTsk2 = null;
int mScrWidth, mScrHeight;
int mRectSpeed = 7; //Game max speed should be 12!!!
int mBallSpeed = 15;
Scoreboard mScoreboard = new Scoreboard();
android.graphics.PointF mBallPos, mBallSpd;
//Going to be used to check if ball hits only white rectangle...use intersects method
Rect rectObject;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE); //hide title bar
//set app to full screen and keep screen on
getWindow().setFlags(0xFFFFFFFF, LayoutParams.FLAG_FULLSCREEN | LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_screen);
//create pointer to main screen
final FrameLayout mainView = (FrameLayout) findViewById(R.id.main_view);
//get screen dimensions
Display display = getWindowManager().getDefaultDisplay();
mScrWidth = display.getWidth();
mScrHeight = display.getHeight();
mBallPos = new PointF();
mBallSpd = new PointF();
//create variables for ball position and speed
mBallPos.x = mScrWidth / 7;
mBallPos.y = mScrHeight / 2;
mBallSpd.x = 0;
mBallSpd.y = 0;
//create initial ball
mBallView = new BallView(this, mBallPos.x, mBallPos.y, mScrWidth/30);
//**************Create initial 6 rectangles****************
rectWhite1 = new Rectangle(this, ((mScrWidth/9) * 8) + mScrWidth, 0 , ((mScrWidth/9) * 9) + mScrWidth, mScrHeight, 0xFFFFFFFF);
rectBlack1 = new Rectangle(this, ((mScrWidth/9) * 8) + mScrWidth, (mScrHeight/10) * 4 ,((mScrWidth/9) * 9) + mScrWidth ,(mScrHeight/10) * 6, 0xFFFFFF00);
rectWhite2 = new Rectangle(this, ((mScrWidth/9) * 5) + mScrWidth, 0, ((mScrWidth/9) * 6) + mScrWidth, mScrHeight,0xFFFFFFFF);
rectBlack2 = new Rectangle(this, ((mScrWidth/9) * 5) + mScrWidth, (mScrHeight/10) * 4, ((mScrWidth/9) * 6) + mScrWidth, (mScrHeight/10) * 6, 0xFFFFFF00);
rectWhite3 = new Rectangle(this, ((mScrWidth/18) * 3) + mScrWidth, 0, ((mScrWidth/18) * 5) + mScrWidth, mScrHeight, 0xFFFFFFFF);
rectBlack3 = new Rectangle(this, ((mScrWidth/18) * 3) + mScrWidth, (mScrHeight/10) * 4, ((mScrWidth/18) * 5) + mScrWidth, (mScrHeight/10) * 6 , 0xFFFFFF00);
//Add to view
mainView.addView(rectWhite1);
rectWhite1.invalidate();
mainView.addView(rectWhite2);
rectWhite2.invalidate();
mainView.addView(rectWhite3);
rectWhite3.invalidate();
mainView.addView(rectBlack1);
rectBlack1.invalidate();
mainView.addView(rectBlack2);
rectBlack2.invalidate();
mainView.addView(rectBlack3);
rectBlack3.invalidate();
mainView.addView(mBallView); //add ball to main screen
mBallView.invalidate(); //call onDraw in BallView
//listener for accelerometer, use anonymous class for simplicity
((SensorManager) getSystemService(Context.SENSOR_SERVICE)).registerListener(
new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
//set ball speed based on phone tilt (ignore Z axis)
mBallSpd.x = -event.values[0] * mBallSpeed;
mBallSpd.y = event.values[1] * mBallSpeed;
//timer event will redraw ball
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
} //ignore
},
((SensorManager) getSystemService(Context.SENSOR_SERVICE))
.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0),
SensorManager.SENSOR_DELAY_NORMAL);
} //OnCreate(mScrWidth/10) * 6
//For state flow see http://developer.android.com/reference/android/app/Activity.html
#Override
public void onPause() //app moved to background, stop background threads
{
mTmr.cancel(); //kill\release timer (our only background thread)
mTmr = null;
mTsk = null;
mTmr2.cancel();
mTmr2 = null;
mTsk2 = null;
super.onPause();
}
#Override
public void onResume() //app moved to foreground (also occurs at app startup)
{
final TextView scoreTextView = (TextView)findViewById(R.id.scoreTextView);
final int[] blackRectangleTopHeights = {0, (mScrHeight/10) * 1, (mScrHeight/10) * 2,(mScrHeight/10) * 3,
(mScrHeight/10) * 4,(mScrHeight/10) * 5,(mScrHeight/10) * 6,
(mScrHeight/10) * 7};
final int[] blackRectangleBottomHeights = {(mScrHeight/10) * 3,(mScrHeight/10) * 4,(mScrHeight/10) * 5,
(mScrHeight/10) * 6, (mScrHeight/10) * 7,(mScrHeight/10) * 8,
(mScrHeight/10) * 9,mScrHeight};
final Random randomGenerator = new Random();
runCircle();
//************Set up rectangle moving mechanism and Logic*********************
mTmr2 = new Timer();
mTsk2 = new TimerTask() {
#Override
public void run() {
int randomNumber = randomGenerator.nextInt(blackRectangleTopHeights.length);
int topBlackRectHeight = blackRectangleTopHeights[randomNumber];
int bottomBlackRectHeight = blackRectangleBottomHeights[randomNumber];
//Moves rectangles left across the screen
int rectWhite1Left = rectWhite1.getTheLeft() - mRectSpeed;
int rectWhite1Right = rectWhite1.getTheRight() - mRectSpeed;
rectWhite1.setX(rectWhite1Left, rectWhite1Right);
int rectBlack1Left = rectBlack1.getTheLeft() - mRectSpeed;
int rectBlack1Right = rectBlack1.getTheRight() - mRectSpeed;
rectBlack1.setX(rectBlack1Left, rectBlack1Right);
int rectWhite2Left = rectWhite2.getTheLeft() - mRectSpeed;
int rectWhite2Right = rectWhite2.getTheRight() - mRectSpeed;
rectWhite2.setX(rectWhite2Left, rectWhite2Right);
int rectBlack2Left = rectBlack2.getTheLeft() - mRectSpeed;
int rectBlack2Right = rectBlack2.getTheRight() - mRectSpeed;
rectBlack2.setX(rectBlack2Left, rectBlack2Right);
int rectWhite3Left = rectWhite3.getTheLeft() - mRectSpeed;
int rectWhite3Right = rectWhite3.getTheRight() - mRectSpeed;
rectWhite3.setX(rectWhite3Left, rectWhite3Right);
int rectBlack3Left = rectBlack3.getTheLeft() - mRectSpeed;
int rectBlack3Right = rectBlack3.getTheRight() - mRectSpeed;
rectBlack3.setX(rectBlack3Left, rectBlack3Right);
//Cycles rectangles when they hit left side of the screen
// Randomizes where middle rectangle will be postitoned vertically
if (rectWhite1.getTheRight() > 0 && rectWhite1.getTheRight() < 20) {
rectWhite1.setX(mScrWidth, rectWhite1.getRectWidth() + mScrWidth);
}
if (rectBlack1.getTheRight() > 0 && rectBlack1.getTheRight() < 20) {
rectBlack1.setX(mScrWidth, rectBlack1.getRectWidth() + mScrWidth);
rectBlack1.setY(topBlackRectHeight, bottomBlackRectHeight);
}
if (rectWhite2.getTheRight() > 0 && rectWhite2.getTheRight() < 20) {
rectWhite2.setX(mScrWidth, rectWhite2.getRectWidth() + mScrWidth);
}
if (rectBlack2.getTheRight() > 0 && rectBlack2.getTheRight() < 20) {
rectBlack2.setX(mScrWidth, rectBlack2.getRectWidth() + mScrWidth);
rectBlack2.setY(topBlackRectHeight, bottomBlackRectHeight);
}
if (rectWhite3.getTheRight() > 0 && rectWhite3.getTheRight() < 20) {
rectWhite3.setX(mScrWidth, rectWhite3.getRectWidth() + mScrWidth);
}
if (rectBlack3.getTheRight() > 0 && rectBlack3.getTheRight() < 20) {
rectBlack3.setX(mScrWidth, rectBlack3.getRectWidth() + mScrWidth);
rectBlack3.setY(topBlackRectHeight, bottomBlackRectHeight);
}
//*********Keeps track of score and update TextView with score*************
if (rectWhite1.getTheRight() > Math.round(mBallPos.x) - 5 && rectWhite1.getTheRight() < Math.round(mBallPos.x) + 5) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
if (rectWhite2.getTheRight() > Math.round(mBallPos.x) - mPointMargin && rectWhite2.getTheRight() < Math.round(mBallPos.x) + mPointMargin) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
if (rectWhite3.getTheRight() > Math.round(mBallPos.x) - mPointMargin && rectWhite3.getTheRight() < Math.round(mBallPos.x) + mPointMargin) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
//Speeds up game correspondingly to the score
if (mScoreboard.getScore() == 10) {
mRectSpeed = 8;
mBallSpeed = 16;
}
if (mScoreboard.getScore() == 20) {
mRectSpeed = 9;
mBallSpeed = 17;
}
if (mScoreboard.getScore() == 30) {
mRectSpeed = 10;
mBallSpeed = 18;
}
if (mScoreboard.getScore() == 40) {
mRectSpeed = 11;
mBallSpeed = 19;
}
if (mScoreboard.getScore() == 50) {
mRectSpeed = 12;
mBallSpeed = 20;
}
if (mScoreboard.getScore() == 60) {
mRectSpeed = 13;
mBallSpeed = 21;
}
if (mScoreboard.getScore() == 70) {
mRectSpeed = 14;
mBallSpeed = 22;
}
if (mScoreboard.getScore() == 80) {
mRectSpeed = 15;
mBallSpeed = 23;
}
if (mScoreboard.getScore() == 90) {
mBallSpeed = 24;
}
if (mScoreboard.getScore() == 100) {
mBallSpeed = 25;
}
RedrawHandler2.post(new Runnable() {
public void run() {
rectWhite1.invalidate();
rectWhite2.invalidate();
rectWhite3.invalidate();
rectBlack1.invalidate();
rectBlack2.invalidate();
rectBlack3.invalidate();
}
});
}
};
mTmr2.schedule(mTsk2, 10, 10); //start timer (Timer 2)
super.onResume();
} // onResume
private void runCircle() {
//create timer to move ball to new position
mTmr = new Timer();
mTsk = new TimerTask() {
public void run() {
//move ball based on current speed
mBallPos.x += mBallSpd.y;
mBallPos.y += -mBallSpd.x;
//if ball goes off screen, reposition to opposite side of screen
if (mBallPos.x > mScrWidth) mBallPos.x = 0;
if (mBallPos.y > mScrHeight) mBallPos.y = 0;
if (mBallPos.x < 0) mBallPos.x = mScrWidth;
if (mBallPos.y < 0) mBallPos.y = mScrHeight;
//update ball class instance
mBallView.x = mBallPos.x;
mBallView.y = mBallPos.y;
//redraw ball. Must run in background thread to prevent thread lock.
RedrawHandler.post(new Runnable() {
public void run() {
mBallView.invalidate();
}
});
//If ball hits sides it goes to the redirect screen, YOU LOSE!
if (mBallPos.y == mScrHeight || mBallPos.y == 0 || mBallPos.x == mScrWidth|| mBallPos.x == 0 ) {
goToRedirectScreen();
}
} //run
}; // TimerTask
mTmr.schedule(mTsk, 10, 10); //start timer (Timer)
}
#Override
public void onDestroy() //main thread stopped
{
super.onDestroy();
//wait for threads to exit before clearing app
System.runFinalizersOnExit(true);
//remove app from memory
android.os.Process.killProcess(android.os.Process.myPid());
}
public void goToRedirectScreen()
{
Intent intent = new Intent(this, Redirect.class);
startActivity(intent);
}
}
I need a method that will check if mBallView is only touching the white rectangle and not both the black and white. Or if you have any other solutions I am open to all approaches. Thank you in advance.
I have already referenced:
How to fix circle and rectangle overlap in collision response
and
Circle-Rectangle collision detection
But I did not see how I could apply them to my particular case.

Related

How to do I save a highscore for simple 2D game similar to flappy bird in android studio project?

I am new to programming and so I'm not sure where my code is failing. I have tried to add a save feature for people's high-scores and have tried searching for the answers myself before asking for help. I understand that shared preferences are needed and I have added the code and there's no errors however it doesn't actually save the high-score so the code I have added is pretty redundant right now. Please can someone point me in the right direction? I have added my code below.
EDIT- I have checked my code and under shared preferences I have put int score (this is what i was going to code as the basic score at first but then I changed it to player.getScore later. Anyway when I try to amend score to player.getScore it cannot resolve player.getScore, how do i fix it and once that's been done will my game save the high score?
Thanks for any help.
package com.curtis.myfirstgame;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.preference.PreferenceManager;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
public static final int WIDTH = 856;
public static final int HEIGHT = 480;
public static final int MOVESPEED = -5;
private long smokeStartTime;
private long missileStartTime;
private MainThread thread;
private Background bg;
private Player player;
private ArrayList<Smokepuff> smoke;
private ArrayList<Missile> missiles;
private ArrayList<TopBorder> topborder;
private ArrayList<BotBorder> botborder;
private Random rand = new Random();
private int maxBorderHeight;
private int minBorderHeight;
private boolean topDown = true;
private boolean botDown = true;
private boolean newGameCreated;
public static int Score = 0;
public static int HighScore = 0;
public static SharedPreferences prefs;
private String saveScore = "HighScore";
//increase to slow down difficulty progression, decrease to speed up difficulty progression
private int progressDenom = 20;
private Explosion explosion;
private long startReset;
private boolean reset;
private boolean dissapear;
private boolean started;
public GamePanel(Context context) {
super(context);
SharedPreferences prefs = context.getSharedPreferences("com.curtis.myfirstgame", Context.MODE_PRIVATE);
int player.getScore = prefs.getInt("highScore", 0);
//above is where my problem is
String spackage = "com.curtis.myfirstgame";
HighScore = prefs.getInt(saveScore, 0);
//add the callback to the surfaceholder to intercept events
getHolder().addCallback(this);
//make gamePanel focusable so it can handle events
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
int counter = 0;
while (retry && counter < 1000) {
counter++;
try {
thread.setRunning(false);
thread.join();
retry = false;
thread = null;
}
catch (InterruptedException e) {
e.printStackTrace();
prefs.edit().putInt(saveScore, HighScore).commit();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.grassbg1));
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.helicopter), 65, 25, 3);
smoke = new ArrayList<Smokepuff>();
missiles = new ArrayList<Missile>();
topborder = new ArrayList<TopBorder>();
botborder = new ArrayList<BotBorder>();
smokeStartTime = System.nanoTime();
missileStartTime = System.nanoTime();
thread = new MainThread(getHolder(), this);
//we can safely start the game loop
thread.setRunning(true);
thread.start();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!player.getPlaying() && newGameCreated && reset) {
player.setPlaying(true);
player.setUp(true);
}
if (player.getPlaying()) {
if (!started) started = true;
reset = false;
player.setUp(true);
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
public void update() {
if (player.getPlaying()) {
if (botborder.isEmpty()) {
player.setPlaying(false);
return;
}
if (topborder.isEmpty()) {
player.setPlaying(false);
return;
}
bg.update();
player.update();
//calculate the threshold of height the border can have based on the score
//max and min border heart are updated, and the border switched direction when either max or
//min is met
maxBorderHeight = 30 + player.getScore() / progressDenom;
//cap max border height so that borders can only take up a total of 1/2 the screen
if (maxBorderHeight > HEIGHT / 4) maxBorderHeight = HEIGHT / 4;
minBorderHeight = 5 + player.getScore() / progressDenom;
//check bottom border collision
for (int i = 0; i < botborder.size(); i++) {
if (collision(botborder.get(i), player))
player.setPlaying(false);
}
//check top border collision
for (int i = 0; i < topborder.size(); i++) {
if (collision(topborder.get(i), player))
player.setPlaying(false);
}
//update top border
this.updateTopBorder();
//udpate bottom border
this.updateBottomBorder();
//add missiles on timer
long missileElapsed = (System.nanoTime() - missileStartTime) / 1000000;
if (missileElapsed > (2000 - player.getScore() / 4)) {
//first missile always goes down the middle
if (missiles.size() == 0) {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.
missile), WIDTH + 10, HEIGHT / 2, 45, 15, player.getScore(), 13));
}
else {
missiles.add(new Missile(BitmapFactory.decodeResource(getResources(), R.drawable.missile),
WIDTH + 10, (int) (rand.nextDouble() * (HEIGHT - (maxBorderHeight * 2)) + maxBorderHeight), 45, 15, player.getScore(), 13));
}
//reset timer
missileStartTime = System.nanoTime();
}
//loop through every missile and check collision and remove
for (int i = 0; i < missiles.size(); i++) {
//update missile
missiles.get(i).update();
if (collision(missiles.get(i), player)) {
missiles.remove(i);
player.setPlaying(false);
break;
}
//remove missile if it is way off the screen
if (missiles.get(i).getX() < -100) {
missiles.remove(i);
break;
}
}
//add smoke puffs on timer
long elapsed = (System.nanoTime() - smokeStartTime) / 1000000;
if (elapsed > 120) {
smoke.add(new Smokepuff(player.getX(), player.getY() + 10));
smokeStartTime = System.nanoTime();
}
for (int i = 0; i < smoke.size(); i++) {
smoke.get(i).update();
if (smoke.get(i).getX() < -10) {
smoke.remove(i);
}
}
}
else {
player.resetDY();
if (!reset) {
newGameCreated = false;
startReset = System.nanoTime();
reset = true;
dissapear = true;
explosion = new Explosion(BitmapFactory.decodeResource(getResources(), R.drawable.explosion), player.getX(),
player.getY() - 30, 100, 100, 25);
}
explosion.update();
long resetElapsed = (System.nanoTime() - startReset) / 1000000;
if (resetElapsed > 2500 && !newGameCreated) {
newGame();
}
}
}
public boolean collision(GameObject a, GameObject b) {
if (Rect.intersects(a.getRectangle(), b.getRectangle())) {
return true;
}
return false;
}
#Override
public void draw(Canvas canvas) {
final float scaleFactorX = getWidth() / (WIDTH * 1.f);
final float scaleFactorY = getHeight() / (HEIGHT * 1.f);
if (canvas != null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
if (!dissapear) {
player.draw(canvas);
}
//draw smokepuffs
for (Smokepuff sp : smoke) {
sp.draw(canvas);
}
//draw missiles
for (Missile m : missiles) {
m.draw(canvas);
}
//draw topborder
for (TopBorder tb : topborder) {
tb.draw(canvas);
}
//draw botborder
for (BotBorder bb : botborder) {
bb.draw(canvas);
}
//draw explosion
if (started) {
explosion.draw(canvas);
}
drawText(canvas);
canvas.restoreToCount(savedState);
}
}
public void updateTopBorder() {
//every 50 points, insert randomly placed top blocks that break the pattern
if (player.getScore() % 50 == 0) {
topborder.add(new TopBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), topborder.get(topborder.size() - 1).getX() + 20, 0, (int) ((rand.nextDouble() * (maxBorderHeight
)) + 1)));
}
for (int i = 0; i < topborder.size(); i++) {
topborder.get(i).update();
if (topborder.get(i).getX() < -20) {
topborder.remove(i);
//remove element of arraylist, replace it by adding a new one
//calculate topdown which determines the direction the border is moving (up or down)
if (topborder.get(topborder.size() - 1).getHeight() >= maxBorderHeight) {
topDown = false;
}
if (topborder.get(topborder.size() - 1).getHeight() <= minBorderHeight) {
topDown = true;
}
//new border added will have larger height
if (topDown) {
topborder.add(new TopBorder(BitmapFactory.decodeResource(getResources(),
R.drawable.brick), topborder.get(topborder.size() - 1).getX() + 20,
0, topborder.get(topborder.size() - 1).getHeight() + 1));
}
//new border added wil have smaller height
else {
topborder.add(new TopBorder(BitmapFactory.decodeResource(getResources(),
R.drawable.brick), topborder.get(topborder.size() - 1).getX() + 20,
0, topborder.get(topborder.size() - 1).getHeight() - 1));
}
}
}
}
public void updateBottomBorder() {
//every 40 points, insert randomly placed bottom blocks that break pattern
if (player.getScore() % 40 == 0) {
botborder.add(new BotBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
botborder.get(botborder.size() - 1).getX() + 20, (int) ((rand.nextDouble()
* maxBorderHeight) + (HEIGHT - maxBorderHeight))));
}
//update bottom border
for (int i = 0; i < botborder.size(); i++) {
botborder.get(i).update();
//if border is moving off screen, remove it and add a corresponding new one
if (botborder.get(i).getX() < -20) {
botborder.remove(i);
//determine if border will be moving up or down
if (botborder.get(botborder.size() - 1).getY() <= HEIGHT - maxBorderHeight) {
botDown = true;
}
if (botborder.get(botborder.size() - 1).getY() >= HEIGHT - minBorderHeight) {
botDown = false;
}
if (botDown) {
botborder.add(new BotBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), botborder.get(botborder.size() - 1).getX() + 20, botborder.get(botborder.size() - 1
).getY() + 1));
}
else {
botborder.add(new BotBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), botborder.get(botborder.size() - 1).getX() + 20, botborder.get(botborder.size() - 1
).getY() - 1));
}
}
}
}
public void newGame() {
dissapear = false;
botborder.clear();
topborder.clear();
missiles.clear();
smoke.clear();
minBorderHeight = 5;
maxBorderHeight = 30;
player.resetDY();
player.resetScore();
player.setY(HEIGHT / 2);
//update score only if new score is higher
if (player.getScore() > HighScore) {
HighScore = player.getScore();
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("highScore", HighScore);
edit.commit();
}
//create initial borders
//initial top border
for (int i = 0; i * 20 < WIDTH + 40; i++) {
//first top border create
if (i == 0) {
topborder.add(new TopBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), i * 20, 0, 10));
}
else {
topborder.add(new TopBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick
), i * 20, 0, topborder.get(i - 1).getHeight() + 1));
}
}
//initial bottom border
for (int i = 0; i * 20 < WIDTH + 40; i++) {
//first border ever created
if (i == 0) {
botborder.add(new BotBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick)
, i * 20, HEIGHT - minBorderHeight));
}
//adding borders until the initial screen is filed
else {
botborder.add(new BotBorder(BitmapFactory.decodeResource(getResources(), R.drawable.brick),
i * 20, botborder.get(i - 1).getY() - 1));
}
}
newGameCreated = true;
}
public void drawText(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(30);
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
canvas.drawText("SCORE: " + (player.getScore() * 3), 10, HEIGHT - 10, paint);
canvas.drawText("HIGHSCORE: " + HighScore, WIDTH - 215, HEIGHT - 10, paint);
if (!player.getPlaying() && newGameCreated && reset) {
Paint paint1 = new Paint();
paint1.setTextSize(40);
paint1.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
canvas.drawText("PRESS TO START", WIDTH / 2 - 50, HEIGHT / 2, paint1);
paint1.setTextSize(20);
canvas.drawText("PRESS AND HOLD TO GO UP", WIDTH / 2 - 50, HEIGHT / 2 + 20, paint1);
canvas.drawText("RELEASE TO GO DOWN", WIDTH / 2 - 50, HEIGHT / 2 + 40, paint1);
}
}
}
Do following
SharedPreferences prefs = this.getSharedPreferences("myPrefsKey", Context.MODE_PRIVATE);
int oldScore = prefs.getInt("highScore", 0);
//update score only if new score is higher
if(newScore > oldScore ){
Editor edit = prefs.edit();
edit.putInt("highScore", newScore);
edit.commit();
}
Use this code :
SharedPreferences preference = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preference.edit();
Integer score = preference.getInt("score",null); //read from pref
if(classFound == null)
{ editor.putInt("score",100); //write to pref
editor.commit();
}
Use Integer as int is not nullabe.
You can save any int value by replacing 100 with a variable
Give an upvote if it helped :)

javafx Glow shatter the animation

Im just starting to code and learn javafx and doing an easy project and my problem is after i add a Glow effect on my graphic context the animation slows down dramaticly.
/**
* JavaFX rocks ;)
*/
public class CDLMatrix extends Application {
Stage matrixStage;
private final String characters = "Effect glow = new Glow(1.0); gc.setEffect(glow); WHY SHATTERS ?!";
private final Random random = new Random();
protected final Font font = Font.font("MS PGothic", FontWeight.BOLD, 15);
char[] data = new char[2000 * 2000];
int[] path = new int[2000 * 2000];
private long lastTime = 0;
int getNumberOfCharsPerRow() {
return (int) matrixStage.getWidth() / 12;
}
int getNumberOfCharsPerColumn() {
return (int) matrixStage.getHeight() / 12;
}
// takes random for now
private char getChar() {
return characters.charAt(Math.abs(random.nextInt()
% characters.length()));
}
void update(long now) {
if (lastTime == 0) {
lastTime = now;
}
// fadeTime = how fast trail will fade out
// flipRate = how fast trail chars will change
final int fadeTime = 3;
final float flipRate = 0.01f;
final int fillStart = 100;
final float fillRate = 0.01f;
int numberOfCharsPerRow = getNumberOfCharsPerRow();
int numberOfCharsPerColumn = getNumberOfCharsPerColumn();
int numberOfChars = numberOfCharsPerRow * numberOfCharsPerColumn;
for (int i = numberOfChars - 1; i >= 0; --i) {
if (i + numberOfCharsPerRow < numberOfChars) {
if (path[i] == 255) {
// This means char was just set
// Initialize the next row at this X
// position
path[i + numberOfCharsPerRow] = 255;
data[i + numberOfCharsPerRow] = getChar();
}
}
// path[i] > 64 means if this char Green component > 25%
if (path[i] > 64 && random.nextFloat() < flipRate) {
data[i] = getChar();
}
// Decrement the char Green component
if (path[i] > fadeTime) {
path[i] -= fadeTime;
} else {
path[i] = 0;
}
// First row
// Start doing stuff only if the Green component > 40%
if (i < numberOfCharsPerRow && path[i] <= fillStart) {
if (random.nextFloat() < fillRate) {
path[i] = 255;
data[i] = getChar();
}
}
}
lastTime = now;
}
#Override
public void start(Stage stage) throws Exception {
this.matrixStage = stage;
matrixStage.setTitle("CDL Matrix");
Group root = new Group();
Scene scene = new Scene(root, 1024, 768);
scene.addEventHandler(KeyEvent.KEY_PRESSED,
new EventHandler<KeyEvent>() {
#Override
// F key for full screen ;)
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.F) {
matrixStage.setFullScreen(!matrixStage
.isFullScreen());
}
// ctrl + Q = exit
if (keyEvent.isControlDown()
&& keyEvent.getCode() == KeyCode.Q) {
matrixStage.close();
}
}
});
Canvas canvas = new Canvas();
canvas.widthProperty().bind(matrixStage.widthProperty());
canvas.heightProperty().bind(matrixStage.heightProperty());
final GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFont(font);
// Effect glow = new Glow(1.0); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// gc.setEffect(glow); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
new AnimationTimer() {
#Override
public void handle(long now) {
update(now);
gc.clearRect(0, 0, matrixStage.getWidth(),
matrixStage.getHeight());
gc.setFill(Color.rgb(0, 1, 0));
gc.fillRect(0, 0, matrixStage.getWidth(),
matrixStage.getHeight());
int y = 0;
int numberOfCharsPerRow = getNumberOfCharsPerRow();
int numberOfCharsPerColumn = getNumberOfCharsPerColumn();
// Colors
for (int i = 0; i < numberOfCharsPerRow
* numberOfCharsPerColumn; ++i) {
gc.setFill(Color.rgb(0, path[i], 0));
String text = String.valueOf(data[i]);
gc.fillText(text, (i % numberOfCharsPerRow) * 12 + 1,
y + 13);
if (i % numberOfCharsPerRow == numberOfCharsPerRow - 1) {
y += 12;
}
}
}
}.start();
root.getChildren().add(canvas);
matrixStage.setScene(scene);
matrixStage.show();
}
}
Apply the glow to the Canvas node rather than to the GraphicsContext.
Animation will then occur at normal speed rather than slideshow speed.
Change:
gc.setEffect(glow);
To:
canvas.setEffect(glow);
There must be something in the internal implementation of JavaFX which causes applying effects such as Glow to a GraphicsContext rather than a Node to be orders of magnitude less efficient. You might want to file an issue in the JavaFX issue tracker to have a developer look into it.
Test environment: Java 8u40, OS X 10.9

Processing game: Gif images not respawning as intended

I am a diploma student making a game based on processing, it's a tower defense game where a heroine would be shooting arrows at zombies charging towards the castle. I have multiple issues with this.
The charger zombies do not respawn after being shot dead.
All of the charger zombies die together when I shot only one charger zombie.
Supposedly I wanted the zombies to spawn in waves repeatedly after a group of them has been shot down, and then I want the charger zombies to die individually, depending on the one I click on.
Here's my source code:
import processing.opengl.*; // transparency
import gifAnimation.*; // after add gifAnimation library
import ddf.minim.*; // importing music
PImage backgroundImg;
PImage animation;
int counter;
//settings
int score = 50, totalScore = 0;
int titleX = 200, titleY = 200;
boolean shotsFired = false;
PFont scorePoints, castleHealthPoints, font; //font for startingScreen
int chargerKilled;
//Charger class
int maxChargerOnScreen;
Charger[] chargerArr; //chargerArray undefined
int chargerIndex;
final int numCharger = 300;
ArrayList<Charger> onScreen = new ArrayList<Charger>();
boolean chargerReachedTarget = false, chargerShot = false, chargerDive = true;
Gif chargerCharge, chargerAttack, chargerDied, shootingStance;
int chargerMoveX = 800, chargerMoveY = 450;
// CastleWallHealth
int castleHealth = 1000;
// audio
Minim minim;
AudioPlayer song;
AudioSnippet arrowShoot;
//-------------------------------Codes start here --------------------------------------------------//
void setup() {
//ipad mini size
// frameRate(10);
frameRate(60);
size(800, 600);
smooth();
minim = new Minim(this);
// song = minim.loadFile("InGameSoundtrack.mp3");
// song.play();
arrowShoot = minim.loadSnippet("arrowSound1.wav");
backgroundImg = loadImage("GameBackground.jpg");
backgroundImg.resize(800, 600);
chargerCharge = new Gif(this, "ChargerCharge.gif");
chargerAttack = new Gif(this, "ChargerAttack.gif");
chargerDied = new Gif(this, "ChargerDie.gif");
gargoyleFly = new Gif(this, "GargoyleFly.gif");
gargoyleAttack = new Gif(this, "GargoyleAttack.gif");
shootingStance = new Gif(this, "ShootingGif.gif");
scorePoints = createFont("Arial", 16, true);
castleHealthPoints = createFont("Arial", 16, true);
// loopingGif.play() plays the animation without loop
// must make charger
chargerCharge.play();
chargerAttack.play();
chargerDied.play();
resetGames(); // starts with respawning 5 charges
}
void draw() {
// backgroud
background(backgroundImg);
image(shootingStance, 120,200);
// scores and health
textFont(scorePoints, 15);
fill(0);
text("Score: " + totalScore, 100, 100);
displayCastleHealth();
//*********************************************charger settings code********************************************************************
// If there's no more zombies. prompt reset (screen no zombies) , index from 0 add till 300 then game won
if (onScreen.size() == 0 && chargerIndex == numCharger) {
println("Game won! :)");
// gameWon = true;
}
// while onScreen charger less than 5 only and chargerIndex havent reach 300 it will only respawn
while (onScreen.size () < maxChargerOnScreen && chargerIndex <= numCharger - 1) {
if (chargerIndex < chargerArr.length) { // <--- this is the problem chargerArrayLength
Charger chargerMobs = chargerArr[chargerIndex];
// starts from chargerArray[0] to chargerArray[300]
onScreen.add(chargerMobs);
chargerIndex++;
// chargerIndex keeps looping why?
// println("ADDED ZOMBIE TO ONSCREEN Zombs on screen: " + onScreen.size());
}
}
// Adjusts maxZombOnScreen based off the current index Difficulties?
if (chargerIndex == 10)
maxChargerOnScreen++;
else if (chargerIndex == 50)
maxChargerOnScreen++;
else if (chargerIndex == 100)
maxChargerOnScreen += 2;
else if (chargerIndex == 150)
maxChargerOnScreen += 2;
else if (chargerIndex == 190)
maxChargerOnScreen += 3;
else if (chargerIndex == 250)
maxChargerOnScreen += 3;
else if (chargerIndex == 260)
maxChargerOnScreen += 3;
else if (chargerIndex == 270)
maxChargerOnScreen += 5;
// removes dead zombies, living zombies act normally
for(int i = 0; i < onScreen.size(); i++) {
Charger c = onScreen.get(i);
// add money when a zombie is dead
// if (c.getHealth() <= 0)
if (chargerShot==true) {
c.chargerDying();
onScreen.remove(i);
chargerKilled++;
i--;
} else {
c.act(); ///it should just act
// c.displayHealth(); // if gt time only do
// }
}
}
// creating list of predetermined zombies and their characteristics
println("chargerIndex: " + chargerIndex); // debug
println("onScreenSize: " + onScreen.size());
// println("ChargerArray: " + chargerArray.length); chargerArray point null?
// cursor
if (mouseY > height - 500) {
noFill();
stroke(255, 0, 0);
ellipse(mouseX, mouseY, 35, 35);
line(mouseX - 25, mouseY, mouseX + 25, mouseY);
line(mouseX, mouseY - 25, mouseX, mouseY + 25);
}
}
void resetGames() {
// resetting variables
chargerIndex = 0;
maxChargerOnScreen = 5;
chargerKilled = 0;
createNewCharger();
}
void createNewCharger() {
Charger[] temp = new Charger[numCharger];
for (int i = 0; i < numCharger; i++)
temp[i] = new Charger((int) random(800, 1200), chargerMoveY);
chargerArr = temp;
}
//____________________________________________________________________________________________________________-
class Charger {
private int chargerMoveX, chargerMoveY;
Gif chargerGif; // by default
// chargerGif will change based on input (either it reaches the castle or its shot)
// no constructor
Charger() {
chargerMoveX = 0;
chargerMoveY = 450;
}
// overloaded constructor
Charger(int cMoveX,int cMoveY) {
chargerMoveX = cMoveX;
chargerMoveY = cMoveY;
}
void act() { // use
// if reached castle it wont move
if (chargerMoveX <= 180) {
// remove gif images
chargerDive = false;
chargerReachedTarget = true;
}
// if not shot or reached castle it will move
if (chargerDive == true) {
chargerGif = chargerCharge;
image(chargerGif, chargerMoveX, chargerMoveY);
chargerMoveX -= 2;
}
// if reached castle perform attack animation
if (chargerReachedTarget == true) {
chargerGif = chargerAttack;
image(chargerGif, chargerMoveX - 80, chargerMoveY - 120);
}
if (mousePressed &&
mouseX < chargerMoveX + 180
&& mouseX > chargerMoveX
&& mouseY < chargerMoveY + 120
&& mouseY > chargerMoveY) {
// score board
totalScore = totalScore + score ;
float r = random(50);
println(r);
chargerShot = true;
chargerDive = false;
}
}
void chargerDying() {
chargerReachedTarget = false;
chargerGif = chargerDied;
image(chargerGif, chargerMoveX, chargerMoveY);
}
}
void displayCastleHealth() {
if (castleHealth <= 0) {
fill(250, 70, 0);
textFont(castleHealthPoints, 20);
text("HP: 0", 100, 50);
} else {
fill(250, 70, 0);
textFont(castleHealthPoints, 20);
text("HP: " + castleHealth, 100, 50);
}
}
void mousePressed() {
strokeWeight(2);
arrowShoot.rewind();
arrowShoot.play();
for (int i = 0 ; i < 3; i++)
shootingStance.play();
shotsFired = true;
}
void mouseReleased() {
strokeWeight(1);
if (shotsFired == true)
shootingStance.pause();
}
public void stop() {
arrowShoot.close();
}
Majority of the problems from the charger came from here:
if (onScreen.size() == 0 && chargerIndex == numCharger) {
println("Game won! :)");
// gameWon = true;
}
// while onScreen charger less than 5 only and chargerIndex havent reach 300 it will only respawn
while (onScreen.size () < maxChargerOnScreen && chargerIndex <= numCharger - 1) {
if (chargerIndex < chargerArr.length) { // <--- this is the problem chargerArrayLength
Charger chargerMobs = chargerArr[chargerIndex];
// starts from chargerArray[0] to chargerArray[300]
onScreen.add(chargerMobs);
chargerIndex++;
// chargerIndex keeps looping why?
// println("ADDED ZOMBIE TO ONSCREEN Zombs on screen: " + onScreen.size());
}
}
// Adjusts maxZombOnScreen based off the current index Difficulties?
if (chargerIndex == 10)
maxChargerOnScreen++;
else if (chargerIndex == 50)
maxChargerOnScreen++;
else if (chargerIndex == 100)
maxChargerOnScreen += 2;
else if (chargerIndex == 150)
maxChargerOnScreen += 2;
else if (chargerIndex == 190)
maxChargerOnScreen += 3;
else if (chargerIndex == 250)
maxChargerOnScreen += 3;
else if (chargerIndex == 260)
maxChargerOnScreen += 3;
else if (chargerIndex == 270)
maxChargerOnScreen += 5;
// removes dead zombies, living zombies act normally
for(int i = 0; i < onScreen.size(); i++) {
Charger c = onScreen.get(i);
// add money when a zombie is dead
// if (c.getHealth() <= 0)
if (chargerShot==true) {
c.chargerDying();
onScreen.remove(i);
chargerKilled++;
i--;
} else {
c.act(); ///it should just act
// c.displayHealth(); // if gt time only do
// }
}
}
Evaluation and criticism is appreciated.
There are several issues with the code, but for now, I'll ignore the parts that are somewhat "not clean" or "not elegant", and focus on the main problem that was the reason for the question:
The state of all Chargers instances was the same. The fields
boolean chargerReachedTarget = false, chargerShot = false, chargerDive = true;
have been defined globally. Just by moving this line (that is, these 3 fields) into the Charger class, and changing the line
if (chargerShot==true) {
to
if (c.chargerShot==true) {
the game already seemed to be much closer to what you presumably have been looking for. After this modification, it was possible to shoot individual opponents, and new opponents kept coming after the old ones had disappeared.
Again: The code is not really nicely structured, and there are many possible minor improvements. For example, something like if (c.chargerShot==true) { ... } should better be if (charger.isShot()) { ... }. But I'm not so familiar with processing and its best practices, so I'm not sure how the "best" solution would look like in a global sense...

AndEngine: Getting a NullPointerException on UpdateThread when adding a Sprite

Getting a NullPointerException on UpdateThread when adding a Sprite
I'm creating my first game in AndEngine and I am simply trying to add a Sprite to my GameScene class. I've been tinkering with it for hours now as my application kept crashing after my splash screen, which is supposed to load my GameScene afterwards. I've narrowed it down to these of code in my drawPanel() method:
selectPanel[0] = new Sprite(0, 0, resourceManager.ballTextureRegionArray[0], vbom) {
#Override
protected void preDraw(GLState pGLState, Camera pCamera) {
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
};
selectPanel[0].setPosition(240, 400);
attachChild(selectPanel[0]);
Here is my ResourceManager class where I loaded the ball texture:
ballTexture = new BitmapTextureAtlas(act.getTextureManager(), 64, 576);
ballTextureRegionArray[0] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "red_ball.png", 0, 0);
ballTextureRegionArray[1] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "blue_ball.png", 0, 64);
ballTextureRegionArray[2] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "green_ball.png", 0, 128);
ballTextureRegionArray[3] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "purple_ball.png", 0, 192);
ballTextureRegionArray[4] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "yellow_ball.png", 0, 256);
ballTextureRegionArray[5] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "orange_ball.png", 0, 320);
ballTextureRegionArray[6] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "black_ball.png", 0, 384);
ballTextureRegionArray[7] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "white_ball.png", 0, 448);
ballTextureRegionArray[8] = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(ballTexture, act, "select_ball.png", 0, 512);
ballTexture.load(); // load ballTexture to the scene
... and of course the error.
11-28 17:44:44.750: E/AndroidRuntime(2119): FATAL EXCEPTION: UpdateThread
11-28 17:44:44.750: E/AndroidRuntime(2119): java.lang.NullPointerException
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.GameScene.drawPanel(GameScene.java:188)
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.GameScene.createScene(GameScene.java:68)
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.BaseScene.<init>(BaseScene.java:38)
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.GameScene.<init>(GameScene.java:28)
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.SceneManager.createGameScene(SceneManager.java:120)
11-28 17:44:44.750: E/AndroidRuntime(2119): at com.eklypze.android.mastermdhd.BaseActivity$1.onTimePassed(BaseActivity.java:84)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.handler.timer.TimerHandler.onUpdate(TimerHandler.java:94)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.handler.UpdateHandlerList.onUpdate(UpdateHandlerList.java:47)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.Engine.onUpdateUpdateHandlers(Engine.java:618)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.Engine.onUpdate(Engine.java:605)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.Engine.onTickUpdate(Engine.java:568)
11-28 17:44:44.750: E/AndroidRuntime(2119): at org.andengine.engine.Engine$UpdateThread.run(Engine.java:858)
Here is my GameScene.java class:
package com.eklypze.android.mastermdhd;
import java.util.Random;
import javax.microedition.khronos.opengles.GL10;
import org.andengine.engine.camera.Camera;
import org.andengine.entity.modifier.AlphaModifier;
import org.andengine.entity.modifier.LoopEntityModifier;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.util.GLState;
import android.util.Log;
import com.eklypze.android.mastermdhd.SceneManager.SceneType;
public class GameScene extends BaseScene {
/*** DECLARATIONS ***/
/* Settings */
protected static final int CAMERA_WIDTH = 480;
protected static final int CAMERA_HEIGHT = 800;
/* Sprites */
Sprite[] selectPanel = new Sprite[8];
Sprite boardPieces[] = new Sprite[40];
Sprite bwPegs[] = new Sprite[10];
Sprite nextSpot; // "next spot" cursor
Sprite gameoverLose, gameoverWin; // REPLACE with scenes
/* Game Options */
private int turn = 0;
private int turnCounter = 0; // per line turn counter
private int currentX = 1;
private int currentY = 13;
private int[] code = new int[4]; // array to store generated code
private int[] codeCopy = new int[4]; // for black&white peg use
private int blackPegs = 0, whitePegs = 0;
// remember to take currentX-1 as the array indexes
private int[] currentXValues = new int[4];
// dummy variable when drawing selectPanel for touch *don't delete*
private int z = 0;
Boolean gameOver = false;
Boolean doublesAllowed = false;
/************************************
* ------------INHERITED------------
************************************/
#Override
/********************************
* createScene()
********************************/
public void createScene() {
// create scene with bgSprite background
setBackground(new SpriteBackground(resourceManager.bgSprite));
// STEP 1: Start a New Game
newGame();
// STEP 2: Draw selectPanel
drawPanel(); // debugging: game seems to work up until this point
}
#Override
/********************************
* onBackKeyPressed()
********************************/
public void onBackKeyPressed() {
System.exit(0);
}
#Override
/********************************
* getSceneType()
********************************/
public SceneType getSceneType() {
return SceneType.SCENE_GAME;
}
#Override
/********************************
* disposeScene()
********************************/
public void disposeScene() {
this.detachSelf();
this.dispose();
}
/************************************
* -----------GAME METHODS-----------
************************************/
/********************************
* newGame()
* Description: Initialize game
* settings for a new session.
********************************/
private void newGame() {
/* [START] Generate New Code Combination
for (int x = 0; x < 4; x++) {
Random r = new Random();
// if doubles is not allowed check if new generated number is
// a double, if yes, generate another number. NOTE: doubles are
// defaulted to 'OFF' until feature is added.
int randomNumber = r.nextInt(8); // why (7-0)+0?
Log.v("randomR", "Number generated is " + randomNumber);
code[x] = randomNumber;
// write to log (debugging)
Log.v("theCode", "Number generated for " + x + " is: " + code[x]
+ " (" + resourceManager.ballColours[randomNumber] + ")");
// if doubles is not allowed check if new generated number is
// a double, if yes, generate another number. NOTE: doubles are
// defaulted to 'OFF' until feature is added.
if (!doublesAllowed && x > 0) {
for (int y = x - 1; y >= 0; y--) {
// Log.v("theY", "y is "+y);
if (code[y] == randomNumber) {
x--;
}
}
}
} [END] Generate New Code Combination */
code = new int[] { 7, 1, 2, 3 };
Log.v("theCode", "The Code Is: " + code[0] + "," + code[1] + ","
+ code[2] + "," + code[3] + ".");
codeCopy = code.clone(); // copies code array for white/black peg use
}
/********************************
* drawPanel()
* Description: Draw the panels
* required for user selection.
********************************/
private void drawPanel() {
int column = 7; // constant?
int rowStart = 2;
/* [START] Draw Selection selectPanel
for (int i = 0; i < 8; i++) {
final int j = i;
selectPanel[i] = new Sprite(grid_xPixel(column),
grid_yPixel(rowStart),
resourceManager.ballTextureRegionArray[i], vbom) {
#Override
/* [START] Touch Detection
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
switch (pSceneTouchEvent.getAction()) {
// On Touch
case TouchEvent.ACTION_DOWN:
this.setScale(2.0f); // enlarge effect
z = j;
Log.v("thisIsZ", "Z: " + z);
break;
// On Move/Drag
case TouchEvent.ACTION_MOVE: {
/* to be implemented in the future
// this.setPosition(pSceneTouchEvent.getX() -
// this.getWidth()/2, pSceneTouchEvent.getY() -
// this.getHeight()/2);
break;
}
// On Release
case TouchEvent.ACTION_UP:
// z = j; // not needed
makeMove(z);
this.setScale(1.0f); // normal size
break;
}
return super.onAreaTouched(pSceneTouchEvent,
pTouchAreaLocalX, pTouchAreaLocalY);
}
[END] Touch Detection
}; */
// selectPanel[0] = new Sprite(200, 400,
// resourceManager.ballTextureRegionArray[0], vbom);
//attachChild(selectPanel[0]);
//registerTouchArea(selectPanel[i]);
selectPanel[0] = new Sprite(0, 0, resourceManager.ballTextureRegionArray[0], vbom) {
#Override
protected void preDraw(GLState pGLState, Camera pCamera) {
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
};
selectPanel[0].setPosition(240, 400);
attachChild(selectPanel[0]);
//} /* [END] Draw Selection selectPanel */
// setTouchAreaBindingOnActionDownEnabled(true);
}
/********************************
* makeMove()
* Description: Allow the player
* to make their selection and
* display pegs as a result.
********************************/
private void makeMove(int inColor) {
boardPieces[turn] = new Sprite(grid_xPixel(currentX),
grid_yPixelBoard(currentY),
resourceManager.ballTextureRegionArray[inColor], vbom);
boardPieces[turn].setScale(0.75f); // set 75% size on board
// store current line, compare values to code and generate B/W pegs
currentXValues[currentX - 1] = inColor;
if (currentXValues[currentX - 1] == codeCopy[currentX - 1]) {
blackPegs++;
// dummy variable so this isn't counted again as a white peg
codeCopy[currentX - 1] = 999;
}
for (int i = 0; i < 4; i++) {
if ((currentXValues[currentX - 1] == codeCopy[i])) {
whitePegs++;
// dummy variable so this isn't counted again as a white peg
codeCopy[i] = 999;
}
}
/* log for debugging */
Log.v("pegs", "blackPegs: " + blackPegs);
Log.v("pegs", "whitePegs: " + whitePegs);
// Draw pieces to scene and advance to next turn & column
attachChild(boardPieces[turn]);
currentX++;
turn++;
// advance to next row, draw B/W pegs
if (currentX > 4) {
currentX = 1;
currentY--;
// Draw Pegs
drawBWPegs(blackPegs, whitePegs);
turnCounter++;
// Reset pegs for next line
blackPegs = 0;
whitePegs = 0;
// codeCopy is only used for counting black and white
// pegs per line to ensure all cases work
codeCopy = code.clone();
}
/* [START] Draw Blinking Cursor in Next Spot */
nextSpot = new Sprite(grid_xPixel(currentX),
grid_yPixelBoard(currentY),
resourceManager.ballTextureRegionArray[8], vbom);
nextSpot.setScale(0.75f);
nextSpot.setBlendFunction(GL10.GL_SRC_ALPHA,
GL10.GL_ONE_MINUS_SRC_ALPHA);
nextSpot.registerEntityModifier(new LoopEntityModifier(
new AlphaModifier(2, 0f, 1.0f)));
attachChild(nextSpot);
/* [END] Draw Blinking Cursor in Next Spot */
/* *
* GAME OVER (LOSE)
* If player reaches turn 40 and still has not received
* correct code, go to Game Over (Lose) scene.
* */
if (turn == 40) {
// NOTE: I will replace this with a Game Over scene.
GameOverWin(false);
Log.v("Game Over", "You Lose");
gameoverLose = new Sprite(CAMERA_WIDTH / 2 - 256,
CAMERA_HEIGHT / 2 - 64, resourceManager.loseTextureRegion,
vbom);
attachChild(gameoverLose);
}
}
/********************************
* GameOverWin()
* Description: Display GameOver
* image as a result of the user
* winning the game.
********************************/
private void GameOverWin(boolean win) {
// clear game
detachChildren();
turn = 0;
}
/********************************
* drawBWPegs()
* Description: Draw the black
* and white pegs to the scene
* based on game results.
********************************/
private void drawBWPegs(int numBlack, int numWhite) {
/* [START] if */
// do not display if no pegs were counted
if (numBlack > 0 || numWhite > 0) {
int pegScore = 0;
// determine pegScore
if (numBlack == 1 && numWhite == 0) {
pegScore = 0;
} else if (numBlack == 1 && numWhite == 2) {
pegScore = 1;
} else if (numBlack == 1 && numWhite == 3) {
pegScore = 2;
} else if (numBlack == 0 && numWhite == 1) {
pegScore = 3;
} else if (numBlack == 2 && numWhite == 0) {
pegScore = 4;
} else if (numBlack == 2 && numWhite == 2) {
pegScore = 5;
} else if (numBlack == 0 && numWhite == 2) {
pegScore = 6;
} else if (numBlack == 3 && numWhite == 0) {
pegScore = 7;
} else if (numBlack == 3 && numWhite == 1) {
pegScore = 8;
} else if (numBlack == 0 && numWhite == 3) {
pegScore = 9;
} else if (numBlack == 4 && numWhite == 0) {
pegScore = 10;
} else if (numBlack == 0 && numWhite == 4) {
pegScore = 11;
} /* [END] if */
// use pegScore to display corresponding image
bwPegs[turnCounter] = new Sprite(grid_xPixel(5),
grid_yPixelBoard(currentY + 1),
resourceManager.pegTextureRegionArray[pegScore], vbom);
bwPegs[turnCounter].setScale(0.80f);
attachChild(bwPegs[turnCounter]);
}
}
/********************************
* ---------GRID SYSTEM---------
********************************/
/************************************
* grid_xPixel()
* Description: Converts grid
* coordinates to pixel coordinates
* based on a 480 by 800 resolution
* screen. Needs to be updated.
************************************/
private int grid_xPixel(int x) {
int pixel = 0;
pixel = x * (CAMERA_WIDTH / 8 + 2) - 32;
return pixel;
}
/************************************
* grid_yPixel()
* Description: Y-grid for user
* selection panel.
************************************/
private int grid_yPixel(int y) {
int pixel = 0;
pixel = y * (CAMERA_HEIGHT / 10) - 32;
return pixel;
}
/************************************
* grid_yPixelBoard()
* Description: Y-grid for the main
* game board.
************************************/
private int grid_yPixelBoard(int y) {
int pixel = 0;
pixel = y * (CAMERA_HEIGHT / 15) - 32;
return pixel;
}
}
I apologize as I'm also new to StackOverflow and don't quite know how to format code properly. Also, if I'm missing important areas of code that are relevant to the question please let me know as I have so many lines of code and don't quite know where to start.
Thanks in advance!
Looking at your code I'd say that ballTextureRegionArray[0] was the null pointer, probably because it wasn't loaded in your resourceManager initialisation.
If your .png files are resources i.e. in the "res" directory not the "asset" directory you need to load with .createFromResource not .createFromAsset.

Creating a snake game, when you press two directions quickly snake eats itself [Java]

I hope this makes sense, but I'm trying to make a snake-type game in Java and if you press two directions at the same time/ too fast the snake goes on top of itself making you lose.
For example if you you're going downwards, and hit right then up very fast, you get the snake going straight up on the same column and killing itself, but it should go right one then up one. If anyone can help me that'd be great, thanks!
package tk.sketchistgames.Snake;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Board extends JPanel implements ActionListener{
/**
* Main graphical area for Snake
*/
private static final long serialVersionUID = 4085437479211945011L;
private final int WIDTH = 600;
private final int HEIGHT = 600;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 1200;
private final int RAND_POS = 59;
public static int DELAY = 90;
private int x[] = new int[ALL_DOTS];
private int y[] = new int[ALL_DOTS];
private int dots, food_x, food_y, pdown_x, pdown_y, rdouble_x, rdouble_y, powerUp_x, powerUp_y, half_x, half_y;
private boolean left = false;
private boolean right = true;
private boolean up = false;
private boolean down = false;
private boolean inGame = true;
private int score = 0;
private int fruitEaten = 0;
private boolean Bonus = false;
private boolean RDouble = false;
private boolean bpower = false;
private boolean halfpower = false;
private Timer timer;
private Image food;
private Image head;
private Image body;
private Image pdown;
private Image rdouble;
private Image powerUp;
private Image half;
public Board() {
addKeyListener(new TAdapter());
setBackground(Color.decode("0x3F919E"));
ImageIcon iid = new ImageIcon(this.getClass().getResource("/images/body.png"));
body = iid.getImage();
ImageIcon iia = new ImageIcon(this.getClass().getResource("/images/food.png"));
food = iia.getImage();
ImageIcon iih = new ImageIcon(this.getClass().getResource("/images/head.png"));
head = iih.getImage();
ImageIcon iipd = new ImageIcon(this.getClass().getResource("/images/pdown.png"));
pdown = iipd.getImage();
ImageIcon iird = new ImageIcon(this.getClass().getResource("/images/pup2.png"));
rdouble = iird.getImage();
ImageIcon iipu1 = new ImageIcon(this.getClass().getResource("/images/pup1.png"));
powerUp = iipu1.getImage();
ImageIcon iihd = new ImageIcon(this.getClass().getResource("/images/halfDown.png"));
half = iihd.getImage();
setFocusable(true);
initGame();
}
public void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
locateFood();
timer = new Timer(DELAY, this);
timer.start();
}
public void checkApple() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
if ((x[0] == pdown_x) && (y[0] == pdown_y)){
dots -= 1;
score -= 50;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerdown.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
bpower = false;
}
if ((x[0] == half_x) && (y[0] == half_y)){
dots = dots /2;
score = score /2;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerdown.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
clip.start();
halfpower = false;
}
if ((x[0] == powerUp_x) && (y[0] == powerUp_y)){
dots += 4;
score += 100;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerup1.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
Bonus = false;
}
if ((x[0] == rdouble_x) && (y[0] == rdouble_y)){
dots = dots * 2;
score += 1000;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerup2.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
RDouble = false;
}
if ((x[0] == food_x) && (y[0] == food_y)) {
dots++;
long r = Math.round(Math.random() * 10);
if(r == 4){
locatePowerUp();
Bonus = true;
}
long half = Math.round(Math.random() * 175);
System.out.println(half);
if(half == 89){
locateHalfDown();
halfpower = true;
}
long rdouble = Math.round(Math.random() * 100);
if(rdouble == 50){
locateDoubleUp();
RDouble = true;
}
long badpower = Math.round(Math.random() * 25);
if(badpower == 25 || badpower == 20 || badpower == 15|| badpower == 10 || badpower == 5|| badpower == 0){
locatePowerDown();
bpower = true;
}
score += (50 + fruitEaten);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/eat.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
fruitEaten++;
locateFood();
}
}
public void paint(Graphics g) {
super.paint(g);
if (inGame) {
if(halfpower){
g.drawImage(half, half_x, half_y, this);
}
if(Bonus){
g.drawImage(powerUp, powerUp_x, powerUp_y, this);
}
if(RDouble){
g.drawImage(rdouble, rdouble_x, rdouble_y, this);
}
if(dots <= 0) gameOver(g);
g.setColor(Color.white);
Font small1 = new Font("arcadepix", Font.PLAIN, 20);
g.setFont(small1);
g.drawString("Score: " + score + " Food Eaten: " + fruitEaten + " Length: " + dots, 15, 15);
g.drawImage(food, food_x, food_y, this);
if(bpower){
g.drawImage(pdown, pdown_x, pdown_y, this);
}
for (int z = 0; z < dots; z++) {
if (z == 0)
g.drawImage(head, x[z], y[z], this);
else g.drawImage(body, x[z], y[z], this);
}
if(Menu.pause){
g.drawString("Paused! 'P' To unpause!", 20, 100);
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}else{
gameOver(g);
}
}
public void gameOver(Graphics g) {
if(dots >= 300){
String msg = "You won!";
Font small = new Font("arcadepix", Font.PLAIN, 20);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString("Total Score: " + score +"!", (WIDTH - metr.stringWidth(msg)) /2 - 12, (HEIGHT / 2) - 18);
g.drawString("Total Food Eaten: " + dots + "!", (WIDTH - metr.stringWidth(msg)) /2 - 72, (HEIGHT / 2) - 38);
g.drawString("Press Space to play again!", (WIDTH - metr.stringWidth(msg)) /2 - 77, (HEIGHT / 2) + 18);
setBackground(Color.red);
}else{
String msg = "Game Over";
Font small = new Font("arcadepix", Font.PLAIN, 20);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString("Total Score: " + score, (WIDTH - metr.stringWidth(msg)) /2 - 12, (HEIGHT / 2) - 18);
g.drawString("Press Space to Continue", (WIDTH - metr.stringWidth(msg)) /2 - 77, (HEIGHT / 2) + 18);
setBackground(Color.decode("0x3F919E"));
}
}
public void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (left) {
x[0] -= DOT_SIZE;
}
if (right) {
x[0] += DOT_SIZE;
}
if (up) {
y[0] -= DOT_SIZE;
}
if (down) {
y[0] += DOT_SIZE;
}
}
public void checkCollision() {
for (int z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
if (y[0] > HEIGHT) {
inGame = false;
}
if (y[0] < 0) {
inGame = false;
}
if (x[0] > WIDTH) {
inGame = false;
}
if (x[0] < 0) {
inGame = false;
}
}
public void locateFood() {
int r = (int) (Math.random() * RAND_POS);
food_x = ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
food_y = ((r * DOT_SIZE));
}
public void locatePowerDown() {
int r = (int) (Math.random() * RAND_POS);
pdown_x = ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
pdown_y = ((r * DOT_SIZE));
}
public void locateDoubleUp() {
int r = (int) (Math.random() * RAND_POS);
rdouble_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
rdouble_y = ((r * DOT_SIZE));
}
public void locatePowerUp() {
int r = (int) (Math.random() * RAND_POS);
powerUp_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
powerUp_y = ((r * DOT_SIZE));
}
public void locateHalfDown() {
int r = (int) (Math.random() * RAND_POS);
half_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
half_y = ((r * DOT_SIZE));
}
public void actionPerformed(ActionEvent e) {
if (inGame) {
if(Menu.pause){
}
try {
checkApple();
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (LineUnavailableException e1) {
e1.printStackTrace();
}
checkCollision();
move();
}
repaint();
}
public void reset(){
left = false;
right = true;
up = false;
down = false;
inGame = true;
score = 0;
fruitEaten = 0;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
dots = 5;
bpower = false;
locatePowerDown();
RDouble = false;
locateDoubleUp();
locatePowerUp();
locateFood();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_SPACE){
if(inGame){
if(Menu.pause){
Menu.pause = false;
}else if(!Menu.pause){
Menu.pause = true;
}
}
if(!inGame){
reset();
}
}
if(key == KeyEvent.VK_P){
if(Menu.pause){
Menu.pause = false;
}else if(!Menu.pause){
Menu.pause = true;
}
}
if ((key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A) && (!right)) {
left = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_RIGHT ||key == KeyEvent.VK_D) && (!left)) {
right = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_UP || key == KeyEvent.VK_W) && (!down)) {
up = true;
right = false;
left = false;
}
if ((key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S) && (!up)) {
down = true;
right = false;
left = false;
}
}
}
}
Based on your description, your code is changing the boolean variables before the move occurs. A simple solution would be to store all moves in a Queue, and process them by removing them, that way you ensure you won't overwrite a move.
In other words, every time you record a key event that would change the booleans, store some sort of signal (an int, a String, an enum, etc.) in a Queue, and in your move method, simply remove the signal from the front of the Queue and process it like you process the boolean variables. If you were to use an enum for UP DOWN RIGHT LEFT it would be fairly readable and you could use a switch-case to process each movement.
ex.
switch (movement) {
case UP: /* up code */ break;
case LEFT: /* left code */ break;
case RIGHT: /* right code */ break;
case DOWN: /* down code */ break;
}
where movement is the signal you removed from the queue, and UP DOWN RIGHT LEFT are enum's (for that matter they could be int constants, but as Bloch recommends in Effective Java, prefer enum types to int constants.)
private enum Movement { UP, DOWN, RIGHT, LEFT }
This allows you to refer to these types in the switch above, and instantiate the Queue as follows:
Queue<Movement> movementQueue = new ArrayDeque<Movement>();
Which in turn means you can add whichever movement you need simply by doing the following:
movementQueue.offer(UP); // or DOWN or RIGHT or LEFT, whichever you want.
And when you're ready to use them, access them as follows:
Movement movement = movementQueue.poll();
For more info on Queues: http://docs.oracle.com/javase/6/docs/api/java/util/Queue.html
For more info on enums: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
Also because you said you're new to Java, I'd recommend Head First: Java for an overhead view, and Effective Java to learn a good amount of best practices.

Categories