OK, So Im drawing a bitmap beneath everything else for my background. Whenever the player moves it moves the enemy array 1 px and its supposed to do the same for the background. But whenever I move the background goes way faster and farther than everything else in the game. Can anyone tell me whats causing this? Heres the code. The code that moves everything is at the bottom in the set direction method.
package com.gametest;
import java.util.concurrent.CopyOnWriteArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class GameSurfaceView extends Activity implements OnTouchListener {
double ran;
int touchX, touchY, screenWidth, screenHeight, objX, objY;
static int bgx, bgy, bgW, bgH, enemyCount, score, playerHealth;
static boolean canUpdate;
static MyView v;
static Bitmap orb, orb2, explosion, bg;
static CopyOnWriteArrayList<Sprite> copy = new CopyOnWriteArrayList<Sprite>();
static String hpString;
static Player player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
v = new MyView(this);
v.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent me) {
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_UP:
touchX = (int) me.getX();
touchY = (int) me.getY();
for (Sprite sprite : copy) {
sprite.checkTouch(touchX, touchY);
return true;
}
}
return true;
}
});
canUpdate = true;
screenWidth = v.getWidth();
screenHeight = v.getHeight();
playerHealth = 250;
hpString = "Health " + playerHealth;
ran = 0;
score = 0;
orb = BitmapFactory.decodeResource(getResources(), R.drawable.blue_orb);
orb2 = BitmapFactory.decodeResource(getResources(), R.drawable.red_orb);
bg = BitmapFactory.decodeResource(getResources(), R.drawable.bg1);
bgx = bg.getHeight()/2;
bgy = bg.getHeight()/2;
bgH = bg.getHeight();
bgW = bg.getWidth();
explosion = BitmapFactory.decodeResource(getResources(), R.drawable.explosion);
player = new Player(v, orb2, explosion, screenWidth, screenHeight);
createEnemies();
setContentView(v);
}
private void createEnemies() {
if (enemyCount < 5) {
screenWidth = v.getWidth();
screenHeight = v.getHeight();
copy.add(new Sprite(v, orb, explosion, screenWidth, screenHeight, copy.size()));
enemyCount++;
}
}
public static void checkECount(int id) {
canUpdate = false;
copy.remove(id);
enemyCount--;
CopyOnWriteArrayList<Sprite> c = new CopyOnWriteArrayList<Sprite>();
int index = 0;
for (Sprite s : copy) {
s.ID = index;
c.add(s);
index++;
}
score = score + 10;
copy = c;
canUpdate = true;
}
#Override
protected void onPause() {
super.onPause();
v.pause();
}
#Override
protected void onResume() {
super.onResume();
v.resume();
}
public class MyView extends SurfaceView implements Runnable {
Thread t = null;
SurfaceHolder holder;
boolean isItOk = false;
public MyView(Context context) {
super(context);
holder = getHolder();
}
#Override
public void run() {
while (isItOk == true) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas c = holder.lockCanvas();
if (canUpdate) {
canvas_draw(c);
}
holder.unlockCanvasAndPost(c);
try {
t.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
protected void canvas_draw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
Rect bgRec = new Rect(bgx, bgy, bgx+bgW, bgy+bgH);
canvas.drawBitmap(bg, null, bgRec, null);
ran = Math.random() * 5;
if (ran > 4.5) {
createEnemies();
}
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(15);
canvas.drawText(hpString, 10, 25, paint);
for (Sprite sprite : copy) {
sprite.sprite_draw(canvas);
}
Player.sprite_draw(canvas, copy);
}
public void pause() {
isItOk = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
}
break;
}
t = null;
}
public void resume() {
isItOk = true;
t = new Thread(this);
t.start();
}
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
return false;
}
public static void damagePlayer() {
hpString = "Health " + playerHealth;
playerHealth = playerHealth - 5;
if (playerHealth < 0) {
hpString = "game over";
}
}
public static void setDirection(int i, int j) {
if (i == 0 && j == -1) {
for (Sprite s : copy) {
s.y++;
bgy++;
}
}
if (i == 0 && j == 1) {
for (Sprite s : copy) {
s.y--;
bgy--;
}
}
if (i == -1 && j == 0) {
for (Sprite s : copy) {
s.x++;
bgx++;
}
}
if (i == 1 && j == 0) {
for (Sprite s : copy) {
s.x--;
bgx--;
}
}
}
}
You are changing bgx based on the number of sprites you have in your copy Iterable. in your setDirection method, please move the bgy, bgx outside of the enhanced for loops, like in:
if (i == 0 && j == -1) {
for (Sprite s : copy) {
s.y++;
}
bgy++;
}
Related
I wanted to create a game in which one could move a ball in a labyrinth using accelerometer sensor. In one of the classes extending from View I have the labyrinth, the ball, the goal and a method which draws them, a method which controls the movement of the ball.
package pl.wsiz.greatlabyrinth;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;
public class GameView extends View {
private enum Direction{
up, down, left, right
}
private Cell[][] cells;
private Cell player, exit;
private static final int columns = 11, rows = 20;
private static final float wallThickness = 5;
private float cellSize, hMargin, vMargin;
private Paint wallPaint, playerPaint, exitPaint;
private Random random;
public GameView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
wallPaint = new Paint();
wallPaint.setColor(Color.BLACK);
wallPaint.setStrokeWidth(wallThickness);
playerPaint = new Paint();
playerPaint.setColor(Color.RED);
exitPaint = new Paint();
exitPaint.setColor(Color.BLUE);
random = new Random();
createLabyrinth();
}
private Cell getNeighbour(Cell cell){
ArrayList<Cell> neighbours = new ArrayList<>();
//left neighbour
if(cell.column > 0) {
if (!cells[cell.column - 1][cell.row].visited) {
neighbours.add(cells[cell.column - 1][cell.row]);
}
}
//right neighbour
if(cell.column < columns-1) {
if (!cells[cell.column + 1][cell.row].visited) {
neighbours.add(cells[cell.column + 1][cell.row]);
}
}
//top neighbour
if(cell.row > 0) {
if (!cells[cell.column][cell.row - 1].visited) {
neighbours.add(cells[cell.column][cell.row - 1]);
}
}
//bottom neighbour
if(cell.row < rows-1) {
if (!cells[cell.column][cell.row + 1].visited) {
neighbours.add(cells[cell.column][cell.row + 1]);
}
}
if(neighbours.size() > 0) {
int index = random.nextInt(neighbours.size());
return neighbours.get(index);
}
return null;
}
private void removeWall(Cell current, Cell next){
if(current.column == next.column && current.row == next.row+1) {
current.topWall = false;
next.bottomWall = false;
}
if(current.column == next.column && current.row == next.row-1) {
current.bottomWall = false;
next.topWall = false;
}
if(current.column == next.column+1 && current.row == next.row) {
current.leftWall = false;
next.rightWall = false;
}
if(current.column == next.column-1 && current.row == next.row) {
current.rightWall = false;
next.leftWall = false;
}
}
private void createLabyrinth(){
Stack<Cell> stack = new Stack<>();
Cell current, next;
cells = new Cell[columns][rows];
for(int i=0; i<columns; i++){
for(int j=0; j<rows;j++){
cells[i][j] = new Cell(i, j);
}
}
player = cells[0][0];
exit = cells[columns-1][rows-1];
current = cells[0][0];
current.visited = true;
do {
next = getNeighbour(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
current = next;
current.visited = true;
} else
current = stack.pop();
}while(!stack.empty());
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
int width = getWidth();
int height = getHeight();
if(width/height < columns/rows) {
cellSize = width/(columns+3);
}
else {
cellSize = height/(rows+3);
}
hMargin = (width-columns*cellSize)/2;
vMargin = (height-rows*cellSize)/2;
canvas.translate(hMargin, vMargin);
for(int i=0; i<columns; i++){
for(int j=0; j<rows;j++){
if(cells[i][j].topWall)
canvas.drawLine(i*cellSize, j*cellSize, (i+1)*cellSize,j*cellSize, wallPaint);
if(cells[i][j].leftWall)
canvas.drawLine(i*cellSize, j*cellSize, i*cellSize,(j+1)*cellSize, wallPaint);
if(cells[i][j].bottomWall)
canvas.drawLine(i*cellSize, (j+1)*cellSize, (i+1)*cellSize,(j+1)*cellSize, wallPaint);
if(cells[i][j].rightWall)
canvas.drawLine((i+1)*cellSize, j*cellSize, (i+1)*cellSize,(j+1)*cellSize, wallPaint);
}
}
float margin = cellSize/2;
canvas.drawCircle(player.column*cellSize+margin, player.row*cellSize+margin,(cellSize/2)-5, playerPaint);
canvas.drawCircle(exit.column*cellSize+margin, exit.row*cellSize+margin,(cellSize/2)-5, exitPaint);
}
private void movePlayer(Direction direction){
switch (direction){
case up:
if(!player.topWall)
player = cells[player.column][player.row-1];
break;
case down:
if(!player.bottomWall)
player = cells[player.column][player.row+1];
break;
case left:
if(!player.leftWall)
player = cells[player.column-1][player.row];
break;
case right:
if(!player.rightWall)
player = cells[player.column+1][player.row];
break;
}
checkExit();
invalidate();
}
private void checkExit(){
if(player == exit)
createLabyrinth();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
return true;
if(event.getAction() == MotionEvent.ACTION_MOVE){
float x = event.getX();
float y = event.getY();
float playerCenterX = hMargin + (player.column+0.5f)*cellSize;
float playerCenterY = vMargin + (player.row+0.5f)*cellSize;
float xDirection = x - playerCenterX;
float yDirection = y - playerCenterY;
float absXD = Math.abs(xDirection);
float absYD = Math.abs(yDirection);
if(absXD > cellSize || absYD > cellSize){
if(absXD>absYD){
//move in x-direction
if(xDirection>0){
movePlayer(Direction.right);
}
else{
movePlayer(Direction.left);
}
}
else {
//move in y-direction
if (yDirection > 0) {
movePlayer(Direction.down);
} else {
movePlayer(Direction.up);
}
}
}
return true;
}
return super.onTouchEvent(event);
}
private class Cell {
boolean leftWall = true;
boolean rightWall = true;
boolean topWall = true;
boolean bottomWall = true;
boolean visited = false;
int column, row;
public Cell(int column, int row) {
this.column = column;
this.row = row;
}
}
}
In the second class extending AppCompatActivity I have the code of accelerometer to be used in moving the ball.
package pl.wsiz.greatlabyrinth;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
public class GameActivity extends AppCompatActivity implements SensorEventListener {
private SensorManager sensorManager;
private Sensor accelerometr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
accelerometr = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, accelerometr, SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
}
I do not know how to join accelerometer with the first quoted code so that the ball moves using sensor and not onTouchEvent method. I would be grateful for some code with a little explanation.
I'm trying to draw a line, I managed to do it before but the first point somehow was always 0, 0. Now my logic is, there are two Vectors, one to store each point that is clicked, and another to store the Line, which is made by two points clicked by the user. I do the verifications to see if the Vector is not empty and only then I draw the line. I don't really know what's going on, I've tried everything, hope some of you can help, I'm in real need. Thank you.
Here it goes the code from MyView.java:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.Vector;
public class MyView extends View {
Paint paint = null;
int figure;
int lados_poly;
int cor;
int deletar;
int CursorX, CursorY;
int nrCliques;
Vector<Ponto2D> ptsReta = new Vector<Ponto2D>();
Vector<Reta> guardaRetas = new Vector<Reta>();
public MyView(Context context) {
super(context);
paint = new Paint();
figure = 0;
cor = 0;
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setStrokeWidth(10);
figure = 0;
cor = 0;
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
figure = 0;
cor = 0;
}
public void clickEcra() {
setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
CursorX = (int)event.getX();
CursorY = (int)event.getY();
if (figure == 2){
Ponto2D ptReta = new Ponto2D();
ptReta.x = CursorX;
ptReta.y = CursorY;
ptsReta.add(ptReta);
if (ptsReta.size()> 0) {
for (int c = 0; c < ptsReta.size(); c++)
System.out.println("ptRetaX: " + ptsReta.get(c).x + " ptRetaY: " + ptsReta.get(c).y + " size " + ptsReta.size());
}
invalidate();
}
default:
return false;
}
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
clickEcra();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#F5F1E0"));
canvas.drawPaint(paint);
paint.setColor(Color.parseColor("#3F5866"));
//cores
if (cor == 1) {
paint.setColor(Color.parseColor("#393E46"));
} else if (cor == 2){
paint.setColor(Color.parseColor("#00ADB5"));
} else if (cor == 3) {
paint.setColor(Color.parseColor("#F8B500"));
} else if (cor == 4) {
paint.setColor(Color.parseColor("#FC3C3C"));
}
if (figure == 2) {
if (ptsReta.size() >= 2) {
for (int b = 0; b < ptsReta.size(); b = b + 2) {
Reta retinha = new Reta(ptsReta.get(b), ptsReta.get(b + 1));
guardaRetas.add(retinha);
System.out.println("pts: " + ptsReta.get(b) + ptsReta.get(b + 1));
}
}
if (guardaRetas.size() > 0) {
for (int r = 0; r < guardaRetas.size(); r++) {
canvas.drawLine(guardaRetas.get(r).pinicial.x, guardaRetas.get(r).pinicial.y, guardaRetas.get(r).pfinal.x, guardaRetas.get(r).pfinal.y, paint);
}
}
}
//clear canvas
if (deletar == 2){
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#F5F1E0"));
canvas.drawPaint(paint);
nrCliques = 0;
ptsCirc.removeAllElements();
ptsReta.removeAllElements();
}
}
public void setfigure(int a) {
this.figure = a;
}
public void Cor1_mudar(int text_cor) {
this.cor = text_cor;
}
public void Resetar(int delete){
this.deletar = delete;
}
}
And now the code from Line.java:
public class Reta {
Ponto2D pinicial;
Ponto2D pfinal;
public Reta(){
pinicial = new Ponto2D();
pfinal = new Ponto2D();
}
public Reta(Ponto2D a, Ponto2D b) {
pinicial = a;
pfinal = b;
}
}
Update: It draws one line, and when I try to do another one, on the third click, it closes and I need to draw multiple lines in my canvas.
This were my changes, the following inside onDraw() method:
if (figure == 2) {
if (ptsReta.size() %2 == 0) {
for (int b = 0; b < ptsReta.size(); b = b + 2) {
Reta retinha = new Reta(ptsReta.get(b), ptsReta.get(b + 1));
guardaRetas.add(retinha);
}
if (guardaRetas.size() > 0) {
for (int r = 0; r < guardaRetas.size(); r++) {
canvas.drawLine(guardaRetas.get(r).pinicial.x, guardaRetas.get(r).pinicial.y, guardaRetas.get(r).pfinal.x, guardaRetas.get(r).pfinal.y, paint);
}
}
}
}
And this ones inside the click method:
public void clickEcra() {
setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
CursorX = (int)event.getX();
CursorY = (int)event.getY();
if (figure == 2){
Ponto2D ptReta = new Ponto2D();
ptReta.x = CursorX;
ptReta.y = CursorY;
ptsReta.add(ptReta);
invalidate();
}
default:
return false;
}
}
});
}
I am unable to run my program. The app gets crashed. I am trying to make the image move on the screen by touchEvent.
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.swapnil.new1.model.conmponents.Speed.getxDirection()' on a null object reference
at com.example.swapnil.new1.GamePanel.update(GamePanel.java:89)
at com.example.swapnil.new1.MainThread.run(MainThread.java:32)
I have added the Speed class which I think is responsible for this exception. Suggest any updates.
Speed class has the getxDirection method which is causing the exception.
package com.example.swapnil.new1.model.conmponents;
public class Speed {
public static final int DIRECTION_RIGHT = 1;
public static final int DIRECTION_LEFT = -1;
public static final int DIRECTION_UP = -1;
public static final int DIRECTION_DOWN = 1;
private float xv = 1; // speed in x
private float yv = 1; // speed in y
private int xDirection = DIRECTION_RIGHT;
private int yDirection = DIRECTION_DOWN;
public Speed() {
this.xv = 1;
this.yv = 1;
}
public Speed(float xv, float yv) {
this.xv = xv;
this.yv = yv;
}
public float getXv() {
return xv;
}
public void setXv(float xv) {
this.xv = xv;
}
public float getYv() {
return yv;
}
public void setYv(float yv) {
this.yv = yv;
}
public int getxDirection() {
return xDirection;
}
public void setxDirection(int xDirection) {
this.xDirection = xDirection;
}
public int getyDirection() {
return yDirection;
}
public void setyDirection(int yDirection) {
this.yDirection = yDirection;
}
public void toggleXDirection() {
xDirection = xDirection * -1;
}
public void toggleYDirection() {
yDirection = yDirection * -1;
}
}
The MainThread class:
package com.example.swapnil.new1;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
private boolean running;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
public MainThread(SurfaceHolder surfaceHolder , GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
Canvas canvas;
Log.d(TAG , "Starting game loop");
while(running) {
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
this.gamePanel.render(canvas);
this.gamePanel.update();
}
} finally {
if(canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
The GamePanel class:
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.example.swapnil.new1.model.Droid;
import com.example.swapnil.new1.model.conmponents.Speed;
public class GamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = GamePanel.class.getSimpleName();
private MainThread thread;
private Droid droid;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
droid = new Droid(BitmapFactory.decodeResource(getResources(),R.drawable.droid_1),50,50);
thread = new MainThread(getHolder() , this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
}catch (InterruptedException e) {
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
droid.handleActionDown((int)event.getX(),(int)event.getY());
if (event.getY() > getHeight() - 50) {
thread.setRunning(false);
((Activity)getContext()).finish();
} else {
Log.d(TAG , "Coords : x = " + event.getX() + ",y = " + event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (droid.isTouched()) {
droid.setX((int)event.getX());
droid.setY((int) event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (droid.isTouched()) {
droid.setTouched(false);
}
}
return true;
}
// changed protected to public
protected void render(Canvas canvas) {
canvas.drawColor(Color.BLACK);
droid.draw(canvas);
}
public void update() {
// collision with right
if (droid.getSpeed().getxDirection() == Speed.DIRECTION_RIGHT &&
droid.getX() + droid.getBitmap().getWidth()/2 >= getWidth()) {
droid.getSpeed().toggleXDirection();
}
//collision with left
if (droid.getSpeed().getxDirection() == Speed.DIRECTION_LEFT &&
droid.getX() - droid.getBitmap().getWidth()/2 <= 0) {
droid.getSpeed().toggleXDirection();
}
// collision with down
if (droid.getSpeed().getyDirection() == Speed.DIRECTION_DOWN &&
droid.getY() + droid.getBitmap().getHeight()/2 >= getHeight()) {
droid.getSpeed().toggleYDirection();
}
//collision with up
if (droid.getSpeed().getyDirection() == Speed.DIRECTION_UP &&
droid.getY() - droid.getBitmap().getHeight()/2 <= 0) {
droid.getSpeed().toggleYDirection();
}
droid.update();
}
}
Speed field in your Droid object is not set. In your GamePanel.update() method you are invoking getxDirection on this field and that cause NullPointerException.
i want to execute this code in the following code again and again in defined intervals
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
i tryed few methods but i am stuck with errors . because i have all my animation timed with sleep and thread extended class
package com.okok;
import java.util.ArrayList;
import java.util.List;
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.SurfaceHolder.Callback;
public class GameView extends SurfaceView {
private Bitmap bmp;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
private long lastClick;
private Bitmap bmpBlood;
private List<TempSprite> temps = new ArrayList<TempSprite>();
private int mint;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmpBlood = BitmapFactory.decodeResource(getResources(), R.drawable.blast);
}
private void createSprites() {
sprites.add(createSprite(R.drawable.greenenact));
sprites.add(createSprite(R.drawable.greenenact));
sprites.add(createSprite(R.drawable.greenenact));
}
private Sprite createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Sprite(this, bmp);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.rgb(21, 181, 195));
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 500) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
float x = event.getX();
float y =event.getY();
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollition(x, y)) {
sprites.remove(sprite);
temps.add(new TempSprite(temps, this, x, y, bmpBlood));
break;
}
}
}
}
return true;
}
}
This is the GameLoopThread class i used to move things
package com.okok;
import android.graphics.Canvas;
public class GameLoopThread extends Thread {
static final long FPS = 10;
private GameView view;
private boolean running = false;
public GameLoopThread(GameView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
}
Try something like:
private void createSprites() {
{
new Thread(new Runnable() {
public void run() {
for (int z =0; z<20; z++ ) // total of 20 sprites
try
{
Thread.sleep(5000); // new enemy every 5 seconds
sprites.add(createSprite(R.drawable.image));
z++;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}).start();
}
I'm trying to create a simple sideScroller in java, so far my game runs as expected but i have no idea on how to create a pause menu to go to the main menu and stuff (haven't got any idea on how to create a main manu for that mater) what do you think it's the best idea? this is the relevant code of my game, this panel is called inside a frame:
Game Code
package videojuegoalpha;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Background extends JPanel implements ActionListener, Runnable {
BufferedImage img, marco;
Character character;
Obstacle[] obstacleArray;
Timer time;
//CONSTANTS
final static int largoPantalla = 800;
final static int borderWidth=24;
final static int diferencialPantalla = 74;
final static int characterFlow=10;
final static int fontSize=18;
final static int flickerTime=150;
final static int invincibilityTime=2000;
int largonivel;
int controlPaso;
int actualHeight;
int standardHeight;
int maxHeightValue;
int deltaObstaculo;
Thread brinco;
static boolean debug=false;
boolean jumpCycleDone;
boolean runDone;
boolean maxHeight;
boolean shrinkHeart;
boolean pause;
static Font fontScore,fontMultiplier;
Lives lives;
static MultithreadSystem sounds = new MultithreadSystem();
static Thread MusicPlayer = new Thread(sounds);
static String BackgroundMusic;
String hitSound;
String score;
public Background(int actualHeight, int maxHeightValue,
String characterImage,String characterHitImage, int pasosPersonaje,int speed,
String imagenFondo,String imagenMarco,
String lowObstacleImage,String highObstacleImage,int obstacleDistance,
String musicFile,String jumpSound,String hitSound, String dashSound) {
controlPaso=0;
this.standardHeight = actualHeight;
this.actualHeight = this.standardHeight;
this.maxHeightValue = maxHeightValue;
jumpCycleDone = false;
runDone = false;
maxHeight = false;
shrinkHeart=false;
pause=false;
character = new Character(characterImage,characterHitImage,pasosPersonaje,
speed,jumpSound,dashSound);
lives=new Lives();
obstacleArray=Obstacle.getObstacleArray(5200,obstacleDistance,
standardHeight+deltaObstaculo+borderWidth, (standardHeight+deltaObstaculo)/,lowObstacleImage,highObstacleImage);
addKeyListener(new AL());
setFocusable(true);
try {
img = CompatibleImage.toCompatibleImage(ImageIO.read(new File(
"Images"+File.separator+"Background"+
File.separator+imagenFondo)));
marco = CompatibleImage.toCompatibleImage(ImageIO.read(new File(
"Images"+File.separator+imagenMarco)));
fontScore=(Font.createFont(Font.TRUETYPE_FONT,new FileInputStream(new File(
"Fonts"+File.separator+"score.ttf")))).deriveFont(Font.BOLD, 18);
fontMultiplier=(Font.createFont(Font.TRUETYPE_FONT,
new FileInputStream(new File("Fonts"+File.separator+"multi.ttf"))))
.deriveFont(Font.BOLD, fontSize+10);
} catch (IOException | FontFormatException e) {
System.out.println("Error al cargar" + ":" + e.toString());
}
deltaObstaculo=(character.getImage(character.pasoActual).
getHeight(null))- (obstacleArray[0].getImage().getHeight(null));
time = new Timer(5, this);
time.start();
BackgroundMusic = "Music/"+musicFile;
backMusic(BackgroundMusic);
this.hitSound=hitSound;
}
public static void backMusic(String MusisBck) {
sounds.newThread(BackgroundMusic);
MusicPlayer.start();
if (MusicPlayer.isAlive() != true) {
sounds.newThread(BackgroundMusic);
MusicPlayer.start();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if(!pause){
character.move();
}
condWin(5200);
condLose();
avanzaPaso();
repaint();
}
public void avanzaPaso() {
if(!pause){
controlPaso++;
}
if (controlPaso % characterFlow == 0) {
character.pasoActual++;
if (character.pasoActual > character.pasos-3) {
character.pasoActual = 0;
}
debugMode("Paso: " + character.pasoActual);
}
if(controlPaso%(characterFlow*(character.pasos-2))==0){
shrinkHeart = !shrinkHeart;//oscilaciĆ³n para encojer/desencojer
}
}
public void condWin(int dist) {
if (character.getPositionX() == dist) {
MultithreadSystem sounds = new MultithreadSystem();
sounds.newThread("Music/FF3Victory.wav");
Thread sounds_player = new Thread(sounds);
MusicPlayer.stop();
sounds_player.start();
JOptionPane.showMessageDialog(null, "YOU WIN!");
System.exit(0);
}
}
public void condLose() {
if (character.lives == 0) {
character.isAlive = false;
if (!character.isAlive) {
MultithreadSystem sounds = new MultithreadSystem();
sounds.newThread("Music/gameOver01.wav");
Thread sounds_player = new Thread(sounds);
MusicPlayer.stop();
sounds_player.start();
JOptionPane.showMessageDialog(null, "YOU SUCK");
System.exit(0);
}
}
}
#Override
public void paint(Graphics g) {
debugMode("Altura: " + actualHeight);
if (character.deltaY == 1 && runDone == false) {
runDone = true;
brinco = new Thread(this);
brinco.start();
}
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(img, largoPantalla - character.getnX2(), 0, null);
if (character.getPositionX() > diferencialPantalla) {
g2d.drawImage(img, largoPantalla - character.getnX(), 0, null);
}
for (int i = 0; i < obstacleArray.length; i++) {
if (obstacleArray[i] != null) {
if (obstacleArray[i].getPositionX() == -character.posicionFija) {
obstacleArray[i] = null;
}
if (obstacleArray[i] != null) {
if(!pause){
obstacleArray[i].move(character.pixPerStep);
}
if (obstacleArray[i].getPositionX() ==
largoPantalla + character.posicionFija) {
obstacleArray[i].setVisible(true);
}
if (obstacleArray[i].isVisible()) {
g2d.drawImage(obstacleArray[i].getImage(),
obstacleArray[i].getPositionX(),
obstacleArray[i].getPositionY(), null);
}
checkCollisions(obstacleArray[i]);
}
}
}
if (character.paintCharacter) {
g2d.drawImage(character.getImage(character.pasoActual),
character.posicionFija, actualHeight, null);
}
character.hit(flickerTime);
if (shrinkHeart) {
g2d.drawImage(lives.getImage(character.getLives()),
borderWidth + 5,
borderWidth + 5,
(int) (lives.getImage(character.getLives()).getWidth() * .95),
(int) (lives.getImage(character.getLives()).getHeight() * .95),
null);
} else {
g2d.drawImage(lives.getImage(character.getLives()),
borderWidth + 5,
borderWidth + 5,
null);
}
g2d.drawImage(marco, 0, 0, null);
g2d.setFont(fontScore);
g2d.setColor(Color.BLACK);
score = String.format("%08d", character.score);
g2d.drawString("score:" + score, 500, borderWidth * 2);
g2d.setFont(fontMultiplier);
g2d.drawString(character.multiplier + "",
(largoPantalla / 2) - 75, (borderWidth * 2) + 10);
}
private class AL extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
character.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(!pause){
character.keyPressed(e);
}
if (key == KeyEvent.VK_D) {
debug=(!debug);
}
if(key==KeyEvent.VK_P){
pause=(!pause);
}
if (key == KeyEvent.VK_ESCAPE) {
System.exit(0);
}
}
}
public void checkCollisions(Obstacle obstacle) {
if (character.posicionFija == obstacle.getPositionX()) {
if (obstacle instanceof LowObstacle) {
debugMode("Obstaculo Bajo, Altura: "+obstacle.getPositionY());
if (actualHeight <= (standardHeight - obstacle.getImage().getHeight(null))){
if (character.multiplier < 4) {
character.multiplier++;
}
} else {
if (character.hitAllowed) {
sounds = new MultithreadSystem();
sounds.newThread("SFX/" + hitSound);
Thread sounds_player = new Thread(sounds);
sounds_player.start();
character.multiplier = 1;
character.lives--;
character.hitAllowed = false;
}
}
}
else{
debugMode("Obstaculo Alto, Altura: "+obstacle.getPositionY());
if (character.dashPressed) {
if (character.multiplier < 4) {
character.multiplier++;
}
} else {
if (character.hitAllowed) {
sounds = new MultithreadSystem();
sounds.newThread("SFX/" + hitSound);
Thread sounds_player = new Thread(sounds);
sounds_player.start();
character.multiplier = 1;
character.lives--;
character.hitAllowed = false;
}
}
}
}
}
public void cycle() {
if(!pause){
if (maxHeight == false) {
actualHeight--;
}
if (actualHeight == maxHeightValue) {
maxHeight = true;
}
if (maxHeight == true && actualHeight <= standardHeight) {
actualHeight++;
if (actualHeight == standardHeight) {
jumpCycleDone = true;
}
}
}
}
#Override
public void run() {
character.isJumping = true;
character.keyAllowed = false;
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (jumpCycleDone == false) {
cycle();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = 8 - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
beforeTime = System.currentTimeMillis();
}
jumpCycleDone = false;
maxHeight = false;
runDone = false;
character.keyAllowed = true;
character.isJumping = false;
}
public static void debugMode(String string){
if(debug){
System.out.println(string);
}
}
// Getters y Setters //
public Character getCharacter() {
return character;
}
public void setCharacter(Character character) {
this.character = character;
}
}
As you can see I already have a pause variable which pauses everything, but I would like to have a little window popup in the middle while pause its true
The problem is that your class Background is directly where you draw.
Normally your game handles all the frames and stuff, but then you have some kind of GameState object which your main game calls, like this:
public void update() {
if (pause) {
gameState = pauseState;
} else {
gameState = playState;
}
gameState.update();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
gameState.paint(g2d)
}
The idea is that you can have as many gameStates as you want. Simply make an interface GameState that provides methods for Update, Paint, Initialize and Dispose (or something like this).
Then you can have all kinds of GameStates, for example Play, Pause, MainMenu, SaveGameMenu, etc., each one in charge of updating and drawing itself.
It's the main class (where your game loop is) where you handle the logic to swap the GameStates.