Getting NPE in 2D Game thread - java

I keep getting a NPE when I run this very basic 2D game. It has something to do with the Key Events but I am not sure how to fix this. Can someone help me? It says the NPE is on this line if (_input.up.isPressed()) {
Here is the InputHandler Class
public class InputHandler implements KeyListener {
public InputHandler(Game game) {
game.addKeyListener(this);
}
public class Key {
private boolean pressed = false;
public void toggle(boolean isPressed) {
pressed = isPressed;
}
public boolean isPressed() {
return pressed;
}
}
// public List<Key> keys = new ArrayList<Key>();
public Key up = new Key();
public Key down = new Key();
public Key left = new Key();
public Key right = new Key();
public void keyPressed(KeyEvent e) {
toggleKey(e.getKeyCode(), true);
}
public void keyReleased(KeyEvent e) {
toggleKey(e.getKeyCode(), false);
}
public void keyTyped(KeyEvent e) {
}
public void toggleKey(int keyCode, boolean isPressed) {
if (keyCode == KeyEvent.VK_W) {
up.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_S) {
down.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_A) {
left.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_D) {
right.toggle(isPressed);
}
}
}
here is the Player Class
public class Player extends Mob {
private InputHandler _input;
private int _speed;
private int _r = 10;
private int _x, _y;
public Player(int x, int y, int speed, InputHandler input) {
super("Player", x, y, 1);
_input = input;
_speed = speed;
_x = x;
_y = y;
}
public boolean hasCollided(int dx, int dy) {
return false;
}
public void update() {
int dx = 0;
int dy = 0;
if (_input.up.isPressed()) {
dy--;
} else if (_input.down.isPressed()) {
dy++;
} else if (_input.left.isPressed()) {
dx--;
} else if (_input.right.isPressed()) {
dx++;
}
if (dx != 0 || dy != 0) {
move(dx, dy);
isMoving = true;
} else {
isMoving = false;
}
if (_x < _r)
_x = _r;
if (_y < _r)
_y = _r;
if (_x > Game.WIDTH - _r)
_x = Game.WIDTH - _r;
if (_y > Game.HEIGHT - _r)
_y = Game.HEIGHT - _r;
}
public void render(Graphics2D g) {
g.setColor(Color.BLACK);
g.fillOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(3));
g.setColor(Color.GRAY);
g.drawOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(1));
}
}
here is the game class which creates the player
public class Game extends Canvas implements Runnable {
private static Game _instance;
private static final String TITLE = "ProjectG";
public static final int WIDTH = 960;
public static final int HEIGHT = WIDTH * 3 / 4;
private static final int SCALE = 1;
// to make it have a higher resolution double the width and height but half
// the scale. You are doubling the width and height but keeping the same
// window size by reducing the scale
public static final Dimension SIZE = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private static final int UPDATE_RATE = 60;
private static final int RENDER_RATE = 60;
private JFrame _frame;
private Thread _thread;
private boolean _running = false;
private int _tps = 0;
private int _fps = 0;
private int _totalTicks = 0;
private BufferedImage image;
private Graphics2D g;
public InputHandler input;
private Player player;
public Game() {
_instance = this;
setPreferredSize(SIZE);
setMinimumSize(SIZE);
setMaximumSize(SIZE);
_frame = new JFrame(TITLE);
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.setLayout(new BorderLayout());
_frame.add(_instance, BorderLayout.CENTER);
_frame.pack();
_frame.setResizable(false);
_frame.setLocationRelativeTo(null);
_frame.setVisible(true);
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
}
public synchronized void start() {
_running = true;
_thread = new Thread(this, TITLE + "_main");
_thread.start();
}
public synchronized void stop() {
_running = false;
if (_thread != null) {
try {
_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
double lastUpdateTime = System.nanoTime();
double lastRenderTime = System.nanoTime();
final int ns = 1000000000;
final double nsPerUpdate = (double) ns / UPDATE_RATE;
final double nsPerRender = (double) ns / RENDER_RATE;
final int maxUpdatesBeforeRender = 1;
int lastSecond = (int) lastUpdateTime / ns;
int tickCount = 0;
int renderCount = 0;
image = new BufferedImage(WIDTH * SCALE, HEIGHT * SCALE, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
while (_running) {
long currTime = System.nanoTime();
int tps = 0;
while ((currTime - lastUpdateTime) > nsPerUpdate && tps < maxUpdatesBeforeRender) {
update();
tickCount++;
_totalTicks++;
tps++;
lastUpdateTime += nsPerUpdate;
}
if (currTime - lastUpdateTime > nsPerUpdate) {
lastUpdateTime = currTime - nsPerUpdate;
}
float interpolation = Math.min(1.0F, (float) ((currTime - lastUpdateTime) / nsPerUpdate));
render(interpolation);
draw();
renderCount++;
lastRenderTime = currTime;
int currSecond = (int) (lastUpdateTime / ns);
if (currSecond > lastSecond) {
_tps = tickCount;
_fps = renderCount;
tickCount = 0;
renderCount = 0;
lastSecond = currSecond;
System.out.println(_tps + " TPS " + _fps + " FPS");
}
while (currTime - lastRenderTime < nsPerRender && currTime - lastUpdateTime < nsPerUpdate) {
Thread.yield();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
currTime = System.nanoTime();
}
}
}
public void update() {
player.update();
}
public void render(float interpolation) {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
}
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH * SCALE, HEIGHT * SCALE);
g.setColor(Color.BLACK);
g.drawString("TPS: " + _fps + " FPS: " + _fps, 10, 20);
player.render(g);
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
}
public Game getGame() {
return this;
}
}

You haven't initialized input, so what you pass to
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
is null. You need to initialize it before
input = new InputHandler(this);

Related

Tile/grid movement in Java (2d game)

I just started game-making. I did follow a tutorial on Youtube from CodeNMore, but I do not like the pixel-based movement system. I wanted to make a grid-based movement system, but I couldn't work out how can I do this.
I am not advanced enough to read some1 else code and understand how it works, that's why i ask you guys!
My tiles are 64x64, so what I do is change x value by 64. It doesn't help me because my character starts to teleport all the 64 pixels at once instead of moving smoothly pixel by pixel for 64 pixels (tile size). I tried using for-loops, timers, and thread.sleep, but it didn't really help me.
//Activate both of the movement methods.
public void move() throws InterruptedException {
if (!checkEntityCollisions(xMove, 0f)) {
moveX();
}
if (!checkEntityCollisions(0f, yMove)) {
moveY();
}
System.out.println("Pos x: " + x + "\n Pos y: " + y);
}
//MOVEMENT METHOD
public void moveX() throws InterruptedException {
timer += System.currentTimeMillis() - lastTime;
lastTime = System.currentTimeMillis();
if (xMove > 0) { // MOVING RIGHT
int tx = (int) (x + xMove + bounds.x + bounds.width) / Tile.TILEWIDTH;
//Checks for collisions
if (!collisionWithTile(tx, (int) (y + bounds.y) / Tile.TILEHEIGHT)
&& !collisionWithTile(tx, (int) (y + bounds.y + bounds.height) / Tile.TILEHEIGHT)) {
//tileSize = 64
x += tileSize;
} else {
x = tx * Tile.TILEWIDTH - bounds.x - bounds.width - 1;
}
} else if (xMove < 0) { //MOVING LEFT
int tx = (int) (x + xMove + bounds.x) / Tile.TILEWIDTH;
if (!collisionWithTile(tx, (int) (y + bounds.y) / Tile.TILEHEIGHT)
&& !collisionWithTile(tx, (int) (y + bounds.y + bounds.height) / Tile.TILEHEIGHT)) {
x -= tileSize;
} else {
x = tx * Tile.TILEWIDTH + Tile.TILEWIDTH - bounds.x;
}
}
}
//Graphics code:
private Display display;
private int width, height;
public String title;
public boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
//STATES
private State gameState;
private State menuState;
//INPUT
private KeyManager keyManager;
//CAMERA
private GameCamera gameCamera;
//Handler
private Handler handler;
//GAME ENGINE
public Game(String title, int width, int height) {
this.height = height;
this.width = width;
this.title = title;
keyManager = new KeyManager();
}
public void init() {
display = new Display(title, width, height);
display.getFrame().addKeyListener(keyManager);
Assets.init();
gameCamera = new GameCamera(this, 0, 0);
handler = new Handler(this);
gameState = new GameState(handler);
menuState = new MenuState(handler);
State.setState(gameState);
}
public void tick() {
keyManager.tick();
if (State.getState() != null) {
State.getState().tick();
}
}
public void render() {
bs = display.getCanvas().getBufferStrategy();
if (bs == null) {
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Clear Screen
g.clearRect(0, 0, width, width);
//Draw here!
if (State.getState() != null) {
State.getState().render(g);
}
//End Drawing
bs.show();
g.dispose();
}
public void run() {
init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
while (running) {
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
lastTime = now;
if (delta >= 1) {
tick();
render();
delta--;
}
}
stop();
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public KeyManager getKeyManager() {
return keyManager;
}
public GameCamera getGameCamera() {
return gameCamera;
}
public synchronized void start() {
if (running) {
return;
}
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if (!running) {
return;
}
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Collision Game Errors and Timers

In my game I have two problems. First I am getting some errors that I have no idea how to resolve. Secondly my goal for this project is to add a ball every 30 seconds the player survives. However I have tried several methods in doing so (timers and for loops). However these methods have resulted in graphics not appearing but the rest of the functions working (an invisible ball). If anyone could help me fix these issues it would be much appreciated.
import java.awt.*;
import java.lang.*;
import java.awt.event.KeyEvent;
import java.util.Formatter;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Polygon;
import java.awt.geom.Area;
public class Man implements KeyListener {
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
private float ballSpeedX3 = 7;
private float ballSpeedY3 = 7;
private double ball3Radius = 20;
private double ball3X = 320 ;
private double ball3Y = 120 ;
private float ballSpeedX4 = -10;
private float ballSpeedY4 = 10;
private double ball4Radius = 15;
private double ball4X = 600 ;
private double ball4Y = 300 ;
private float ballSpeedX = 0;
private float ballSpeedY = 0;
private double ballRadius = 20;
private double ballX = 120;
private double ballY = 140;
private float ballSpeed1X = 10;
private float ballSpeed1Y = -10;
private double ballRadius1 = 20;
private double ball1X = 320;
private double ball1Y = 340;
private float ballSpeed2X = -3;
private float ballSpeed2Y = -3;
private double ballRadius2 = 50;
private double ball2X = 50;
private double ball2Y = 400;
private static final int UPDATE_RATE = 30;
public Man() {
this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
Thread gameThread = new Thread() {
public void run() {
while(true){
if ( Math.sqrt( (Math.pow((ballX- ball1X), 2)) + Math.pow((ballY-ball1Y), 2)) <= (ballRadius1 + ballRadius)) {
System.exit(0);}
if ( Math.sqrt( (Math.pow((ball4X- ballX), 2)) + Math.pow((ball4Y-ballY), 2)) <= (ball4Radius + ballRadius)) {
System.exit(0);}
if ( Math.sqrt( (Math.pow((ball2X- ballX), 2)) + Math.pow((ball2Y-ballY), 2)) <= (ballRadius2 + ballRadius)) {
System.exit(0);}
ball4X += ballSpeedX4;
ball4Y += ballSpeedY4;
if (ball4X - ball4Radius < 0) {
ballSpeedX4 = -ballSpeedX4;
ball4X = ball4Radius;
} else if (ball4X + ball4Radius > BOX_WIDTH) {
ballSpeedX4 = -ballSpeedX4;
ball4X = BOX_WIDTH - ball4Radius;
}
if (ball4Y - ball4Radius < 0) {
ballSpeedY4 = -ballSpeedY4;
ball4Y = ball4Radius;
} else if (ball4Y + ball4Radius > BOX_HEIGHT) {
ballSpeedY4 = -ballSpeedY4;
ball4Y = BOX_HEIGHT - ball4Radius;
}
if ( Math.sqrt( (Math.pow((ball3X- ballX), 2)) + Math.pow((ball3Y-ballY), 2)) <= (ball3Radius + ballRadius)) {
System.exit(0);}
ball3X += ballSpeedX3;
ball3Y += ballSpeedY3;
if (ball3X - ball3Radius < 0) {
ballSpeedX3 = -ballSpeedX3;
ball3X = ball3Radius;
} else if (ball3X + ball3Radius > BOX_WIDTH) {
ballSpeedX3 = -ballSpeedX3;
ball3X = BOX_WIDTH - ball3Radius;
}
if (ball3Y - ball3Radius < 0) {
ballSpeedY3 = -ballSpeedY3;
ball3Y = ball3Radius;
} else if (ball3Y + ball3Radius > BOX_HEIGHT) {
ballSpeedY3 = -ballSpeedY3;
ball3Y = BOX_HEIGHT - ball3Radius;
}
ballX += ballSpeedX;
ballY += ballSpeedY;
if (ballX - ballRadius < 0) {
ballX = ballRadius;
} else if (ballX + ballRadius > BOX_WIDTH) {
ballX = BOX_WIDTH - ballRadius;
}
if (ballY - ballRadius < 0) {
ballY = ballRadius;
} else if (ballY + ballRadius > BOX_HEIGHT) {
ballY = BOX_HEIGHT - ballRadius;
}
ball1X += ballSpeed1X;
ball1Y += ballSpeed1Y;
if (ball1X - ballRadius1 < 0) {
ballSpeed1X = -ballSpeed1X;
ball1X = ballRadius1;
} else if (ball1X + ballRadius1 > BOX_WIDTH) {
ballSpeed1X = -ballSpeed1X;
ball1X = BOX_WIDTH - ballRadius1;
}
if (ball1Y - ballRadius1 < 0) {
ballSpeed1Y = -ballSpeed1Y;
ball1Y = ballRadius1;
} else if (ball1Y + ballRadius1 > BOX_HEIGHT) {
ballSpeed1Y = -ballSpeed1Y;
ball1Y = BOX_HEIGHT - ballRadius1;
}
ball2X += ballSpeed2X;
ball2Y += ballSpeed2Y;
if (ball2X - ballRadius2 < 0) {
ballSpeed2X = -ballSpeed2X;
ball2X = ballRadius2;
} else if (ball2X + ballRadius2 > BOX_WIDTH) {
ballSpeed2X = -ballSpeed2X;
ball2X = BOX_WIDTH - ballRadius2;
}
if (ball2Y - ballRadius2 < 0) {
ballSpeed2Y = -ballSpeed2Y;
ball2Y = ballRadius2;
} else if (ball2Y + ballRadius2 > BOX_HEIGHT) {
ballSpeed2Y = -ballSpeed2Y;
ball2Y = BOX_HEIGHT - ballRadius2;
}
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException ex) { }
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);
g.setColor(Color.BLUE);
g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
(int)(2 * ballRadius), (int)(2 * ballRadius));
g.setColor(Color.RED);
g.fillOval((int) (ball1X - ballRadius1), (int) (ball1Y - ballRadius1),
(int)(2 * ballRadius1), (int)(2 * ballRadius1));
g.setColor(Color.PINK);
g.fillOval((int) (ball2X - ballRadius2), (int) (ball2Y - ballRadius2),
(int)(2 * ballRadius2), (int)(2 * ballRadius2));
g.setColor(Color.GREEN);
g.fillOval((int) (ball3X - ball3Radius), (int) (ball3Y - ball3Radius),
(int)(2 * ball3Radius), (int)(2 * ball3Radius));
g.setColor(Color.YELLOW);
g.fillOval((int) (ball4X - ball4Radius), (int) (ball4Y - ball4Radius),
(int)(2 * ball4Radius), (int)(2 * ball4Radius));
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
ballSpeedX = 5;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
ballSpeedX = -5;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
ballSpeedY = -5;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
ballSpeedY = 5;
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
ballSpeedX = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
ballSpeedX = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
ballSpeedY = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
ballSpeedY = 0;
}
}
public void keyTyped(KeyEvent e) { }
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Collision");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Man man = new Man();
frame.setContentPane(man);
frame.pack();
frame.addKeyListener(man);
frame.setVisible(true);
}
});
}
}
I reworked your code and created the following GUI.
The red ball hit the pink player, which ended the animation.
All of your code was in one large class. It was too difficult for me to understand what was going on, so I broke your code up into 7 classes. That way, each class could do one thing and do it well. Don't be afraid to use classes and methods to simplify your code and make it easier to find problems.
Here are the changes I made.
I created a Player class to define the player.
I created a Ball class to hold the values of a Ball; the X and Y position, the color, the radius, and the X and Y speed of the ball.
I created a GameModel class to hold an instance of Player and a List of Ball instances. Whenever you're creating a game, you should use the model / view / controller pattern. This pattern allows you to separate your code and focus on one part of the code at a time.
I renamed your Main class to CollisionGame. The only code left in the CollisionGame class is the code to create the game model, create the JFrame and drawing panel, and start the animation.
I created a DrawingPanel from a JPanel. You should always draw on a JPanel. You should never draw on a JFrame.
I put the KeyListener in it's own class. I added the KeyListener to the JPanel. I made sure that the JPanel would have focus.
I put the animation in its own Animation class.
Here's the code. I put all the classes in one file so it would be easier for me to copy and paste. These classes should be put in separate files.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CollisionGame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CollisionGame();
}
});
}
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
public CollisionGame() {
GameModel gameModel = new GameModel();
JFrame frame = new JFrame("Collision");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel(gameModel, BOX_WIDTH,
BOX_HEIGHT);
frame.add(drawingPanel);
frame.pack();
frame.setVisible(true);
Animation animation = new Animation(drawingPanel, gameModel, BOX_WIDTH,
BOX_HEIGHT);
new Thread(animation).start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -8219208002512324440L;
private int width;
private int height;
private GameModel gameModel;
public DrawingPanel(GameModel gameModel, int width, int height) {
this.gameModel = gameModel;
this.width = width;
this.height = height;
this.setFocusable(true);
this.requestFocusInWindow();
this.addKeyListener(new GameKeyListener(gameModel.getPlayer()));
this.setPreferredSize(new Dimension(width, height));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
Player player = gameModel.getPlayer();
g.setColor(player.getColor());
double playerRadius = player.getRadius();
double playerDiameter = playerRadius + playerRadius;
g.fillOval((int) (player.getPositionX() - playerRadius),
(int) (player.getPositionY() - playerRadius),
(int) (playerDiameter), (int) (playerDiameter));
for (Ball ball : gameModel.getBalls()) {
g.setColor(ball.getColor());
double ballRadius = ball.getRadius();
double ballDiameter = ballRadius + ballRadius;
g.fillOval((int) (ball.getPositionX() - ballRadius),
(int) (ball.getPositionY() - ballRadius),
(int) (ballDiameter), (int) (ballDiameter));
}
}
}
public class Animation implements Runnable {
private static final long UPDATE_RATE = 30;
private boolean running;
private double width;
private double height;
private DrawingPanel drawingPanel;
private GameModel gameModel;
public Animation(DrawingPanel drawingPanel, GameModel gameModel,
double width, double height) {
this.drawingPanel = drawingPanel;
this.gameModel = gameModel;
this.width = width;
this.height = height;
this.running = true;
}
#Override
public void run() {
sleep(1000L);
long ballTime = System.currentTimeMillis();
long nextBallTime = 30000L;
gameModel.addBall();
while (running) {
long elapsedTime = System.currentTimeMillis() - ballTime;
if (elapsedTime >= nextBallTime) {
gameModel.addBall();
ballTime += nextBallTime;
}
movePlayer(gameModel.getPlayer());
for (Ball ball : gameModel.getBalls()) {
moveBall(ball);
}
repaint();
if (isPlayerHit()) {
running = false;
} else {
sleep(1000L / UPDATE_RATE);
}
}
}
private void movePlayer(Player player) {
player.setPositionX(player.getPositionX() + player.getSpeedX());
player.setPositionY(player.getPositionY() + player.getSpeedY());
double radius = player.getRadius();
if (player.getPositionX() - radius < 0) {
player.setSpeedX(-player.getSpeedX());
player.setPositionX(radius);
} else if (player.getPositionX() + radius > width) {
player.setSpeedX(-player.getSpeedX());
player.setPositionX(width - radius);
}
if (player.getPositionY() - radius < 0) {
player.setSpeedY(-player.getSpeedY());
player.setPositionY(radius);
} else if (player.getPositionY() + radius > height) {
player.setSpeedY(-player.getSpeedY());
player.setPositionY(height - radius);
}
}
private void moveBall(Ball ball) {
ball.setPositionX(ball.getPositionX() + ball.getSpeedX());
ball.setPositionY(ball.getPositionY() + ball.getSpeedY());
double radius = ball.getRadius();
if (ball.getPositionX() - radius < 0) {
ball.setSpeedX(-ball.getSpeedX());
ball.setPositionX(radius);
} else if (ball.getPositionX() + radius > width) {
ball.setSpeedX(-ball.getSpeedX());
ball.setPositionX(width - radius);
}
if (ball.getPositionY() - radius < 0) {
ball.setSpeedY(-ball.getSpeedY());
ball.setPositionY(radius);
} else if (ball.getPositionY() + radius > height) {
ball.setSpeedY(-ball.getSpeedY());
ball.setPositionY(height - radius);
}
}
private boolean isPlayerHit() {
Player player = gameModel.getPlayer();
for (Ball ball : gameModel.getBalls()) {
double radiusSquared = Math.pow(
ball.getRadius() + player.getRadius(), 2D);
double distanceSquared = Math.pow(
(ball.getPositionX() - player.getPositionX()), 2D)
+ Math.pow(ball.getPositionY() - player.getPositionY(),
2D);
if (distanceSquared <= radiusSquared) {
return true;
}
}
return false;
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
private void sleep(long sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}
public class GameKeyListener implements KeyListener {
private float playerSpeedX;
private float playerSpeedY;
private Player player;
public GameKeyListener(Player player) {
this.player = player;
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
playerSpeedX = 5;
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
playerSpeedX = -5;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
playerSpeedY = -5;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerSpeedY = 5;
}
updatePlayer();
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
playerSpeedX = 0;
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
playerSpeedX = 0;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
playerSpeedY = 0;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerSpeedY = 0;
}
updatePlayer();
}
#Override
public void keyTyped(KeyEvent e) {
}
private void updatePlayer() {
player.setSpeedX(playerSpeedX);
player.setSpeedY(playerSpeedY);
}
}
public class GameModel {
private List<Ball> balls;
private List<Ball> newBalls;
private Player player;
public GameModel() {
this.balls = new ArrayList<>();
this.newBalls = createBalls();
this.player = new Player(Color.PINK, 120, 140, 20, 0, 0);
}
private List<Ball> createBalls() {
List<Ball> balls = new ArrayList<>();
balls.add(new Ball(Color.BLUE, 320, 120, 20, 7, 7));
balls.add(new Ball(Color.RED, 600, 300, 15, -10, 10));
balls.add(new Ball(Color.GREEN, 320, 340, 20, 10, -10));
balls.add(new Ball(Color.YELLOW, 50, 400, 50, -3, -3));
return balls;
}
public void addBall() {
if (!newBalls.isEmpty()) {
balls.add(newBalls.get(0));
newBalls.remove(0);
}
}
public List<Ball> getBalls() {
return balls;
}
public Player getPlayer() {
return player;
}
}
public class Player {
private float speedX;
private float speedY;
private double radius;
private double positionX;
private double positionY;
private Color color;
public Player(Color color, double positionX, double positionY,
double radius, float speedX, float speedY) {
this.color = color;
this.positionX = positionX;
this.positionY = positionY;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public float getSpeedX() {
return speedX;
}
public void setSpeedX(float speedX) {
this.speedX = speedX;
}
public float getSpeedY() {
return speedY;
}
public void setSpeedY(float speedY) {
this.speedY = speedY;
}
public double getRadius() {
return radius;
}
public double getPositionX() {
return positionX;
}
public void setPositionX(double positionX) {
this.positionX = positionX;
}
public double getPositionY() {
return positionY;
}
public void setPositionY(double positionY) {
this.positionY = positionY;
}
public Color getColor() {
return color;
}
}
public class Ball {
private float speedX;
private float speedY;
private double radius;
private double positionX;
private double positionY;
private Color color;
public Ball(Color color, double positionX, double positionY,
double radius, float speedX, float speedY) {
this.color = color;
this.positionX = positionX;
this.positionY = positionY;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public float getSpeedX() {
return speedX;
}
public void setSpeedX(float speedX) {
this.speedX = speedX;
}
public float getSpeedY() {
return speedY;
}
public void setSpeedY(float speedY) {
this.speedY = speedY;
}
public double getRadius() {
return radius;
}
public double getPositionX() {
return positionX;
}
public void setPositionX(double positionX) {
this.positionX = positionX;
}
public double getPositionY() {
return positionY;
}
public void setPositionY(double positionY) {
this.positionY = positionY;
}
public Color getColor() {
return color;
}
}
}
The Man class you're trying to paint on isn't actually a displayable component. What other errors are you getting? They could all be related.
public class Man extends JComponent implements KeyListener {
This will allow the balls to be displayed and the game to start working. As for adding new balls, you may want to create a Ball Object as well as draw methods. You can then add multiple balls to the List and then draw each ball on the list each time your game needs to refresh itself.

Java swing rendering phenomenon in 2D Game

I am currently working on my first jump'n Run game. The initial part is already working decent, but i still get a "bug" which appears when my "colums" are moving. This only happens when "MOVE_SPEED" is 1<. I tryed it with a Timer too, same thing.
This is how it looks like:
Please have a look at the code:
...
public class Board implements Runnable, KeyListener {
JFrame frame;
ArrayList<Column> cList;
Player p;
private boolean ingame = false;
public final static int INIT_WIDTH = 600;
public final static int INIT_HEIGHT = 400;
public static int WIDTH;
public static int HEIGHT;
private final int MOVE_SPEED = 10;
//When this is 1 the problem doesnt appear!
private final int GRAVITY = -3;
private int cPlayerStayingOn;
private double playerBottom;
private double floorTop;
private boolean mR = false;
private boolean mL = false;
private boolean jump = false;
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 100;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
private int fps;
private int lastFpsTime;
public static double delta = 1;
public Board() {
initBoard();
initPlayer();
initColumns();
}
private void initBoard() {
frame = new JFrame("Jump'nRun");
frame.setSize(INIT_WIDTH, INIT_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.addKeyListener(this);
cList = new ArrayList<Column>();
frame.setVisible(true);
Board.WIDTH = frame.getContentPane().getWidth();
Board.HEIGHT = frame.getContentPane().getHeight();
}
private void initColumns() {
for (int i = 0; i < 8; i++) {
cList.add(new Column(i + 1, true));
frame.add(cList.get(i));
}
}
private void initPlayer() {
p = new Player();
frame.add(p);
}
private void moveColums() {
for (Column col : cList) {
col.setLocation((int) (col.getLocation().getX() - MOVE_SPEED), 0);
}
}
private int playerStanding(double pX) {
for (int i = 0; i < 8; i++) {
if (cList.get(i).getX() <= pX
&& (cList.get(i).getX() + cList.get(i).getWidth()) >= pX) {
return i;
}
}
return -1;
}
private void movePlayer() {
// gravity
if (playerBottom < floorTop) {
p.setLocation((int) p.getLocation().getX(), (int) p.getLocation()
.getY() - GRAVITY);
}
if (mR) {
p.moveRight();
}
if (mL) {
p.moveLeft();
}
if (jump) {
p.jump();
jump = false;
}
}
private void collectData() {
this.cPlayerStayingOn = playerStanding(p.getBounds().getX()
+ p.getBounds().getWidth());
this.playerBottom = p.getBounds().getMaxY();
this.floorTop = cList.get(cPlayerStayingOn).floor.getY();
}
private void recycleColums() {
if (cList.get(0).getX() + cList.get(0).getWidth() <= 0) {
cList.remove(0);
cList.add(7, new Column(7 + 1, false));
frame.add(cList.get(7));
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE
|| e.getKeyCode() == KeyEvent.VK_W
|| e.getKeyCode() == KeyEvent.VK_UP) {
if (playerBottom >= floorTop) {
jump = true;
}
}
if (e.getKeyCode() == KeyEvent.VK_D
|| e.getKeyCode() == KeyEvent.VK_RIGHT) {
mR = true;
}
if (e.getKeyCode() == KeyEvent.VK_A
|| e.getKeyCode() == KeyEvent.VK_LEFT) {
mL = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_D
|| e.getKeyCode() == KeyEvent.VK_RIGHT) {
mR = false;
}
if (e.getKeyCode() == KeyEvent.VK_A
|| e.getKeyCode() == KeyEvent.VK_LEFT) {
mL = false;
}
}
private int getFps() {
return fps;
}
private void setFps(int fps) {
this.fps = fps;
}
#Override
public void run() {
while (true) {
if (!ingame) {
ingame = true;
} else {
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
delta = updateLength / ((double) OPTIMAL_TIME);
lastFpsTime += updateLength;
setFps(getFps() + 1);
if (lastFpsTime >= 1000000000) {
lastFpsTime = 0;
setFps(0);
}
recycleColums();
collectData();
moveColums();
movePlayer();
try {
Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
} catch (Exception e) {
}
}
}
}
}
and the Column Class:
...
public class Column extends JPanel {
JPanel floor;
JPanel grass;
Random rand = new Random();
private static final long serialVersionUID = 1L;
public final static int WIDTH = Board.WIDTH / 6;
public final int HEIGHT = Board.HEIGHT;
private int position;
public final static int FLOOR_H = WIDTH;
public Column(int pos, boolean init) {
this.position = pos;
setBounds((WIDTH * position) - WIDTH, 0, WIDTH, HEIGHT);
setLayout(null);
setBackground(Color.WHITE);
floor = new JPanel();
floor.setLayout(null);
floor.setBackground(Color.BLACK);
if (init) {
floor.setBounds(0, HEIGHT - FLOOR_H, WIDTH, FLOOR_H);
} else {
floor.setBounds(0,
(HEIGHT - (FLOOR_H + (FLOOR_H * rand.nextInt(2) / 2))),
WIDTH, FLOOR_H * 2);
}
grass = new JPanel();
grass.setBounds(0, 0, WIDTH, 10);
grass.setBackground(Color.GREEN);
floor.add(grass);
add(floor);
}
}
Any hints are appreciatet!
(Sorry for the bad english)
i fixed it by changing the following:
private void recycleColums() {
if (cList.get(0).getX() + cList.get(0).getWidth() <= 0) {
cList.remove(0);
cList.add(7, new Column(7 + 1, false, cList.get(6).getX()));
frame.add(cList.get(7));
}
}
...
public Column(int pos, boolean init, int lastX) {
this.position = pos;
setLayout(null);
setBackground(Color.WHITE);
floor = new JPanel();
floor.setLayout(null);
floor.setBackground(Color.BLACK);
if (init) {
setBounds((WIDTH * position) - WIDTH, 0, WIDTH, HEIGHT);
floor.setBounds(0, HEIGHT - FLOOR_H, WIDTH, FLOOR_H);
} else {
setBounds(lastX + WIDTH, 0, WIDTH, HEIGHT);
floor.setBounds(0,
(HEIGHT - (FLOOR_H + (FLOOR_H * rand.nextInt(2) / 2))),
WIDTH, FLOOR_H * 2);
}

How to detect a collision?

I'm having a two image(a cat and a dog) inside the world which is in my Board class. The cat moves in a random direction while the dog move only when I press the arrow keys. My problem now is that how can I make the cat disappear whenever there is a collision between the two images? Any answer or idea would be much appreciated.
Here's what I've tried...
public class Cat extends Sprite implements ImageObserver
{
private java.awt.Image catImage;
private final Board board;
private double x;
private double y;
private double speed;
private double angle;
private boolean visible;
public Cat(Board board, double x, double y, double speed)
{
this.board = board;
this.x = x;
this.y = y;
this.speed = convertToMeterPerSecond(speed);
visible = true;
URL iU = this.getClass().getResource("cat.gif");
ImageIcon icon = new ImageIcon(iU);
catImage = icon.getImage();
}
public Image getImage()
{
return catImage;
}
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx_m = speed * dt_s * Math.sin(angle);
double dy_m = speed * dt_s * Math.cos(angle);
final double right_wall = board.x1_world;
final double up_wall = board.y1_world;
final double down_wall = 0.0;
final double left_wall = 0.0;
x += dx_m;
y += dy_m;
if (x >= right_wall)
{
x = right_wall;
setRandomDirection();
}
if (y > up_wall)
{
y = up_wall;
setRandomDirection();
}
if (x <= left_wall)
{
x = left_wall;
setRandomDirection();
}
if (y < down_wall)
{
y = down_wall;
setRandomDirection();
}
}
public void setRandomDirection()
{
Cat myObject = this;
myObject.setAngle(Math.PI * 2 * Math.random());
}
#Override
public void render(Graphics2D g2d)
{
AffineTransform t = g2d.getTransform();
double height = 0.3; //meter
double width = 0.3; //meter
double cat_footy = height;
double cat_footx = width / 2;
int xx = board.convertToPixelX(x - cat_footx);
int yy = board.convertToPixelY(y + cat_footy);
g2d.translate(xx, yy);
double x_expected_pixels = width * board.meter;
double y_expected_pixels = height * board.meter;
double x_s = x_expected_pixels / ((ToolkitImage) catImage).getWidth();
double y_s = y_expected_pixels / ((ToolkitImage) catImage).getHeight();
double w = ((ToolkitImage) catImage).getWidth();
double h = ((ToolkitImage) catImage).getHeight();
g2d.scale(x_s, y_s);
g2d.drawImage(getImage(), 0, 0, this); // upper left corner
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, (int) w, (int) h);
g2d.setTransform(t);
}
public void moveAt(double distance_x, double distance_y)
{
this.x = (int) distance_x;
this.y = (int) distance_y;
}
#Override
public Rectangle getBounds()
{
double w = ((ToolkitImage) catImage).getWidth();
double h = ((ToolkitImage) catImage).getHeight();
return new Rectangle((int) x, (int) y, (int) w, (int) h);
}
public void setAngle(double angle)
{
this.angle = angle;
}
public boolean isVisible()
{
return visible;
}
public void setVisible(Boolean visible)
{
this.visible = visible;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return true;
}
}
for my Cat class
public class Dog extends Sprite implements ImageObserver
{
private java.awt.Image humanImage;
private final Board board;
private double x;
private double y;
private double speed;
private boolean visible;
private double angle;
private double dx_m;
private double dy_m;
public Dog(Board board, double x, double y, double speed)
{
this.board = board;
this.x = x;
this.y = y;
this.speed = convertToMeterPerSecond(speed);
visible = true;
URL iU = this.getClass().getResource("dog.jpg");
ImageIcon icon = new ImageIcon(iU);
dogImage = icon.getImage();
}
public Image getImage()
{
return dogImage;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = -0.3;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0.3;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0.3;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = -0.3;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = 0;
}
}
#Override
public void move(long dt)
{
double dt_s = dt / 1e9;
final double right_wall = board.x1_world;
final double up_wall = board.y1_world;
final double down_wall = 0.0;
final double left_wall = 0.0;
x += dx_m;
y += dy_m;
if (x <= left_wall)
{
x = left_wall;
}
if (x >= right_wall)
{
x = right_wall;
}
if (y <= down_wall)
{
y = down_wall;
}
if (y >= up_wall)
{
y=up_wall;
}
}
public void setRandomDirection()
{
Dog myObject = this;
myObject.setAngle(Math.PI * 2 * Math.random());
}
#Override
public void render(Graphics2D g2d)
{
AffineTransform t = g2d.getTransform();
final double dogHeight = 1.6;// meter
final double dogWidth = 1.8; //meter
final double foot_position_y = dogHeight;
final double foot_position_x = dogWidth / 2;
int xx = board.convertToPixelX(x - foot_position_x); // to find the upper-left corner
int yy = board.convertToPixelY(y + foot_position_y); // to find the upper-left corner
g2d.translate(xx, yy);
// ratio for actual Image size
double x_expected_pixels = dogHeight * board.meter;
double y_expected_pixels = dogWidth * board.meter;
double w = ((ToolkitImage) dogImage).getWidth();
double h = ((ToolkitImage) dogImage).getHeight();
double x_s = x_expected_pixels / w;
double y_s = y_expected_pixels / h;
g2d.scale(x_s, y_s);
g2d.drawImage(getImage(), 0, 0, this); // upper left corner
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, (int) w, (int) h);
g2d.setTransform(t);
}
#Override
public void moveAt(double distance_x, double distance_y)
{
this.x = distance_x;
this.y = distance_y;
}
public void setAngle(double angle)
{
this.angle = angle;
}
#Override
public Rectangle getBounds()
{
double width = ((ToolkitImage) dogImage).getWidth();
double height = ((ToolkitImage) dogImage).getHeight();
return new Rectangle((int) x, (int) y, (int) width, (int) height);
}
public boolean isVisible()
{
return visible;
}
public void setVisible(Boolean visible)
{
this.visible = visible;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return true;
}
}
for my Dog class
public class Board extends Canvas
{
private Cat cat;
public static final long SECOND = 1000 * 1000 * 1000;
public double meter;//PIXEL
private HumanBeing humanBeing;
/**
* ascending from 0 to N
* 0 : most far way...
* N : is the closest (painted the last)
*/
private final java.util.List<Sprite> z_sorted_sprites = new ArrayList<Sprite>();
private BufferStrategy strategy;
int x0_pixel;
int y0_pixel;
int x1_pixel;
int y1_pixel;
double x1_world;
double y1_world;
private final Frame frame;
public Board(Frame frame, double meter)
{
addKeyListener(new TAdapter());
this.frame = frame;
this.setIgnoreRepaint(true);
this.meter = meter;
setFocusable(true);
dog = new Dog(this, 5, 5, 40);
init();
addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
render();
}
});
}
public void init()
{
z_sorted_sprites.add(new Cat(this, 0, 0, 30));
z_sorted_sprites.add(new Cat(this, 1, 1, 10));
z_sorted_sprites.add(new Cat(this, 2, 2, 20));
z_sorted_sprites.add(new Cat(this, 3, 3, 100));
}
public void render()
{
setupStrategy();
x0_pixel = 0;
y0_pixel = 0;
x1_pixel = getWidth();
y1_pixel = getHeight();
x1_world = x1_pixel / meter;
y1_world = y1_pixel / meter;
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
g2d.setBackground(Color.lightGray);
g2d.clearRect(0, 0, x1_pixel, y1_pixel);
g2d.setColor(Color.BLACK);
for (double x = 0; x < x1_world; x++)
{
for (double y = 0; y < y1_world; y++)
{
int xx = convertToPixelX(x);
int yy = convertToPixelY(y);
g2d.drawOval(xx, yy, 2, 2);
}
}
for (Sprite z_sorted_sprite : z_sorted_sprites)
{
z_sorted_sprite.render(g2d);
}
dog.render(g2d);
g2d.dispose();
strategy.show();
Toolkit.getDefaultToolkit().sync();
}
public int convertToPixelX(double distance)
{
return (int) (distance * meter);
}
public int convertToPixelY(double y_world)
{
return (int) (y1_pixel - (y_world * meter));
}
public void onZoomUpdated(int value)
{
meter = value;
render();
}
private void setupStrategy()
{
if (strategy == null)
{
this.createBufferStrategy(2);
strategy = this.getBufferStrategy();
}
}
public void start() throws InterruptedException
{
long prevLoopStart = System.nanoTime();
Avg avg = new Avg();
while (true)
{
final long loopStart = System.nanoTime();
final long dt = loopStart - prevLoopStart;
for (Sprite sprite : z_sorted_sprites)
{
sprite.move(dt);
}
dog.move(dt);
render();
frame.onFpsUpdated(1.0 / dt * SECOND, avg.add(loopStart));
final long elapsed_ns = System.nanoTime() - loopStart;
long expected_elapsed_ms = 1000 / 60;
long elapsed_ms = (long) (elapsed_ns / (1000.0 * 1000.0));
long sleep_ms = expected_elapsed_ms - elapsed_ms;
if (sleep_ms > 0)
{
Thread.sleep(sleep_ms /* ms */);
}
prevLoopStart = loopStart;
}
}
private void checkCollision()
{
Rectangle r2 = cat.getBounds();
Rectangle r3 = dog.getBounds();
if (r3.intersects(r2))
{
dog.setVisible(false);
cat.setVisible(false);
}
}
static class Avg
{
java.util.List<Long> ticks = new ArrayList<Long>();
/**
* #return the rate for the last second
*/
int add(long tick)
{
ticks.add(0, tick);
if (ticks.size() < 2)
{
return -1;
}
int last = -1;
for (int pos = ticks.size() - 1; pos >= 0; pos--)
{
if (tick - ticks.get(pos) <= SECOND)
{
last = pos;
break;
}
}
while (ticks.size() - 1 > last)
{
ticks.remove(ticks.size() - 1);
}
return ticks.size();
}
}
private class TAdapter extends KeyAdapter
{
public void keyReleased(KeyEvent e)
{
dog.keyReleased(e);
}
public void keyPressed(KeyEvent e)
{
dog.keyPressed(e);
}
}
}
For my Board class
public abstract class Sprite
{
public Sprite()
{
}
public Rectangle getBounds()
{
return new Rectangle();
}
public static double convertToMeterPerSecond(double speed)
{
// 25 km / hour
// 25000 m / 3600 s
return speed / 3.6;
}
public abstract void move(long dt);
public abstract void moveAt(double distance_x, double distance_y);
public abstract void render(Graphics2D g2d);
public abstract void setVisible(Boolean visible);
}
For my sprite class
public boolean checkCollisions(java.util.List<Sprite> sprites)
{
Dog dog = this;
Rectangle r1 = dog.getBounds();
for (int i = 0; i < sprites.size(); i++)
{
Rectangle r2 = sprites.get(i).getBounds();
if (r1.intersects(r2))
{
sprites.remove(i);
}
}
return true;
}
You have given a lot of code, but as Sibbo said, I don't see your checkCollisions method being called anywhere. It should be called every loop of your game.
Check out this tutorial, specifically look at the gameLoop method in the Game class. When I made a sprite based game that required a lot of collision detection this tutorial helped me out a lot.
I'd implement method that detects that positions of cat and dog overlap in the board class since board is the only instance that "knows" both dog and cat. The implementation is pretty simple: compare coordinates (something like dog.x + dog.width < cat.x || dog.x > cat.x + cat.width etc, etc.
If future you can implement more generic method, so if you will wish to add mouse you will be able to reuse the code.
The dog class doesn't overwrite the getBounds() method. So everytime you check if the rectangle (0, 0, 0, 0) intersects for example (3, 4, 50, 50) (if the cat is at (3, 4)).
Where do you call the checkCollision() method?
EDIT:
Create a method like your checkCollision() in your Dog class:
public boolean checkCollision(Sprite s) {...}
It should return true, when a collision is detected. Call this method from the Board.start() method for every Sprite in z_sorted_sprites. IF it returns true, remove the Sprite from the list.

