Home > Software engineering >  Color Randomizer for Java Pong game
Color Randomizer for Java Pong game

Time:05-12

I'm trying to alter this java pong game code in a way so that the color of the background, ball and paddles changes whenever the ball hits either the paddles or walls, but make it so that none of are the same color so that way the players can still see where they are. Any idea on how I can do so?

Main

package ponggame;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;

public class pong extends JFrame {
    
    //Sets screen dimensions.
    int ScreenWidth = 500;
    int ScreenHeight = 400;
    Dimension screenSize = new Dimension(ScreenWidth, ScreenHeight);
    
    Image dbImage;
    Graphics dbGraphics;
    
    //sets the ball object
    static pongball b = new pongball(250, 200);
    
    
    //constructor for application window
    public pong() {
        this.setTitle("Pong");
        this.setSize(screenSize);
        this.setResizable(false);
        this.setVisible(true);
        this.setBackground(Color.black);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.addKeyListener(new AL());
    }
    
    public static void main(String[] args) {
        pong pg = new pong();
        
        //creates and starts threads.
        Thread pongball = new Thread(b);
        pongball.start();
        Thread p1 = new Thread(b.p1);
        Thread p2 = new Thread(b.p2);
        p2.start();
        p1.start();
        
    }
    
    @Override
    public void paint(Graphics g) {
        dbImage = createImage(getWidth(), getHeight());
        dbGraphics = dbImage.getGraphics();
        draw(dbGraphics);
        g.drawImage(dbImage, 0, 0, this);
    }
    
    public void draw(Graphics g) {
        b.draw(g);
        b.p1.draw(g);
        b.p2.draw(g);
        
        g.setColor(Color.white);
        g.drawString("" b.p1score, 15, 20);
        g.drawString("" b.p2score, 385, 20);
        
        repaint();
    }
    
    public class AL extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            b.p1.keyPressed(e);
            b.p2.keyPressed(e);
        }
        @Override
        public void keyReleased(KeyEvent e) {
            b.p1.keyReleased(e);
            b.p2.keyReleased(e);
        }
        
    }
}

Ball

package ponggame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;


public class pongball implements Runnable {

    //global variables
    int x;
    int y; 
    int yDirection; 
    int xDirection;
    
    int p1score, p2score;
    
    //Sets position of the paddles when running the code
    pongpaddle p1 = new pongpaddle(10, 25, 1);
    pongpaddle p2 = new pongpaddle(485, 25, 2);
    
    Rectangle ball;

    
    public pongball(int x, int y){
        p1score = p2score = 0;
        this.x = x;
        this.y = y;
        
        //Sets the ball to move randomly
        Random r = new Random();
        int rXDir = r.nextInt(1);
        if (rXDir == 0)
            rXDir--;
        settingXDirection(rXDir);
        
        int rYDir = r.nextInt(1);
        if (rYDir == 0)
            rYDir--;
        settingYDirection(rYDir);
        
        //creates the "ball" on the application screen
        ball = new Rectangle(this.x, this.y, 15, 15);
    }
    
    public void settingXDirection(int xDir){
        xDirection = xDir;
    }
    public void settingYDirection(int yDir){
        yDirection = yDir;
    }
    
    //parameters and dimensions of the ball
    public void draw(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(ball.x, ball.y, ball.width, ball.height);
    }
    
    //movement of ball when colliding with paddles
    public void collision(){
        if(ball.intersects(p1.paddle))
            settingXDirection( 1);
        if(ball.intersects(p2.paddle))
            settingXDirection(-1);
    }   
    
    public void move() {
        collision();
        ball.x  = xDirection;
        ball.y  = yDirection;
        //causes the ball to bounce when it hits the edge of the screen
        if (ball.x <= 0) {
            settingXDirection( 1);
            p2score  ;
            
    }
        if (ball.x >= 485) {
            settingXDirection(-1);
            p1score  ;
        }
        
        if (ball.y <= 15) {
            settingYDirection( 1);
        }
        
        if (ball.y >= 385) {
            settingYDirection(-1);
        }
    }
    
    @Override
    public void run() {
        try {
            while(true) {
                move();
                Thread.sleep(8);
            }
        }catch(Exception e) { System.err.println(e.getMessage()); }

    }

}

Paddle

package ponggame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

public class pongpaddle implements Runnable{
    
    
    int x;
    int y; 
    int yDirection; 
    int id;
    
    Rectangle paddle;
    
