Julian Jacobs Julian Jacobs - 2 months ago 4
Java Question

JAVA why isnt my 2nd circle moving with arrow keys

I am confused on why this code doesn't make the second ball move. My goal is to have two balls and you are controlling one of them and the other one is just randomly bouncing around. Right now I am stuck on the arrow key ball. I don't understand why it is not moving via arrow-keys.

import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Formatter;
import javax.swing.*;
/**
* One ball bouncing inside a rectangular box.
* All codes in one file. Poor design!
*/
// Extends JPanel, so as to override the paintComponent() for custom rendering codes.
public class Man extends JPanel {
// Container box's width and height
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;

private boolean upPressed = false;
private boolean downPressed = false;
private boolean leftPressed = false;
private boolean rightPressed = false;

// Ball's properties
private float ballRadius = 20; // Ball's radius
private float ballX = ballRadius + 50; // Ball's center (x, y)
private float ballY = ballRadius + 20;
private float ballSpeedX = 3; // Ball's speed for x and y
private float ballSpeedY = 2;
// ball # 2
public float ballSpeedX2 = 0;
public float ballSpeedY2 = 0;
private float ball2Radius = 20; // Ball's radius
private float ball2X = 320; // Ball's center (x, y)
private float ball2Y = 240;

private static final int UPDATE_RATE = 30; // Number of refresh per second

/** Constructor to create the UI components and init game objects. */
public Man() {
this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));

// Start the ball bouncing (in its own thread)
Thread gameThread = new Thread() {
public void step(){
ball2X += ballSpeedX2;
ball2Y += ballSpeedY2;

if (rightPressed) {
ballSpeedX2+=5;
}
if (leftPressed) {
ballSpeedX2-=5;
}
if (upPressed) {
ballSpeedY2-=5;
}
if (downPressed) {
ballSpeedY2+=5;
}

repaint();
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}
public void run() {
while (true) { // Execute one update step
// Calculate the ball's new position
ballX += ballSpeedX;
ballY += ballSpeedY;
// Check if the ball moves over the bounds
// If so, adjust the position and speed.
if (ballX - ballRadius < 0) {
ballSpeedX = -ballSpeedX; // Reflect along normal
ballX = ballRadius; // Re-position the ball at the edge
} else if (ballX + ballRadius > BOX_WIDTH) {
ballSpeedX = -ballSpeedX;
ballX = BOX_WIDTH - ballRadius;
}
// May cross both x and y bounds
if (ballY - ballRadius < 0) {
ballSpeedY = -ballSpeedY;
ballY = ballRadius;
} else if (ballY + ballRadius > BOX_HEIGHT) {
ballSpeedY = -ballSpeedY;
ballY = BOX_HEIGHT - ballRadius;
}
// Refresh the display
repaint(); // Callback paintComponent()
// Delay for timing control and give other threads a chance
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}
}
};
gameThread.start(); // Callback run()
}

/** Custom rendering codes for drawing the JPanel */
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint background

// Draw the box
g.setColor(Color.BLACK);
g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);

// Draw the ball
g.setColor(Color.BLUE);
g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
(int)(2 * ballRadius), (int)(2 * ballRadius));

// Display the ball's information
g.setColor(Color.WHITE);
g.setFont(new Font("Courier New", Font.PLAIN, 12));
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);
formatter.format("Ball @(%3.0f,%3.0f) Speed=(%2.0f,%2.0f)", ballX, ballY,
ballSpeedX, ballSpeedY);
g.drawString(sb.toString(), 20, 30);
g.setColor(Color.BLUE);

g.fillOval((int) (ball2X - ball2Radius), (int) (ball2Y - ball2Radius),
(int)(2 * ball2Radius), (int)(2 * ball2Radius));

g.setColor(Color.RED);
g.setFont(new Font("Courier New", Font.PLAIN, 12));
g.drawString(sb.toString(), 20, 30);
g.setColor(Color.GREEN);}

