I'm very confused as to why my scoreboard isn't updating on screen. The scores are increasing (I checked with debugger, also the ball is being centered). But the scoreboard isn't updating at all it constantly says "0 : 0"
Pong Class
package com.dheraxysgames.pong;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Pong extends JFrame{
private static final long serialVersionUID = 1L;
//Set Resolution
public static final int width = 300,
height = width / 4 * 3,
scale = 3;
public Pong() {
Dimension size = new Dimension(width * scale, height * scale);
setSize(size);
setTitle("PONG");
setResizable(false);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
}
public static int getWindowWidth(){
return width * scale;
}
public static int getWindowHeight(){
return height * scale;
}
public static void main(String[] args) {
new Pong();
}
}
GamePanel Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
public GamePanel(){
Timer time = new Timer(50, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
}
private void update(){
player.update();
ai.update();
ball.update();
ball.checkCollision(player);
ball.checkCollision(ai);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, Pong.getWindowWidth(), Pong.getWindowHeight());
g.setColor(Color.WHITE);
Font font = new Font("IMMORTAL", Font.BOLD, 50);
g.setFont(font);
g.drawString(player.score + " : " + ai.score, Pong.getWindowWidth() / 2 - 60, 50);
player.paint(g);
ai.paint(g);
ball.paint(g);
}
public Ball getBall(){
return ball;
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
//Keyboard
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(-10);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(10);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(0);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(0);
}
public void keyTyped(KeyEvent e) {
}
}
Player Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Player {
public int score = 0;
private static int width = 50,
height = 150;
private int x = 800, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public Player() {
}
public void update(){
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
AI Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class AI {
public int score = 0;
private static int width = 50,
height = 150;
private GamePanel field;
private int x = 50, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public AI(GamePanel game) {
this.field = game;
}
public AI(){
}
public void update(){
if(field.getBall().getY() < this.y) yV = -8;
if(field.getBall().getY() > this.y) yV = 8;
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
Ball Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Ball {
private int x = Pong.getWindowWidth() / 2, y = Pong.getWindowHeight() / 2,
xV = 10, yV = 10;
private static int size = 40;
Player player = new Player();
AI ai = new AI();
public void update() {
x += xV;
y += yV;
if (x < 0){
reverseXDirection();
player.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (x > Pong.getWindowWidth() - size){
reverseXDirection();
ai.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (y < 0 || y > Pong.getWindowHeight() - size - 38) reverseYDirection();
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillOval(x, y, size, size);
}
private void reverseXDirection(){
xV = -xV;
}
private void reverseYDirection(){
yV = -yV;
}
public void checkCollision(Player p) {
if (this.x + size > p.getX() && this.x + size < p.getX() + p.getWidth()){
if (this.y + size > p.getY() && this.y + size < p.getY() + p.getHeight()){
reverseXDirection();
}
}
}
public void checkCollision(AI ai) {
if (this.x > ai.getX() && this.x < ai.getX() + ai.getWidth()){
if (this.y > ai.getY() && this.y < ai.getY() + ai.getHeight()){
reverseXDirection();
}
}
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
In you're Ball class the score you're updating is not the same score that is being checked in the GamePanel class.
Notice how in both classes you are calling
Player player = new Player();
AI ai = new AI();
player and ai in Ball are seperate instances from the player and ai in GamePanel.
You will need to get the player and ai from the GamePanel class and pass them to the Ball class. The easiest way to do this would probably be to give Ball a constructor like so
Player player;
AI ai;
public Ball(Player player, AI ai) {
this.player = player;
this.ai = ai;
}
And in your GamePanel class change:
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
To this:
Player player = new Player();
AI ai = new AI(this);
Ball ball = new Ball(player, ai);
It's been a while since I've used java so I'm probably forgetting a simpler way to do this, but this should solve the problem.
Related
I'm making an java app (for exercise) where there must be a panel and 2 buttons.
Each time you press the start button a ball must be displayed and it moves based on thread. The user can display all the way up to 10 independent balls.
By pressing the stop button, 1 ball must be removed with each time the stop button is pressed (example, when there is 4 balls, the user must press 4 times stop button to remove all the balls independently)
All the x- and y coordinates of the balls must be stored in a Matrix
When 1 or more ball(s) are colliding with each other, only the colliding balls must change color from red to blue
Ok I'm almost done with it completely ( from point 1 to 4 ), but here comes my problem. When a ball is colliding with another, instead of changing the colors of the colliding balls to blue, my code is changing all the balls color from red to blue. I know that my error lies at the new Balls().setColor(Color.Blue), but I have no idea how to change only the colliding balls.
Below follows a screen shot of the java app and the code.
Can anyone help me with this headache?
Printscreen:
source code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;`
public class BouncingBalls extends JPanel implements ActionListener {
protected List<Ball> balls = new ArrayList<Ball>(10);
private final Container container;
private final DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public JButton start, stop;
int [][] coords= new int[11][2];
int ammountOfBalls = 0;
static Color clr= Color.RED;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
setLayout(new FlowLayout());
start= new JButton("start");
start.addActionListener(this);
stop= new JButton("stop");
stop.addActionListener(this);
add(start);
add(stop);
add(new JLabel(""));
container = new Container();
canvasWidth = width;
canvasHeight = height;
canvas = new DrawCanvas();
this.setLayout(new FlowLayout());
this.add(canvas);
start();
}
public void start() {
Thread t = new Thread() {
#Override
public void run() {
while (true) {
update();
getPositions();
collisionDetection();
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
}
}
}
private void collisionDetection() {
// The algorithm that detects collision
for(int i=0;i<ammountOfBalls;i++){
for(int j=i+1; j<ammountOfBalls; j++){
if(collisionMethod(i,j)){ // my collision method
//HOW DO I CHANGE ONLY THE COLLIDING BALLS COLOR HERE????
new Ball().setColor(Color.BLUE); // this line here changes the color of all the balls on the panel
System.out.println("Its a hit");
}
}
}
}
private void getPositions() {
int row=0;
for (Ball ball : balls) {
int x =ball.getXPosition();
int y =ball.getYPosition();
coords[row][0]=x;
coords[row][1]=y;
row++;
}
}
private boolean collisionMethod(int i, int j) {
float xd = coords[i][0]-coords[j][0];
float yd=coords[i][1]-coords[j][1];
float radius= new Ball().ballRadius;
float sqrRadius= radius * radius;
float distSqr= (xd * xd) + (yd * yd);
if(distSqr <= sqrRadius)
return true;
return false;
}
};
t.start();
}
public void update() {
for (Ball ball : balls) {
ball.move(container);
}
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == start){
if(ammountOfBalls < 10){
// to limit the ammount of balls to 10
balls.add(new Ball());
ammountOfBalls++;
}
}
else if( e.getSource() == stop){
if(ammountOfBalls > 0){
ammountOfBalls --;
balls.remove(ammountOfBalls);
}
}
}
class DrawCanvas extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (Ball ball : balls) {
ball.draw(g);
}
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(700, 400));
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setPreferredSize(new Dimension(800,500));
f.setContentPane(new BouncingBalls(800,800));
f.pack();
f.setVisible(true);
}
public static class Ball {
public int random(int maxRange) {
return (int) Math.round(Math.random() * maxRange);
}
int x = random(700); // method to get random coords for the x-value
int y = random(400); // method to get random coords for the y-value ...... these are used to get random positions for the balls instead of only static
int xMovement = 10;
int yMovement = 10;
int ballRadius = 20;
int i = 0;
public Color getColor(){
return clr;
}
public Color setColor(Color color){
clr=color;
return clr;
}
public void draw(Graphics g) {
g.setColor(getColor());
g.fillOval(x,y,ballRadius,ballRadius);
}
public int getXPosition(){
return x;
}
public int getYPosition(){
return y;
}
public void move(Container container) {
x += xMovement;
y += yMovement;
if (x - ballRadius < 0) {
xMovement = -xMovement;
x = ballRadius;
}
else if (x + ballRadius > 700) {
xMovement = -xMovement;
x = 700 - ballRadius;
}
if (y - ballRadius < 0) {
yMovement = -yMovement;
y = ballRadius;
}
else if (y + ballRadius > 400) {
yMovement = -yMovement;
y = 400 - ballRadius;
}
}
}
public static class Container {
private static final int hightPanel = 800;
private static final int widthPanel= 800;
public void draw(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, widthPanel, hightPanel);
}
}
}
`
You have defined clr as a static field of your application. When your Ball class calls setColor() you are changing the value of clr to blue... and then any Ball that calls getColor() will see that clr is blue.
Solution: Don't make clr an application-wide static field. Define it in the Ball class as a non-static field, so each Ball has its own color.
I put in a particle system but when i run the program, when I spawn some particles, they don't render. I looked at the ArrayList and its value would always be 0 even when i added a particle to it.
heres the code for main class:
package Main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import me.mango.rendering.Particle;
//do double buffering
public class Game extends JPanel {
private static final long serialVersionUID = 1L;
public static final int height = 400;
public static final int width = height * 16 / 9;
JPanel p;
Game game;
Graphics g;
JFrame frame;
KeyListener kl;
MouseListener ml;
public boolean running = true;
private ArrayList<Particle> particles = new ArrayList<Particle>(500);
public Game(){
kl = new KeyListener(){
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
};
ml = new MouseListener(){
public void mousePressed(MouseEvent e) {
addParticle(true);addParticle(false);addParticle(true);
addParticle(false);addParticle(true);addParticle(false);
}
public void mouseReleased(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
};
}
public void addParticle(boolean b){
int dx,dy;
int x = 100;
int y = 100;
if(b){
dx = (int) (Math.random()*5);
dy = (int) (Math.random()*5);
}else{
dx = (int) (Math.random()*-5);
dy = (int) (Math.random()*-5);
}
int size = (int) (Math.random()*12);
int life = (int) Math.random()*(120)+380;
particles.add(new Particle(x,y,dx,dy,size,life,Color.blue));
}
public void update(double delta){
for(int i = 0; i<= particles.size() - 1;i++){
if(particles.get(i).update()) particles.remove(i);
}
System.out.println(particles.size());
}
#Override
public void paint(Graphics g){
g.clearRect(0, 0, getWidth(), getHeight());
//render here
renderParticles(g);
g.dispose();
}
public void renderParticles(Graphics g){
for(int i =0;i <= particles.size() - 1;i++){
particles.get(i).render(g);
System.out.println("spawned");
}
}
public void run(){
//initialize time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
//Main game loop
while(running)
{
//Calculate since last update
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
lastFpsTime = 0;
}
//game updates
game.update(delta);
//graphics (gameState)
game.repaint();
try{
Thread.sleep((Math.abs(lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000));
}catch(Exception e){
System.out.println("Error in sleep");
}
}
}
public void start(){
frame = new JFrame("Game");
game = new Game();
frame.add(game);
frame.pack();
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.addKeyListener(kl);
frame.addMouseListener(ml);
frame.setVisible(true);
run();
}
public static void main(String[] args){
new Game().start();
}
}
and for the particle class:
package me.mango.rendering;
import java.awt.Color;
import java.awt.Graphics;
public class Particle {
private int x;
private int y;
private int dx;
private int dy;
private int size;
private int life;
private Color color;
public Particle(int x, int y, int dx, int dy, int size, int life, Color c){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.size = size;
this.life = life;
this.color = c;
}
public boolean update(){
x += dx;
y += dy;
life--;
if(life <= 0){
return true;
}
return false;
}
public void render(Graphics g){
g.setColor(color);
g.fillRect(x-(size/2), y-(size/2), size, size);
g.dispose();
}
}
Thanks!
You have a thing called game inside the class Game: that's not good design at all. Apparently you dont understand the meaning of creating an object.
In main() you created an object game: that should be enough. That thing you have to manipulate.
Therefore calling game.something() inside the class game is a convolution. Get rid of it.
game = new Game();
Game game;
These things must go.
And any reference to game.someMethod()
should be replaced with just someMethod(), if you are inside Game.
Plus you have things like run() and start() etc: do you think you are creating some threads?? by just using those names for your methods?
No.
Basically, I'm developing a Java game where I have to make the troops move to the nearest hall inside the panel (like in Clash of Clans).
I have a BasePanel class that initializes 5 objects (Halls) that are randomly placed anywhere in the panel. The BasePanel has a mouselistener that when clicked, drops another object (Troop) to the x and y coordinates. The Troop object has an attribute that moves in a linear pattern. My problem is that the troop object just moves in a downward direction.
The question is how do I get the Troop object move to the closest Hall object in the BasePanel?
Here is my code:
import javax.swing.*;
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.event.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
public class Test extends JFrame{
public static BasePanel panel1;
public static JButton baseClick, buttonClick, barbarian, archer, goblin;
public static int clicks=0, count1=10, count2=5, count3=7, hallCount=5, basePanelW=600, basePanelH=420;
public List<Troop> troops = new ArrayList<Troop>(20);
public List<Hall> halls = new ArrayList<Hall>(5);
public Thread gameThread;
Random rand = new Random();
float mouseX, mouseY;
float x = mouseX; // troop's center (x, y)
float y = mouseY;
double troopSpeedX = 1;
double troopSpeedY = 1;
float troopRadius = 5;
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test Test = new Test();
}
});
}
public void update() {
for (Troop troop : troops) {
troop.move(panel1);
}
}
class Hall{
int xVal = rand.nextInt(basePanelW);
int yVal = rand.nextInt(basePanelH);
public Hall(){}
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillOval(xVal, yVal, 50, 50);
}
public int getX(){
System.out.println("xVal: "+xVal);
return xVal;
}
public int getY(){
System.out.println("yVal: "+yVal);
return yVal;
}
}
class Troop{
float x = mouseX;
float y = mouseY;
double troopSpeedX = 1;
double troopSpeedY = 1;
float troopRadius = 5;
Hall h = new Hall();
public Troop(){}
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.fillOval((int) (x - troopRadius), (int) (y - troopRadius), (int)(2 * troopRadius), (int)(2 * troopRadius));
}
public void move(JPanel panel){
x += troopSpeedX;
y += troopSpeedY;
if (x - troopRadius < 0) {
troopSpeedX = -troopSpeedX;
x = troopRadius;
}else if (x + troopRadius > basePanelW) {
troopSpeedX = -troopSpeedX;
x = basePanelW - troopRadius;
}else if (y - troopRadius < 0) {
troopSpeedY = -troopSpeedY;
y = troopRadius;
}else if (y + troopRadius > basePanelH) {
troopSpeedY = -troopSpeedY;
y = basePanelH - troopRadius;
}repaint();
}
}
public void start(){
gameThread = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {Thread.sleep(100/3);}catch(InterruptedException ex){}
}
}
}; gameThread.start();
}
class BasePanel extends JPanel{
private BufferedImage image;
BasePanel(){
setPreferredSize(new Dimension(basePanelW,basePanelH));
setBackground(Color.green);
while(hallCount>0){
halls.add(new Hall());
hallCount--;
}
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
mouseX = e.getX();
mouseY = e.getY();
clicks++;
}
public void mouseReleased(MouseEvent e){
troops.add(new Troop());
}
});
}
private void msgbox(String s){
JOptionPane.showMessageDialog(null, s);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Troop troop : troops){
troop.paint(g);
}
}
public void paint(Graphics g){
super.paint(g);
for (Hall hall : halls){
hall.paint(g);
}
}
}
public Test(){
panel1 = new BasePanel();
add(panel1, BorderLayout.CENTER);
setVisible(true);
setSize(700,420);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start();
}
}
import java.awt.Graphics;
import javax.swing.JApplet;
import javax.swing.JPanel;
public class Circle extends JPanel {
int x = 75;
int y = 100;
int diameter = 50;
public void setAnimationY(int y) {
this.y = y;
}
public int getAnimationY() {
return y;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter) {
diameter = startDiameter;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, diameter, diameter);
}
}
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BouncingBall extends JApplet {
private int speed = 5;
private Timer timer;
private Circle draw;
#Override
public void init() {
super.init();
setLayout(new BorderLayout());
draw = new Circle();
add(draw);
timer = new Timer(30, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int y = draw.getAnimationY();
int diameter = draw.getDiameter();
int roof = getHeight();
y += speed;
if (y < 0) {
y = 0;
speed *= -1;
} else if (y + diameter > roof) {
y = roof - diameter;
speed *= -1;
}
draw.setAnimationY(y);
repaint();
}
});
}
#Override
public void start() {
super.start();
timer.start();
}
#Override
public void stop() {
timer.stop();
super.stop();
}
}
I am trying to create a JApplet that contains a ball that is bouncing up and down. So far I have been able to get the ball to go up and down but now I am trying to make the ball more "life-like" so I want the height of the ball to decrease each time the ball bounces until eventually it stops.
I have attempted to do a while loop using the roof variable that I created for the getHeight() method but for some reason when I tried to use it either the ball didn't move at all or the loop had no affect on the ball.
I have also tried a for loop but I ran into the same problem that I got into with the while loop. I believe the problem is that I am not placing this for loop in the correct spot for it to work correctly.
thanks in advance.
Little modifications to your code that can give you some trails:
#Override
public void actionPerformed(ActionEvent e) {
int y = draw.getAnimationY();
int diameter = draw.getDiameter();
int roof = getHeight();
y += speed;
//
// Reduce the ball size at the bottom of the screen
//
if(y + diameter > roof) {
if(diameter > minDiameter) {
diameter -= (roof - y);
} else {
diameter = minDiameter;
}
} else if (diameter < maxDiameter) {
diameter++;
}
draw.setDiameter(diameter);
if (y < 0) {
y = 0;
speed *= -1;
} else if (y + diameter > roof) {
y = roof - diameter;
speed *= -1;
}
// Simulates a little gravity
speed += 0.5;
draw.setAnimationY(y);
repaint();
}
For more realism, the best way would to find an equation that is function of the ball position and a coefficient of hardness for the ball and would give you the ball size.
Well let use continue with #MadProgrammer's solution from your other related question:
In your class of DrawPane we can easily define the height, getAnimationHeight() and setAnimationHeight(int) to control the height decrease as soon as it touches the ground. Please remember that in java left-top co-ordinate is (0, 0) and right-bottom co-ordinate is (getWidth(), getHeight()). Suppose that it starts from height = 0(top). Then it will start from y = height(top) and eventually move to the getHeight()(bottom) of your container. We will increase the height(top y) using setAnimationHeight() by adding an amount(say 30) to current height(which getAnimationHeight() will return) .
So, this little tweak made to #MadeProgrammer's solution in your other question will be the following demo.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
public class Circle extends JApplet {
private int delta = 8;
private Timer timer;
private DrawPane drawPane;
#Override
public void init() {
super.init();
setLayout(new BorderLayout());
drawPane = new DrawPane();
add(drawPane);
timer = new Timer(100, new ActionListener() {
int frameCount = 0;
#Override
public void actionPerformed(ActionEvent e) {
int y = drawPane.getAnimationY();
int diameter = drawPane.getDiameter();
y += delta;
if (y < drawPane.getAnimationHeight()) {
y = drawPane.getAnimationHeight();
delta *= -1;
} else if (y + diameter > getHeight()) {
y = getHeight()- diameter;
delta *= -1;
int animationHeight = drawPane.getAnimationHeight();
animationHeight = animationHeight + (getHeight() - diameter - animationHeight)/2;
drawPane.setAnimationHeight(animationHeight);
if(animationHeight + diameter + 2 >= getHeight())
{
System.out.println("true");
drawPane.setAnimationY(getHeight() - diameter);
repaint();
timer.stop();
return;
}
}
drawPane.setAnimationY(y);
repaint();
}
});
}
#Override
public void start() {
super.start();
timer.start();
}
#Override
public void stop() {
timer.stop();
super.stop();
}
public class DrawPane extends JPanel {
int x = 100;
int y = 0;
int diameter = 50;
int height = 0;
public void setAnimationX(int x) {
this.x = x;
}
public void setAnimationY(int y) {
this.y = y;
}
public void setAnimationHeight(int h)
{
height = h;
}
public int getAnimationHeight()
{
return height;
}
public int getAnimationX() {
return x;
}
public int getAnimationY() {
return y;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter) {
diameter = startDiameter;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, diameter, diameter);
}
}
}
NOTE: As soon as it touches the bottom finally, you should stop the Timer to get rid of the flickering of the ball. This task is left as an exercise for you.
I'm building a little "pong" game in Java.
I'm trying to add a scorekeeper up top that shows the updated score (+1) everytime the player saves the ball with the paddle.
I'm trying to use a JLabel but the problem is that I can't think of a way to continuously update the JLabel each time the paddle is hit.
Any ideas?
My code:
MainPanel Class (the one with the Paddle and Ball and Label)
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
//import swing.graphics.BounceFrame;
//import swing.graphics.Circle;
public class MainPanel extends JPanel implements ActionListener, KeyListener, Runnable{
public Paddle paddle;
public Ball ball;
public MainPanel(){
ball = new Ball(50, 50, 10); //centerX, centerY, radius
setSize(300, 300);
paddle = new Paddle();
JLabel scoreKeeper = new JLabel("Score" + ball.getScore());
add(scoreKeeper);
Thread thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D)g;
paddle.draw(g2);
ball.draw(g2);
}
public void actionPerformed(ActionEvent e) {
String direction = e.getActionCommand();
switch(direction){
case "left": Paddle.movePaddleLeft(); break;
case "right": Paddle.movePaddleRight(); break;
}
this.repaint();
}
public void run() {
try {
while(true){
ball.move(getBounds());
repaint();
Thread.sleep(500/30);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 37){
Paddle.movePaddleLeft();
}
if (e.getKeyCode() == 39){
Paddle.movePaddleRight();
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
And my Ball class:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.Random;
public class Ball {
private Ellipse2D ball;
private double radius;
private double ballCircumference;
private Color color;
private double x;
private double y;
private double dx = 5;
private double dy = 5;
private int score = 0;
public int getScore() {
return score;
}
//Boundaries to determine if ball is hit by paddle
private double criticalBoundaryX;
private double criticalBoundaryY1;
private double criticalBoundaryY2;
private double paddleHalfwayPoint;
private boolean inGame = true;
public void recalculateCriticals(){
criticalBoundaryX = Paddle.getYPosition() - ballCircumference;
criticalBoundaryY1 = Paddle.getXPosition()- ballCircumference; //Left boundary
criticalBoundaryY2 = Paddle.getXPosition()+Paddle.getPaddleWidth()+ballCircumference; //Right Boundary
paddleHalfwayPoint = (Paddle.getXPosition()+Paddle.getPaddleWidth())/2;
}
public Ball(int centerX, int centerY, int radius) {
this.x = centerX - radius;
this.y = centerY - radius;
this.radius = radius;
ballCircumference = 2*radius;
Random randomRGB = new Random();
color = new Color(randomRGB.nextInt(255), randomRGB.nextInt(255), randomRGB.nextInt(255));
this.ball = new Ellipse2D.Double(x, y, 2*radius, 2*radius);
}
public void move(Rectangle2D bounds) {
recalculateCriticals();
x += dx;
y += dy;
if (x < bounds.getMinX()) {
x = bounds.getMinX();
dx = -dx;
}
if (x + 2*radius >= bounds.getMaxX()) {
//System.out.println(bounds.getMaxX());
x = bounds.getMaxX() - 2*radius;
dx = -dx;
}
if (y < bounds.getMinY()) {
y = bounds.getMinY();
dy = -dy;
}
if (y > criticalBoundaryX){
if (x < criticalBoundaryY1 || x > criticalBoundaryY2){
inGame = false;
}
if (!inGame && hittingEdge(x))
dx = -dx;
}
if (y > criticalBoundaryX && inGame){ //When it hits the paddle
changeColor();
score++;
y = criticalBoundaryX;
dy = -dy;
}
if (y > bounds.getMaxY()){
System.out.println("Game Over");
System.exit(0);
}
recalculateCriticals();
ball.setFrame(x, y, 2*radius, 2*radius);
}
public boolean onPaddle(double x){
return ((x > Paddle.getXPosition()) && (x < Paddle.getXPosition()+Paddle.getPaddleWidth()) && (y > Paddle.getYPosition()-10));
}
public boolean hittingEdge(double x){
return ((x >= criticalBoundaryY1 && x < paddleHalfwayPoint)
||
(x <= criticalBoundaryY1 && x > paddleHalfwayPoint)); //Return true if x is hitting the side edge of the paddle
}
public void changeColor(){
Random randomColor = new Random();
color = new Color(randomColor.nextInt(255), randomColor.nextInt(255), randomColor.nextInt(255));
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.fill(ball);
}
}
The "Java way" of doing this would be to define a listener interface, for example:
public interface BallListener {
void paddleHit();
}
In the Ball class, you should add a field
private List<BallListener> listeners;
as well as methods
public void addBallListener(BallListener l) { listeners.add(l); }
public void removeBallListener(BallListener l) { listeners.remove(l); }
When the paddle is hit, you go:
for (BallListener l : listeners)
l.paddleHit();
The main class should implement the BallListener interface, and register itself with the ball (ball.addBallListener(this)).
This approach also enables you to, when needed, inform other parts of your program about different events that happen to the ball (i.e. add a new method to BallListener for each event you'd like to signal).