    public pongpaddle(int x, int y, int id){
        this.x = x;
        this.y = y;
        this.id = id;
        paddle = new Rectangle(x, y, 10, 75);
    }
        
    public void keyPressed(KeyEvent e) {
        switch(id) {
        default:
            System.out.println("Please enter a valid input");
            break;
    //Movement for left paddle when W and S keys are pressed
        case 1:
            if(e.getKeyCode() == KeyEvent.VK_W) {
                setYDirection(-1);
            }
            if(e.getKeyCode() == KeyEvent.VK_S) {
                setYDirection(1);
            }
            break;
    //Movement for right paddle when UP and DOWN keys are pressed
        case 2:
            if(e.getKeyCode() == KeyEvent.VK_UP) {
                setYDirection(-1);
            }
            if(e.getKeyCode() == KeyEvent.VK_DOWN) {
                setYDirection(1);
            }
            break;
    }
    }
    
    public void keyReleased(KeyEvent e) {
        switch(id) {
        default:
            System.out.println("Please enter a valid input");
            break;
        case 1:
        if(e.getKeyCode() == e.VK_UP) {
            setYDirection(0);
        }
        if(e.getKeyCode() == e.VK_DOWN) {
            setYDirection(0);
        }
        break;
        case 2:
            
        if(e.getKeyCode() == e.VK_W) {
            setYDirection(0);
        }
        if(e.getKeyCode() == e.VK_S) {
            setYDirection(0);
        }
        break;
        }
    }
    
    public void setYDirection(int yDir) {
        yDirection = yDir;
    }
    
    //sets the limits of movementmaking it so that the paddles don't just fall out the screen
    public void move() {
        paddle.y  = yDirection;
        if (paddle.y <= 15)
            paddle.y = 15;
        if (paddle.y >= 340)
            paddle.y = 340;
    }
    

    public void draw(Graphics g) {
        switch(id) {
        default:
            System.out.println("Please enter a Valid ID in paddle contructor");
            break;
        //Sets the paddles, using dimensions from Rectangle paddle
        case 1:
            g.setColor(Color.WHITE);
            g.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
            break;
        case 2:
            g.setColor(Color.RED);
            g.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
            break;
        }
    }
    @Override
    public void run() {
        try {
            while(true) {
                move();
                Thread.sleep(7);
            }
        } catch(Exception e) { System.err.println(e.getMessage()); }
    }

}

CodePudding user response:

in java you can create new colors with: Color color = new Color(red, green, blue); red, green, blue are values between 0 - 255. So you could maybe write a function to generate 9 unique numbers from 0 - 255 and then set the the rgb-values of each object.

CodePudding user response:

A simple solution to your problem is to use Collections.shuffle to randomise a List of colors. Then you can just pop off the next color from the List until you run out, at which point, you would refill the and shuffle the List again.

Color[] masterColors = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW };
List<Color> randomColors = new ArrayList<>(13);

if (randomColors.isEmpty()) {
    randomColors.addAll(Arrays.asList(masterColors));
    Collections.shuffle(randomColors);
}
Color color = randomColors.remove(0);

To make this work across multiple classes, you'll need to share this with each instance. This would first require you to encapsulate the workflow, for example...

public class ColorManager {
    private Color[] masterColors = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW };
    private List<Color> randomColors = new ArrayList<>(13);
    
    public Color next() {
        if (randomColors.isEmpty()) {
            randomColors.addAll(Arrays.asList(masterColors));
            Collections.shuffle(randomColors);
        }
        return randomColors.remove(0);
    }
}

A shared instance of this then get's passed to each instance of the paddle and ball, which it detects a collision, it requests the next color, based on conditions of the collision (ie wall or paddle)

Feedback...

You should not be overriding paint of a top level, especially JFrame, which is a composite component (it contains child components).

Swing, if used correctly, is double buffered by default, so you don't need the backing buffer at all.

Instead, you should start with a JPanel and override it's paintComponent method and use it as your primary surface.

See Painting in AWT and Swing and Performing Custom Painting for more details.

KeyListener is a poor choice for monitoring key events in this context, it's notorious for causing, seemingly random, issues. Make use of the Key Bindings API instead.

Swing is not thread safe (and is single threaded). This means you should not update the UI or any state the UI relies on from outside the context of the Event Dispatching Thread OR executing long running or blocking operations within the context of the Event Dispatching Thread.

To this end, you should not be using Thread (and really shouldn't be using three) to update the game state. Instead, use a single Swing Timer.

See Concurrency in Swing and How to Use Swing Timers

  • Related