public void keyPressed(KeyEvent e) {

if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
rightPressed = true;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
leftPressed = true;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
upPressed = true;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
downPressed = true;
}

repaint();
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}

public void keyReleased(KeyEvent e) {

if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
rightPressed = false;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
leftPressed = false;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
upPressed = false;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
downPressed = false;
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}}

public void keyTyped(KeyEvent e) {}

/** main program (entry point) */
public static void main(String[] args) {
// Run GUI in the Event Dispatcher Thread (EDT) instead of main thread.

javax.swing.SwingUtilities.invokeLater(new Runnable() {

public void run() {
// Set up main window (using Swing's Jframe)
JFrame frame = new JFrame("A Bouncing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new Man());
frame.pack();
frame.setVisible(true);
}
});
}
}

Answer

I modified your code a bit, I deleted things non-related to moving of a 2nd ball, so you can see how it all works, plus I don't want to give you a complete answer, you will have to first understand what happens and modify your current code accordingly.

First - you need a KeyListener. Name is self-explanatory, it listens for keyboard clicks. You do it by implements KeyListener on your class. Then you need to add that listener to your frame - frame.addKeyListener(cat) in my code. Then you need to actually move a ball inside loop in run method (ball2X += ballSpeedX2 etc.). Also in your code you had delays basically everywhere - that's not a good idea, they will block everything. In your code you have a step method and you are not calling it anywhere - modify it and call it in a run method, or just put all the code in run method if you want. If you want ball to move only when you click (1 click - 1 move, no holding) then after changing it's positions set speed to 0. If you want it to move when you are holding key - set speeds to 0 on keyRelease, but be careful, what if you are holding left and right at the same time? You need to take care of that. Ok here's code, I basically moved some lines, added maybe 5 lines (for KeyListener) and removed code non-related to 2nd ball, it's in 98% your own code.

btw. I changed class name to Cat so put it in Cat.java not Man.java!

import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Formatter;
import javax.swing.*;
import java.awt.event.*;
public class Cat extends JPanel implements KeyListener {

    private static final int BOX_WIDTH = 640;
    private static final int BOX_HEIGHT = 480;
    private float ballSpeedX2 = 0;
    private float ballSpeedY2 = 0;
    private float ball2Radius = 20;
    private float ball2X = 120;
    private float ball2Y = 140;

    private static final int UPDATE_RATE = 30;

    public Cat() {
        this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
        Thread gameThread = new Thread() {
            public void run() {
                while (true) {
                    ball2X += ballSpeedX2;
                    ball2Y += ballSpeedY2;
                    if (ball2X - ball2Radius < 0) {
                        ballSpeedX2 = -ballSpeedX2;
                        ball2X = ball2Radius;
                    } else if (ball2X + ball2Radius > BOX_WIDTH) {
                        ballSpeedX2 = -ballSpeedX2;
                        ball2X = BOX_WIDTH - ball2Radius;
                    }

                    if (ball2Y - ball2Radius < 0) {
                        ballSpeedY2 = -ballSpeedY2;
                        ball2Y = ball2Radius;
                    } else if (ball2Y + ball2Radius > BOX_HEIGHT) {
                        ballSpeedY2 = -ballSpeedY2;
                        ball2Y = BOX_HEIGHT - ball2Radius;
                    }
                    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) (ball2X - ball2Radius), (int) (ball2Y - ball2Radius),
                   (int)(2 * ball2Radius), (int)(2 * ball2Radius));
    }

    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
            ballSpeedX2 = 5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
            ballSpeedX2 = -5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP ) {
            ballSpeedY2 = -5;
        }
        else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
            ballSpeedY2 = 5;
        }
    }

    public void keyReleased(KeyEvent e) { }
    public void keyTyped(KeyEvent e) { }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("A Bouncing Ball");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                Cat cat = new Cat();
                frame.setContentPane(cat);
                frame.pack();
                frame.addKeyListener(cat);
                frame.setVisible(true);
            }
        });
    }
}
Comments