Tile/grid movement in Java (2d game) - java

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();
}
}
}

Related

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.

Firing a projectile in mouse direction in java

I'm trying to fire a projectile in the mouse direction but i am having trouble.
The angles are wrong, and by that I mean it will only go up left or in the top-left corner.
This is my Gun class for which I fire the Bullet.
package assets;
import Reaper.Game;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class Gun
{
public ArrayList<Bullet> bullets;
protected double angle;
Mouse mouse = new Mouse();
private BufferedImage image;
private int centerX = Game.WIDTH / 2;
private int centerY = Game.HEIGHT;
public Gun()
{
bullets = new ArrayList<Bullet>();
image = null;
try
{
image = ImageIO.read(new File("assets/gun.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public BufferedImage loadImage()
{
return image;
}
public int getImageWidth()
{
return image.getWidth(null);
}
public int getImageHeight()
{
return image.getHeight(null);
}
public void rotate(Graphics g)
{
angle = Math.atan2(centerY - mouse.getMouseY(), centerX - mouse.getMouseX()) - Math.PI / 2;
((Graphics2D) g).rotate(angle, centerX, centerY);
g.drawImage(image, Game.WIDTH / 2 - image.getWidth() / 2,
900 - image.getHeight(), image.getWidth(), image.getHeight(),
null);
}
public Image getImage()
{
return image;
}
public void update()
{
shoot();
for (int i = 0; i < bullets.size(); i++)
{
Bullet b = bullets.get(i);
b.update();
}
}
public void shoot()
{
if (mouse.mouseB == 1)
{
double dx = mouse.getMouseX() - Game.WIDTH / 2;
double dy = mouse.getMouseY() - Game.HEIGHT / 2;
double dir = Math.atan2(dy, dx);
bullets.add(new Bullet(Game.WIDTH / 2, Game.HEIGHT / 2, dir));
mouse.mouseB = -1;
}
}
public void render(Graphics g)
{
for (int i = 0; i < bullets.size(); i++)
{
bullets.get(i).render(g);
}
rotate(g);
}
}
This is my Bullet class:
package assets;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Bullet
{
private double dx, dy;
private int x, y;
private double dir;
private BufferedImage image;
public Bullet(int x, int y, double angle)
{
this.x = x;
this.y = y;
this.dir = angle;
image = null;
try
{
image = ImageIO.read(new File("assets/bolt.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
dx = Math.cos(dir);
dy = Math.sin(dir);
}
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
public void render(Graphics g)
{
g.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
}
public BufferedImage getImage()
{
return image;
}
}
And this is the main Game class:
package Reaper;
import Reaper.graphics.Screen;
import assets.Gun;
import assets.Mouse;
import gameState.MenuState;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable
{
private static final long serialVersionUID = 1L;
public static int WIDTH = 900;
public static int HEIGHT = 900;
public static int scale = 3;
public int frames = 0;
public int updates = 0;
private boolean running = false;
private Thread thread;
private JFrame frame;
#SuppressWarnings("unused")
private Screen screen;
private Gun gun;
private MenuState mns;
private Mouse mouse;
public Game()
{
Dimension size = new Dimension(WIDTH, HEIGHT);
setPreferredSize(size);
screen = new Screen(WIDTH, HEIGHT);
frame = new JFrame();
gun = new Gun();
mns = new MenuState();
mouse = new Mouse();
addMouseListener(mouse);
addMouseMotionListener(mouse);
}
public static void main(String[] args)
{
Game game = new Game();
game.frame.setResizable(false);
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setVisible(true);
game.frame.setLocationRelativeTo(null);
game.strat();
}
public void strat()
{
running = true;
thread = new Thread(this, "Reaper");
thread.start();
}
public void stop()
{
running = false;
try
{
thread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void run()
{
long timer = System.currentTimeMillis();
long lastTime = System.nanoTime();
double ns = 1000000000.0 / 60;
double delta = 0;
while (running)
{
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1)
{
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000)
{
timer = System.currentTimeMillis();
frame.setTitle("Reaper! " + " | " + updates + " ups , " + frames + " fps");
updates = 0;
frames = 0;
}
}
stop();
}
public void update()
{
if (mns.play)
{
gun.update();
}
}
public void render()
{
BufferStrategy bs = getBufferStrategy();
if (bs == null)
{
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.fillRect(0, 0, WIDTH, HEIGHT);
if (mns.menu)
{
mns.draw(g);
}
if (mns.play)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
g.drawImage(mns.getImage(), 0, 0, mns.getImageWidth(), mns.getImageHeight(), this);
gun.render(g);
}
if (mns.rules)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
}
bs.show();
}
}
I know it's very badly coded, and I will try to fix it as much as I can, but I am really stuck on this. Searched around the web, tried some of the solutions but it wont work. I guess I'm doing it wrong by putting methods in wrong places and calling them, I guess.
I know it's very badly coded, and I will try to fix it as much as I can, ...
Next time, consider first cleaning up the mess and then asking the question.
(Are the variables storing the values returned by getMouseX() and getMouseY() really static?)
However, the main reason for the actual problem are the x and y values in the Bullet class:
class Bullet
{
private double dx, dy;
private int x, y;
....
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
...
}
They are declared as int values. Imagine what happens in the update method, for example, when x=0 and dx = 0.75: It will compute 0+0.75 = 0.75, truncate this to be an int value, and the result will be 0.
Thus, the x and y values will never change, unless the dx and dy values are >= 1.0, respectively.
Just changing the type of x and y to double will solve this. You'll have to add casts in the render method accordingly:
g.drawImage(image, (int)x, (int)y, ...);
But you should really clean this up.

How to make two balls collide and deflect in opposite directions?

I have written the code for movement of two balls within a rectangle(canvas). The balls deflect in opposite direction when they hit the top, bottom, left or right of the rectangle. But,I've tried in vain to make the balls collide with each other and deflect in opposite direction. I have searched many sites and articles but in vain. Can someone please help.
This is MainActivity.java
package com.example.movements;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MovementView(this));
}
}
This is MovementView.java
package com.example.movements;
public class MovementView extends SurfaceView implements SurfaceHolder.Callback{
private int xPos,xPos1;
private int yPos,yPos1;
private int xVel,xVel1;
private int yVel,yVel1;
private int width;
private int height;
private int circleRadius,circleRadius1;
private Paint circlePaint,circlePaint1;
UpdateThread updateThread;
public MovementView(Context context) {
super(context);
getHolder().addCallback(this);
circleRadius = 10;
circlePaint = new Paint();
circlePaint.setColor(Color.BLUE);
xVel = 10;
yVel = 10;
circleRadius1 = 10;
circlePaint1 = new Paint();
circlePaint1.setColor(Color.MAGENTA);
xVel1 = 11;
yVel1 = 11;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawCircle(xPos, yPos, circleRadius, circlePaint);
canvas.drawCircle(xPos1, yPos1, circleRadius1, circlePaint1);
}
public void updatePhysics() {
xPos += xVel;
yPos += yVel;
if (yPos - circleRadius < 0 || yPos + circleRadius > height) {
if (yPos - circleRadius < 0) {
yPos = circleRadius;
}else{
yPos = height - circleRadius;
}
yVel *= -1;
}
if (xPos - circleRadius < 0 || xPos + circleRadius > width) {
if (xPos - circleRadius < 0) {
xPos = circleRadius;
} else {
xPos = width - circleRadius;
}
xVel *= -1;
}
xPos1 += xVel1;
yPos1 += yVel1;
if (yPos1 - circleRadius1 < 0 || yPos1 + circleRadius1 > height) {
if (yPos1 - circleRadius1 < 0) {
yPos1 = circleRadius1;
}else{
yPos1 = height - circleRadius1;
}
yVel1 *= -1;
}
if (xPos1 - circleRadius1 < 0 || xPos1 + circleRadius1 > width) {
if (xPos1 - circleRadius1 < 0) {
xPos1 = circleRadius1;
} else {
xPos1 = width - circleRadius1;
}
xVel1 *= -1;
}
}
public void surfaceCreated(SurfaceHolder holder) {
Rect surfaceFrame = holder.getSurfaceFrame();
width = surfaceFrame.width();
height = surfaceFrame.height();
xPos = width / 2;
yPos = circleRadius;
xPos1 = width / 2;
yPos1 = circleRadius1;
updateThread = new UpdateThread(this);
updateThread.setRunning(true);
updateThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
updateThread.setRunning(false);
while (retry) {
try {
updateThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
This is UpdateThread.java
package com.example.movements;
import android.view.SurfaceHolder;
public class UpdateThread extends Thread {
private long time;
private final int fps = 20;
private boolean toRun = false;
private MovementView movementView;
private SurfaceHolder surfaceHolder;
public UpdateThread(MovementView rMovementView) {
movementView = rMovementView;
surfaceHolder = movementView.getHolder();
}
public void setRunning(boolean run) {
toRun = run;
}
#Override
public void run() {
Canvas c;
while (toRun) {
long cTime = System.currentTimeMillis();
if ((cTime - time) <= (1000 / fps)) {
c = null;
try {
c = surfaceHolder.lockCanvas(null);
movementView.updatePhysics();
movementView.onDraw(c);
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
time = cTime;
}
}
}
To check wether they are hitting each other, you can just check if the distance between their centers is smaller than (radius*2). To make a nice deflection, you'll have to do some math that's beyond me. Here is another answer on that.
I've googled it a bit and apparantly the term used in physics for this problem is called elastic collision. I've found a nice tutorial on the subject here (especially the dynamic circle-circle collision bit). Also, here is an applet which demonstrates this. The source code for this can be found [here]

Getting NPE in 2D Game thread

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);

Java Multithread

After making changes based on user suggestions I have taken the following code a few steps further by introducing single/double click recognition. Why are the balls being created in the top left corner and not where the mouse is clicked?
BouncingBalls.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BouncingBalls extends JPanel implements MouseListener {
protected List<RandomBall> randomBalls = new ArrayList<RandomBall>(20);
protected List<VerticalBall> verticalBalls = new ArrayList<VerticalBall>(20);
private Container container;
private DrawCanvas canvas;
private Boolean doubleClick = false;
private final Integer waitTime = (Integer) Toolkit.getDefaultToolkit()
.getDesktopProperty("awt.multiClickInterval");
private static int canvasWidth = 500;
private static int canvasHeight = 500;
public static final int UPDATE_RATE = 30;
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
canvasWidth = width;
canvasHeight = height;
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
start();
}
public void start() {
Thread t = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
public void update() {
for (RandomBall ball : randomBalls) {
ball.ballBounce(container);
}
for (VerticalBall ball : verticalBalls) {
ball.verticalBounce(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (RandomBall ball : randomBalls) {
ball.draw(g);
}
for (VerticalBall ball : verticalBalls) {
ball.draw(g);
}
}
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Stack Answer 2");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(canvasHeight, canvasWidth));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() >= 2) {
doubleClick = true;
verticalBalls.add(new VerticalBall(getX(), getY(), canvasWidth, canvasHeight));
System.out.println("double click");
} else {
Timer timer = new Timer(waitTime, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (doubleClick) {
/* we are the first click of a double click */
doubleClick = false;
} else {
count++;
randomBalls.add(new RandomBall(getX(), getY(), canvasWidth, canvasHeight));
/* the second click never happened */
System.out.println("single click");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
RandomBall.java
import java.awt.Color;
import java.awt.Graphics;
public class RandomBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean leftRight;
private boolean upDown;
private int deltaX;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
RandomBall(int x, int y, int width, int height) {
this(x, y, width, height, false, false);
}
RandomBall(int x, int y, int width, int height, boolean leftRight, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.leftRight = leftRight;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
deltaX = minimumMovement + (int) (Math.random() * maxExtra);
}
public void ballBounce(Container container) {
// controls horizontal ball motion
if (leftRight) {
x += deltaX;
if (x >= getWidth()) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
VerticalBall.java
import java.awt.Color;
import java.awt.Graphics;
public class VerticalBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean upDown;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
VerticalBall(int x, int y, int width, int height) {
this(x, y, width, height, false);
}
VerticalBall(int x, int y, int width, int height, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
Container.java
import java.awt.Color;
import java.awt.Graphics;
public class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g) {
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
Change your move method in the Ball class with this one (your conditions are not corrects) :
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= canvasWidth) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (canvasHeight));
if (y >= (canvasHeight)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
I run it and it works
Your movement logic is overly complicated for simply moving a ball, you should think about conservation of momentum if you want it to bounce off the walls.
The problem is
x >= (Ball.this.getWidth() - canvasWidth / 2)` and `y >= (Ball.this.getHeight() - canvasHeight / 2)
You are creating balls using the first constructor
balls.add(new Ball(x, y, canvasWidth, canvasHeight));
So you are just checking if x>=0 and y>=0, it will keep bouncing around with +- deltax/deltay positions.
A simpler way of making it bounce off walls would be
public void move(Container container) {
if(x>=canvasWidth || x<=0){
deltaX = -1*deltaX;
}
if(y>=canvasHeight || y<=0){
deltaY = -1*deltaY;
}
x+= deltaX;
y+= deltaY;
}
change
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= (Ball.this.getWidth() - canvasWidth / 2)) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (Ball.this.getHeight() - canvasHeight / 2));
if (y >= (Ball.this.getHeight() - canvasHeight / 2)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
to
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= getWidth()) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
It's because you're using Ball.this.getWidth() and getHeight()...which are set to the canvas height in the constructor. If you use the radius instead, it works. For example:
if ( x >= ( canvasWidth - radius ) )
{
leftRight = false;
updateDelta();
}
And:
if ( y >= ( canvasHeight - radius ) )
{
upDown = false;
updateDelta();
}

Categories