Basically, all that shows up is a JFrame with the black JPanel inside but no Ball/polygon anywhere. It's really annoying me now and I can't see the reason why. Any help greatly appreciated.
EDIT: Added code. Sorry for posting to Github, didn't know it was frowned upon.
public class Board extends JFrame {
private int width = 800;
private int height = 1000;
private int currentKeyCode = 0;
private boolean keyHeldDown = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Board b = new Board();
b.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Board() {
setSize(width, height);
setTitle("Drop");
setBackground(Color.BLACK);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
currentKeyCode = KeyEvent.VK_RIGHT;
keyHeldDown = true;
System.out.println("Right + 10");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
currentKeyCode = KeyEvent.VK_LEFT;
keyHeldDown = true;
System.out.println("Left + 10");
}
if (e.getKeyCode() == KeyEvent.VK_P) {
currentKeyCode = KeyEvent.VK_P;
keyHeldDown = true;
System.out.println("Pause");
}
}
#Override
public void keyReleased(KeyEvent e) {
keyHeldDown = false;
}
});
setContentPane(new Panel(this));
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
}
#Override
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
#Override
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
private class RepaintBoard implements Runnable {
final Board board;
public RepaintBoard(Board board) {
this.board = board;
}
#Override
public void run() {
board.repaint();
}
}
}
class Panel extends JComponent {
Ball ball;
private Board board;
public Panel(Board board) {
this.board = board;
ball = new Ball();
}
#Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setColor(Color.BLACK);
g.drawRect(0, 0, board.getWidth(), board.getHeight());
g.drawPolygon(ball);
}
}
class Ball extends Polygon {
private int radius = 5;
private Point loc;
private int[] xPos = new int[radius * 2 + 1];
private int[] yPos = new int[radius * 2 + 1];
public Ball() {
for (int i = -radius, j = 0; i <= radius; i++, j++) {
xPos[j] = i;
yPos[j] = i;
}
new Ball(xPos, yPos, radius * 2 + 1, 100, 100);
}
public Ball(int[] xPos, int[] yPos, int points, int x, int y) {
super(xPos, yPos, points);
loc = new Point(x, y);
for (int i : xPos) {
System.out.println(i);
}
}
}
Don't have Ball extends Polygon
Put a drawBall(Grapchics g) {} method in the Ball class, and do your ball painting in there.
call the drawBall method in the paint
ball.drawBall(g);
Don't override paint, instead override paintComponent on the panel, and don't forget to call super.paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
This new Ball(xPos, yPos, radius * 2 + 1, 100, 100); in your constructor does absolutely nothing. You should instead just use the second constructor, and create the ball with that constructor. Each ball should be different, so a no-arg constructor is pointless
Related
public class Board extends JPanel implements ActionListener {
private Player player;
private Timer timer;
public ArrayList<Enemy> enemyList;
public ArrayList<Bullet> bulletList;
private Random randomNumber;
public int WIDTH;
public int HEIGHT;
public Image plane;
public Image enemyimage;
private int x,y;
private final int DELAY = 25;
private final int B_WIDTH = 300;
private final int B_HEIGHT = 300;
private final int ICRAFT_X = 40;
private final int ICRAFT_Y = 60;
public Board(){
initBoard();
}
public void initBoard(){
addKeyListener(new TAdapter());
setBackground(Color.BLACK);
setFocusable(true);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
player = new Player();
loadImage();
timer = new Timer(DELAY, this);
timer.start();
}
public void loadImage(){
ImageIcon ii = new ImageIcon("src/resources/planeimage.png");
plane = ii.getImage();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
doDrawing(g);
}
public void doDrawing(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(player.getImage(),player.getX(),player.getY(),this);
ArrayList<Bullet> bulletList = player.getBullets();
for (Bullet bullet : bulletList){
g2d.drawImage(bullet.getImage(),bullet.getX(),bullet.getY(),this);
}
}
#Override
public void actionPerformed(ActionEvent e){
updateBullets();
updatePlayer();
repaint();
}
public void updateBullets() {
for (int i = 0; i < bulletList.size(); i++) {
Bullet bullet = bulletList.get(i);
if (bullet.isVisible()) {
bullet.move();
} else {
bulletList.remove(i);
}
}
}
public void updatePlayer(){
player.move();
}
private class TAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
player.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
player.keyPressed(e);
}
}
This is the player class which extends a vehicle class. Player constructor is being called in the board class and i guess, the problem lies their.
public class Player extends Vehicle{
public ArrayList<Bullet> bulletList;
public Player(){
super();
initPlayer();
}
public void initPlayer(){
bulletList = new ArrayList<>();
loadImage("src/resources/planeimage.png");
getImageDimensions();
}
#Override
public void move(){
x += dx;
y += dy;
}
public ArrayList<Bullet> getBullets(){
return bulletList;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
fire();
}
if (key == KeyEvent.VK_LEFT) {
dx = -1;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 1;
}
if (key == KeyEvent.VK_UP) {
dy = -1;
}
if (key == KeyEvent.VK_DOWN) {
dy = 1;
}
}
#Override
public void fire() {
bulletList.add(new Bullet(x + w, y + h / 2));
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = 0;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 0;
}
if (key == KeyEvent.VK_UP) {
dy = 0;
}
if (key == KeyEvent.VK_DOWN) {
dy = 0;
}
}
}
public class Application extends JFrame {
public Application() {
initUI();
}
private void initUI() {
add(new Board());
setSize(1024, 768);
setTitle("Application");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Application ex = new Application();
ex.setVisible(true);
});
}
}
Application class is the main class. Board class has all the code. When i run the program, only the black background is being shown, not the images. Why is that so, what am i doing wrong. Thank you.
I am creating a Space Invaders Game with just one Invader. The images are stuttering and are only visible ~10% of the time. What is wrong with my code?
package spaceinvader;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class spaceInvaders extends JApplet implements KeyListener, ActionListener
{
//Declare components and variables
JPanel mainPanel = new JPanel();
ImageIcon carImage = new ImageIcon("ship.png");
ImageIcon invaderImage = new ImageIcon("invader.png");
int intPosX = 240;
int intPosY = 330;
int intXAmount = 15;
boolean shipMoveLeft = false;
boolean shipMoveRight = false;
Timer shipTimer = new Timer(100,this);
int intBulletX = -50;
int intBulletY = -50;
boolean bulletMove = false;
boolean bulletActive = false;
Timer bulletTimer = new Timer(50,this);
int intInvaderX = 0;
int intInvaderY = 0;
int invaderXAmount = 10;
boolean invaderMove = true;
Timer invaderTimer= new Timer(1000,this);
public void init()
{
addKeyListener(this);
setFocusable(true);
resize(600,400);
setContentPane(mainPanel);
shipTimer.start();
bulletTimer.start();
invaderTimer.start();
}
public void actionPerformed(ActionEvent e)
{
requestFocus();
if(shipMoveLeft)
intPosX += intXAmount;
else if(shipMoveRight)
intPosX -= intXAmount;
if(bulletMove && bulletActive){
intBulletY -= 15;
if(intBulletY <= -50){
bulletMove = false;
bulletActive = false;
}
}
if(invaderMove){
intInvaderX += invaderXAmount;
if(intInvaderX > getWidth() - 60 || intInvaderX < 0){
intInvaderY += 40;
invaderXAmount *= -1;
}
}
repaint();
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == 37){
shipMoveRight = true;
}
else if (key == 39){
shipMoveLeft = true;
}
else if (key == 32){
if(bulletActive == false){
intBulletX = intPosX;
intBulletY = intPosY;
}
bulletMove = true;
bulletActive = true;
}
}
public void keyReleased(KeyEvent e)
{
shipMoveLeft = false;
shipMoveRight = false;
}
public void keyTyped(KeyEvent e)
{
}
public void paint(Graphics gr)
{
super.paint(gr);
gr.setColor(Color.red);
gr.fillOval(intBulletX, intBulletY, 10, 25);
carImage.paintIcon(this,gr, intPosX, intPosY); //Draw image in new spot
invaderImage.paintIcon(this,gr, intInvaderX, intInvaderY);
}
}
So there are a number of issues which jump out immediately...
Applets are a dead end, most browsers will actively block them and/or have dropped support for the plugin
You're adding a JPanel to the applet, but overriding the applet's paint method, because of the way painting can work, the panel can be painted independently of the applet, causing it to paint over whatever you might have painted
You don't need multiple timers, you just need to have better delta values (smaller been faster)
KeyListener is a poor choice for detecting keyboard input, it's rather low level and has focus related issues which are easily overcome by using the Key Bindings API
I'd start by having a look at Performing Custom Painting, Painting in AWT and Swing and How to Use Key Bindings for more details.
So how would you start fixing it? Start by using a JPanel as you basic container, override it's paintComponent and place all your paint logic here.
Use a single Timer to manage the updates
There are any number of approaches you can take, but I'd start with defining some contracts that define what can go on in the game
public interface GameSpace extends ImageObserver {
public Dimension getGameSpace();
public boolean hasInput(Input input);
}
public interface Entity {
public void paint(GameSpace gameSpace, Graphics2D g2d);
public boolean update(GameSpace gameSpace);
public Rectangle getBounds();
}
public abstract class AbstractEntity implements Entity {
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
protected abstract int getWidth();
protected abstract int getHeight();
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
}
public abstract class AbstractImageEntity extends AbstractEntity {
protected abstract BufferedImage getImage();
#Override
protected int getWidth() {
return getImage().getWidth();
}
#Override
protected int getHeight() {
return getImage().getHeight();
}
}
This separates some of management of key elements, allowing for a more flexible design. You might have a lot more entities, one's which could move, ones which could not, some which are painted, some which are not, but all which provide support for the core engine to get work done.
Once you have that you can start defining some core entities you need
public class ShipEntity extends AbstractImageEntity {
private BufferedImage ship;
public ShipEntity(GameSpace gameSpace) throws IOException {
ship = ImageIO.read(getClass().getResource("/resources/ship.png"));
setY(gameSpace.getGameSpace().height - getBounds().height);
setX((gameSpace.getGameSpace().width - getBounds().width) / 2);
}
#Override
public BufferedImage getImage() {
return ship;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(ship, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
int x = getX();
if (gameSpace.hasInput(Input.LEFT)) {
x -= 2;
}
if (gameSpace.hasInput(Input.RIGHT)) {
x += 2;
}
if (x < 0) {
x = 0;
} else if (x + getWidth() > gameSpace.getGameSpace().width) {
x = gameSpace.getGameSpace().width - getWidth();
}
setX(x);
return true;
}
}
public class InvaderEntity extends AbstractImageEntity {
private BufferedImage invader;
public InvaderEntity() throws IOException {
invader = ImageIO.read(getClass().getResource("/resources/Invader.png"));
}
#Override
protected BufferedImage getImage() {
return invader;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(invader, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
return true;
}
}
public class ProjectileEntity extends AbstractEntity {
private int delta;
public ProjectileEntity(int delta) {
this.delta = delta;
}
#Override
protected int getWidth() {
return 10;
}
#Override
protected int getHeight() {
return 10;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.setColor(Color.RED);
int width = getWidth();
int height = getHeight();
g2d.fillOval(getX() - width / 2, getY() - height / 2, width, height);
}
#Override
public boolean update(GameSpace gameSpace) {
int y = getY() + delta;
setY(getY() + delta);
return y + getHeight() >= 0 && y + getHeight() <= gameSpace.getGameSpace().height;
}
}
Basically, they contain the logic required for getting their jobs done.
Finally, you need to setup the actual game UI
public class GamePane extends JPanel implements GameSpace {
private Set<Input> inputs;
private Entity playerEntity;
private List<Entity> projectileEntities;
private List<Entity> invaderEntities;
private long timeOfLastProjectile = -1;
public GamePane() throws IOException {
setBackground(Color.BLACK);
inputs = new HashSet<>(2);
playerEntity = new ShipEntity(this);
projectileEntities = new ArrayList<>(25);
invaderEntities = new ArrayList<>(25);
InvaderEntity invader = new InvaderEntity();
invader.setX((getGameSpace().width - invader.getBounds().width) / 2);
invader.setY((getGameSpace().height - invader.getBounds().height) / 2);
invaderEntities.add(invader);
addKeyBinding(Input.LEFT, "left", KeyEvent.VK_LEFT);
addKeyBinding(Input.RIGHT, "right", KeyEvent.VK_RIGHT);
addKeyBinding(Input.SPACE, "space", KeyEvent.VK_SPACE);
Timer timer = new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
processCollisions();
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
protected void updateState() {
playerEntity.update(this);
if (hasInput(Input.SPACE)) {
long time = System.currentTimeMillis() - timeOfLastProjectile;
if (time < 0 || time > 1000) {
timeOfLastProjectile = System.currentTimeMillis();
Rectangle bounds = playerEntity.getBounds();
ProjectileEntity projectile = new ProjectileEntity(-1);
int x = bounds.x + ((bounds.width - projectile.getWidth()) / 2);
int y = bounds.y - projectile.getHeight();
projectile.setX(x);
projectile.setY(y);
projectileEntities.add(projectile);
}
}
for (Entity entity : invaderEntities) {
entity.update(this);
}
List<Entity> outOfBounds = new ArrayList<>(25);
for (Entity entity : projectileEntities) {
if (!entity.update(this)) {
outOfBounds.add(entity);
}
}
projectileEntities.removeAll(outOfBounds);
}
protected void processCollisions() {
Set<Entity> hitInvaders = new HashSet<>(25);
Set<Entity> hitProjectiles = new HashSet<>(25);
for (Entity invader : invaderEntities) {
for (Entity projectile : projectileEntities) {
if (projectile.getBounds().intersects(invader.getBounds())) {
// Maybe lots of cool explosiions
hitInvaders.add(invader);
hitProjectiles.add(projectile);
}
}
}
invaderEntities.removeAll(hitInvaders);
projectileEntities.removeAll(hitProjectiles);
}
protected void addKeyBinding(Input input, String name, int virtualKey) {
ActionMap am = getActionMap();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name + ".pressed");
im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name + ".released");
am.put(name + ".pressed", new KeyAction(inputs, input, true));
am.put(name + ".released", new KeyAction(inputs, input, false));
}
#Override
public Dimension getGameSpace() {
return getPreferredSize();
}
#Override
public boolean hasInput(Input input) {
return inputs.contains(input);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
playerEntity.paint(this, g2d);
g2d.dispose();
for (Entity entity : invaderEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
for (Entity entity : projectileEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
}
}
public class KeyAction extends AbstractAction {
private Input input;
private Set<Input> inputs;
private boolean pressed;
public KeyAction(Set<Input> inputs, Input input, boolean pressed) {
this.input = input;
this.inputs = inputs;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
inputs.add(input);
} else {
inputs.remove(input);
}
}
}
Now you could go a little further and generate an "engine" class which controls the entities and performs all the required updating, but I'm lazy ;)
That's a really rough idea of some the basic concepts you need to develop to be able to move forward, hope it helps
I am new to graphics in java and I am currently working on a game. Essentially, there are rising bubbles, and the user has to pop them by moving the mouse over them.
I have already made the bubbles but now for the collision detection, I need to be able to find the x and coordinates as well as the diameter of the circle. How can I return the instance variables for each bubble (from the Bubbles object array). You can see my code below. If you find coding errors, please let me know.
Game Class:
public class Game extends JPanel{
public static final int WINDOW_WIDTH = 600;
public static final int WINDOW_HEIGHT = 400;
private boolean insideCircle = false;
private static boolean ifPaused = false;
private static JPanel mainPanel;
private static JLabel statusbar;
private static int clicks = 0;
//Creates a Bubbles object Array
Bubbles[] BubblesArray = new Bubbles[5];
public Game() {
//initializes bubble objects
for (int i = 0; i < BubblesArray.length; i++)
BubblesArray[i] = new Bubbles();
}
public void paint(Graphics graphics) {
//makes background white
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
//paints square objects to the screen
for (Bubbles aBubblesArray : BubblesArray) {
aBubblesArray.paint(graphics);
}
}
public void update() {
//calls the Square class update method on the square objects
for (Bubbles aBubblesArray : BubblesArray) aBubblesArray.update();
}
public static void main(String[] args) throws InterruptedException {
statusbar = new JLabel("Default");
Game game = new Game();
game.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
statusbar.setText(String.format("Your mouse is at %d, %d", e.getX(), e.getY()));
}
public void mouseExited(MouseEvent e){
ifPaused = true;
}
public void mouseEntered(MouseEvent e){
ifPaused = false;
}
});
JFrame frame = new JFrame();
frame.add(game);
frame.add(statusbar, BorderLayout.SOUTH);
frame.setVisible(true);
frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Bubble Burst");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
while (true) {
if (!ifPaused){
game.update();
game.repaint();
Thread.sleep(5);
}
}
}
}
Bubbles Class:
public class Bubbles{
private int circleXLocation;
private int circleSize;
private int circleYLocation = Game.WINDOW_WIDTH + circleSize;
private int fallSpeed = 1;
private int color = (int) (4 * Math.random() + 1);
Random rand = new Random();
private int whereMouseX;
private int whereMouseY;
public int generateRandomXLocation(){
return circleXLocation = (int) (Game.WINDOW_WIDTH * Math.random() - circleSize);
}
public int generateRandomCircleSize(){
return circleSize = (int) (50 * Math.random() + 30);
}
public int generateRandomFallSpeed(){
return fallSpeed = (int) (5 * Math.random() + 1);
}
public void paint(Graphics g){
if (color == 1) g.setColor(new Color(0x87CEEB));
if (color == 2) g.setColor(new Color(0x87CEFF));
if (color == 3) g.setColor(new Color(0x7EC0EE));
if (color == 4) g.setColor(new Color(0x6CA6CD));
g.fillOval (circleXLocation, circleYLocation, circleSize, circleSize);
}
public Bubbles(){
generateRandomXLocation();
generateRandomCircleSize();
generateRandomFallSpeed();
}
public void update(){
if (circleYLocation <= - circleSize){
generateRandomXLocation();
generateRandomFallSpeed();
generateRandomCircleSize();
circleYLocation = Game.WINDOW_HEIGHT + circleSize;
}
if (circleYLocation > - circleSize){
circleYLocation -= fallSpeed;
}
}
public int getX(){
return circleXLocation;
}
public int getY(){
return circleYLocation;
}
public int getCircleSize(){
return circleSize;
}
}
Set your bubbles to include x and y values in it's constructor.
Public Bubble(float x, float y, int circleSize){
// initialize variables here
}
Then check to see if they are colliding with your current mouse location, something like...
if(e.getX() == this.getX() && e.getY() == this.getY()){
// do something
}
Loop through each Bubble in the array and access the public get methods you have created in the Bubble class:
Example:
for (Bubble b : BubblesArray)
{
int x = b.getX();
int y = b.getY();
}
I created a program that makes multiple bouncing balls with random color, speed and radius. When user clicks on the screen a new random ball should appear and move around screen. But i have a multi-thread issue. When i click on the screen a ball appears and doesn't moving at all. When another click comes nothing happens.
BouncingBalls Class
public class BouncingBalls extends JPanel implements MouseListener{
private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
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;
ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
}
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(){
ball.move(container);
}
class DrawCanvas extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
container.draw(g);
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("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
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) {
count++;
balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
balls.get(count-1).start();
start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Ball Class
import java.awt.Color;
import java.awt.Graphics;
public class Ball{
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private BouncingBalls balls;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball(int x, int y, int speedX, int speedY, int radius, int red, int green, int blue){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.red = red;
this.green = green;
this.blue = blue;
}
public void draw(Graphics g){
for(Ball ball : balls){
g.setColor(new Color(red, green, blue));
g.fillOval((int)(x - radius), (int)(y - radius), (int)(2 * radius), (int)(2 * radius));
}
}
public void move(Container container){
x += speedX;
y += speedY;
if(x - radius < 0){
speedX = -speedX;
x = radius;
}
else if(x + radius > 500){
speedX = -speedX;
x = 500 - radius;
}
if(y - radius < 0){
speedY = -speedY;
y = radius;
}
else if(y + radius > 500){
speedY = -speedY;
y = 500 - radius;
}
}
}
Container Class
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);
}
}
You're maintaing two different references to your ball.
You have a reference to a single Ball called ball and a List of balls. Your update and paint methods only reference the single ball
Ball doesn't seem to have a start method (that I can see) so this balls.get(count-1).start(); doesn't make sense...
Updated
You don't need the reference to ball
While not a bad idea, while testing, you should probably call start in the constructor
Your update method in BouncingBalls should looping through the balls list, calling move on each ball in the list...
The paintComponent method of DrawCanvas needs access to and should make use of the balls list. This might be better achievable through a model interface
Do not construct a new Ball with parameters, as it's giving each ball the same properties, especially when you assign random values to it when you construct it any way...
Ball doesn't have (or need) a start method
public class BouncingBalls extends JPanel implements MouseListener {
// private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
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;
// ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
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 (Ball ball : balls) {
ball.move(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (Ball ball : balls) {
ball.draw(g);
}
// 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("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
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) {
count++;
balls.add(new Ball());
// balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
// balls.get(count - 1).start();
// start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public static class Ball {
public int random(int maxRange) {
return (int) Math.round(Math.random() * maxRange);
}
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball() { //int x, int y, int speedX, int speedY, int radius, int red, int green, int blue) {
// this.x = x;
// this.y = y;
// this.speedX = speedX;
// this.speedY = speedY;
// this.radius = radius;
// this.red = red;
// this.green = green;
// this.blue = blue;
}
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));
}
public void move(Container container) {
x += speedX;
y += speedY;
if (x - radius < 0) {
speedX = -speedX;
x = radius;
} else if (x + radius > 500) {
speedX = -speedX;
x = 500 - radius;
}
if (y - radius < 0) {
speedY = -speedY;
y = radius;
} else if (y + radius > 500) {
speedY = -speedY;
y = 500 - radius;
}
}
}
public static 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);
}
}
}
Updated
As pointed out by the commentators, ArrayList is not thread safe, it's not a good idea to have multiple threads trying to access it simultaneously. While adding is slightly safer then removing, it is still bad practice.
You can either replace ArrayList with Vector, which would be the simpler solution, or synchronize the access to the list around a common monitor lock. Given your example, I'd use a java.util.Vector
You Can try this alternate Java Programm for bouncing 10 multi-colored balls on a single "START" button.....
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javaimage.io.*;
class Thr extends Thread
{
boolean up=false;
Ballbounce parent;
int top,left;
Color c;
Thr(int t,int l,Color cr,ex5 p)
{
top=l;
if(top > 170)
top=170-t/8;
left=t;
c=cr;
parent=p;
}
public void run()
{
try
{
while(true)
{
Thread.sleep(37);
if(top >= 188)
up=true;
if(top <= 0)
up=false;
if(!up)
top=top+2;
else
top=top-2;
parent.p.repaint();
}
}catch(Exception e){}
}
}
class Ballbounce extends JFrame implements ActionListener
{
int top=0,left=0,n=0,radius=50;
Color C[]={Color.black,Color.cyan,Color.orange,Color.red,Color.yellow,Color.pink,Color.gray,Color.blue,Color.green,Color.magenta};
Thr t[]=new Thr[10];
GPanel p;
JButton b;
Panel p1;
Ballbounce()
{
setSize(700,300);
setVisible(true);
setLayout( new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(p=new GPanel(this),BorderLayout.CENTER);
b= new JButton("Start");
b.addActionListener(this);
add(p1=new Panel(),BorderLayout.SOUTH);
p1.setBackground(Color.lightGray);
p1.add(b);
}
public static void main(String args[])
{
new Ballbounce();
}
public void actionPerformed(ActionEvent e)
{
t[n]=new Thr(left+(radius+13)*n+29,top+n*25,C[n],this);
t[n].start();
n++;
p.repaint();
if(n >9)
b.setEnabled(false);
}
}
class GPanel extends JPanel
{
Ballbounce parent;
GPanel(Ballbounce p)
{
parent=p;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.white);
for(int i=0;i< parent.n;i++)
{
g.setColor(parent.t[i].c);
g.fillOval(parent.t[i].left,parent.t[i].top,parent.radius,parent.radius);
}
}
}
I hope you will like it....
If u are unable to understand the code... You can question it anytime...... :)
Enjoy the code... :)
i want to create a Pong game. I want to move the ball in a way until it touch a wall. if it touch the wall, it go the other way. The problem is that when I start playing, the ball goes in the right way but when it touch the wall, the ball direction reverse but only for one pixel so the ball reverse for 1 pixel and then the direction change angain and it touch the wall again. My code for the moving ball is in the initBall method. Please help me :(
here is my playPanel class :
private int posX = SCREEN_WIDTH / 2;
private int posY;
public Point posMouse = new Point();
private Point posBall = new Point();
private int playPanelWidth;
private int playPanelHeight;
private int padPanelWidth;
private int padPanelHeight;
private int panPanelWidth;
private int panPanelHeight;
private JLabel player1Score = new JLabel("0");
private JLabel ComputerScore = new JLabel("0");
private JPanel panPlayer1;
public JPanel panComputer;
public JPanel padPlayer1;
public JPanel padComputer;
private JButton but_Escape = new JButton("Press escape to continue !");
/*
* Constructor
*/
// ==============================================
public PlayPanel() {
super(new BorderLayout());
setBackground(PANPLAY_COLOR);
panPlayer1 = new JPanel();
panComputer = new JPanel();
padPlayer1 = new JPanel();
padComputer = new JPanel();
padPlayer1.setBackground(Color.DARK_GRAY);
padComputer.setBackground(Color.DARK_GRAY);
padPlayer1.setPreferredSize(PADPANEL_SIZE);
padComputer.setPreferredSize(PADPANEL_SIZE);
panPlayer1.setBackground(PANPLAY_COLOR);
panComputer.setBackground(PANPLAY_COLOR);
panPlayer1.add(padPlayer1);
panComputer.add(padComputer);
add(panPlayer1, BorderLayout.WEST);
add(panComputer, BorderLayout.EAST);
addMouseMotionListener(this);
panPlayer1.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPanPanelWidth(arg0.getComponent().getSize().width);
setPanPanelHeight(arg0.getComponent().getSize().height);
}
});
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPlayPanelWidth(arg0.getComponent().getSize().width);
setPlayPanelHeight(arg0.getComponent().getSize().height);
}
});
}
/*
* Setters and Getters
*/
// ==============================================
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public JPanel getPanPlayer1() {
return panPlayer1;
}
public void setPanPlayer1(JPanel panPlayer1) {
this.panPlayer1 = panPlayer1;
}
public JPanel getPanComputer() {
return panComputer;
}
public void setPanComputer(JPanel panComputer) {
this.panComputer = panComputer;
}
public int getPlayPanelHeight() {
return playPanelHeight;
}
public void setPlayPanelHeight(int playPanelHeight) {
this.playPanelHeight = playPanelHeight;
}
public int getPlayPanelWidth() {
return playPanelWidth;
}
public void setPlayPanelWidth(int playPanelWidth) {
this.playPanelWidth = playPanelWidth;
}
public int getPadPanelWidth() {
return padPanelWidth;
}
public void setPadPanelWidth(int padPanelWidth) {
this.padPanelWidth = padPanelWidth;
}
public int getPadPanelHeight() {
return padPanelHeight;
}
public void setPadPanelHeight(int padPanelHeight) {
this.padPanelHeight = padPanelHeight;
}
public int getPanPanelWidth() {
return panPanelWidth;
}
public void setPanPanelWidth(int panPanelWidth) {
this.panPanelWidth = panPanelWidth;
}
public int getPanPanelHeight() {
return panPanelHeight;
}
public void setPanPanelHeight(int panPanelHeight) {
this.panPanelHeight = panPanelHeight;
}
/*
* Add the ball
*/
// ==============================================
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLACK);
initBall(g2);
// trait épais
g2.setColor(Color.DARK_GRAY);
g2.setStroke(new BasicStroke(10));
g2.drawLine((getPlayPanelWidth() / 2) - 5, getPlayPanelHeight(),
(getPlayPanelWidth() / 2) - 5, 0);
}
/*
* Init ball
*/
// ==============================================
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
Graphics2D g2 = graphics2d;
g2.fillOval(posX, posY, BALL_WIDTH, BALL_HEIGHT);
//posBall.setLocation(posX + BALL_WIDTH, posY + (BALL_HEIGHT / 2));
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
if (!backX)
setPosX(++x);
else {
setPosX(--x);
}
if (!backY)
setPosY(++y);
else
setPosY(--y);
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent arg0) {
posMouse.setLocation(arg0.getX(), arg0.getY()
- (getPadPanelHeight() / 2));
padPlayer1.setLocation(getPanPanelWidth() - 15, (int) posMouse.getY());
padComputer.setLocation(5, (int) posMouse.getY());
}
}
So you have:
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
in the beginning, so that regardless of which direction the ball is going, booth booleans are set to false every time. Then, you don't have an "Else" when it comes to setting the back option in
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
What is happening is that the ball is moving in the right direction, until it hits a wall (I'm guessing the top wall). then this is called:
if (y > getHeight() - 50)
backY = true;
So then for that iteration the ball goes back because of
if (!backY)
setPosY(++y);
else
setPosY(--y);
But then you set it back to false right away. I suggest you have
private boolean backX = false; //same for backY
outside your method.