Problems with InfiniteProgressDemo

I have implemented a small example using InfiniteProgressDemo and works perfectly, showing the "loading wheel" rotating at the center of the frame.
Now I have ported it to my program. I have a button for a connect action (do not worry about the BussinessException):
public class ConnectAction extends AbstractAction {
private JFrame framePrincipal;
private InfiniteProgressPanel glassPane;
/**
* Constructor
* #param m
* #param pNodos
* #param pGraficas
* #param front
* #throws BusinessException
*/
public ConnectAction(Main main, DockFrontend front) throws BusinessException{
super();
this.framePrincipal = main.getFramePrincipal();
this.glassPane = new InfiniteProgressPanel();
framePrincipal.setGlassPane(glassPane);
}
private void perform() throws BusinessException {
// DOING SOME HEAVY STUFF...
System.out.println("You've successfully waited :)");
glassPane.stop();
}
#Override
public Object execute() throws BusinessException {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
glassPane.start();
Thread performer = new Thread(new Runnable() {
public void run() {
try {
perform();
} catch (BusinessException e) {
e.printStackTrace();
}
}
}, "Performer");
performer.start();
}
});
return null;
}
#Override
public void redo() throws BusinessException {
// TODO Auto-generated method stub
}
#Override
public void undo() throws BusinessException {
// TODO Auto-generated method stub
}
#Override
protected void initServices() throws BusinessException {
}
}
The only file I needed from the InfiniteProgressDemo demo was InfiniteProgressPane.
When I execute and push my button, the "loading wheel" appears, but not at the center of the frame. It appears on one corner... next second it appears on another corner, and so on. I don't know what's wrong.
I also attach here the InfiniteProgressDemo:
public class InfiniteProgressPanel extends JComponent implements MouseListener
{
protected Area[] ticker = null;
protected Thread animation = null;
protected boolean started = false;
protected int alphaLevel = 0;
protected int rampDelay = 300;
protected float shield = 0.70f;
protected String text = "";
protected int barsCount = 14;
protected float fps = 15.0f;
protected RenderingHints hints = null;
public InfiniteProgressPanel()
{
this("");
}
public InfiniteProgressPanel(String text)
{
this(text, 14);
}
public InfiniteProgressPanel(String text, int barsCount)
{
this(text, barsCount, 0.70f);
}
public InfiniteProgressPanel(String text, int barsCount, float shield)
{
this(text, barsCount, shield, 15.0f);
}
public InfiniteProgressPanel(String text, int barsCount, float shield, float fps)
{
this(text, barsCount, shield, fps, 300);
}
public InfiniteProgressPanel(String text, int barsCount, float shield, float fps, int rampDelay)
{
this.text = text;
this.rampDelay = rampDelay >= 0 ? rampDelay : 0;
this.shield = shield >= 0.0f ? shield : 0.0f;
this.fps = fps > 0.0f ? fps : 15.0f;
this.barsCount = barsCount > 0 ? barsCount : 14;
this.hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
this.hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
this.hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public void setText(String text)
{
repaint();
this.text = text;
}
public String getText()
{
return text;
}
public void start()
{
addMouseListener(this);
setVisible(true);
ticker = buildTicker();
animation = new Thread(new Animator(true));
animation.start();
}
public void stop()
{
if (animation != null) {
animation.interrupt();
animation = null;
animation = new Thread(new Animator(false));
animation.start();
}
}
public void interrupt()
{
if (animation != null) {
animation.interrupt();
animation = null;
removeMouseListener(this);
setVisible(false);
}
}
public void paintComponent(Graphics g)
{
if (started)
{
int width = getWidth();
int height = getHeight();
double maxY = 0.0;
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHints(hints);
g2.setColor(new Color(255, 255, 255, (int) (alphaLevel * shield)));
g2.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < ticker.length; i++)
{
int channel = 224 - 128 / (i + 1);
g2.setColor(new Color(channel, channel, channel, alphaLevel));
g2.fill(ticker[i]);
Rectangle2D bounds = ticker[i].getBounds2D();
if (bounds.getMaxY() > maxY)
maxY = bounds.getMaxY();
}
if (text != null && text.length() > 0)
{
FontRenderContext context = g2.getFontRenderContext();
TextLayout layout = new TextLayout(text, getFont(), context);
Rectangle2D bounds = layout.getBounds();
g2.setColor(getForeground());
layout.draw(g2, (float) (width - bounds.getWidth()) / 2,
(float) (maxY + layout.getLeading() + 2 * layout.getAscent()));
}
}
}
private Area[] buildTicker()
{
Area[] ticker = new Area[barsCount];
Point2D.Double center = new Point2D.Double((double) getWidth() / 2, (double) getHeight() / 2);
double fixedAngle = 2.0 * Math.PI / ((double) barsCount);
for (double i = 0.0; i < (double) barsCount; i++)
{
Area primitive = buildPrimitive();
AffineTransform toCenter = AffineTransform.getTranslateInstance(center.getX(), center.getY());
AffineTransform toBorder = AffineTransform.getTranslateInstance(45.0, -6.0);
AffineTransform toCircle = AffineTransform.getRotateInstance(-i * fixedAngle, center.getX(), center.getY());
AffineTransform toWheel = new AffineTransform();
toWheel.concatenate(toCenter);
toWheel.concatenate(toBorder);
primitive.transform(toWheel);
primitive.transform(toCircle);
ticker[(int) i] = primitive;
}
return ticker;
}
private Area buildPrimitive()
{
Rectangle2D.Double body = new Rectangle2D.Double(6, 0, 30, 12);
Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 12, 12);
Ellipse2D.Double tail = new Ellipse2D.Double(30, 0, 12, 12);
Area tick = new Area(body);
tick.add(new Area(head));
tick.add(new Area(tail));
return tick;
}
protected class Animator implements Runnable
{
private boolean rampUp = true;
protected Animator(boolean rampUp)
{
this.rampUp = rampUp;
}
public void run()
{
Point2D.Double center = new Point2D.Double((double) getWidth() / 2, (double) getHeight() / 2);
double fixedIncrement = 2.0 * Math.PI / ((double) barsCount);
AffineTransform toCircle = AffineTransform.getRotateInstance(fixedIncrement, center.getX(), center.getY());
long start = System.currentTimeMillis();
if (rampDelay == 0)
alphaLevel = rampUp ? 255 : 0;
started = true;
boolean inRamp = rampUp;
while (!Thread.interrupted())
{
if (!inRamp)
{
for (int i = 0; i < ticker.length; i++)
ticker[i].transform(toCircle);
}
repaint();
if (rampUp)
{
if (alphaLevel < 255)
{
alphaLevel = (int) (255 * (System.currentTimeMillis() - start) / rampDelay);
if (alphaLevel >= 255)
{
alphaLevel = 255;
inRamp = false;
}
}
} else if (alphaLevel > 0) {
alphaLevel = (int) (255 - (255 * (System.currentTimeMillis() - start) / rampDelay));
if (alphaLevel <= 0)
{
alphaLevel = 0;
break;
}
}
try
{
Thread.sleep(inRamp ? 10 : (int) (1000 / fps));
} catch (InterruptedException ie) {
break;
}
Thread.yield();
}
if (!rampUp)
{
started = false;
repaint();
setVisible(false);
removeMouseListener(InfiniteProgressPanel.this);
}
}
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
Finally the problem is that getWidth() and getHeight() methods aren't getting the correct dimensions of the JFrame of my main windows, because they are called straigth forwards. Modifying the InfiniteProgressDemo constructors to receive a JFrame myFrame, and calling myFrame.getWidth() and myFrame.getHeight() got the animation working correctly in the center of the screen.

Categories