I'm using JGrasp, and in drawingPanel
, I'm trying to create a ball that changes colors as it moves across the screen. Right now, I've got:
for (int i = 10; i<=i; i++) {
Color c = new Color(i*i, 0, 0);
pen.setColor(c);
My full simplified code is:
import java.awt.*;
import java.util.*;
import java.awt.Color;
public class BallSample {
public static final int SIZE = 30;
public static final int HALF = SIZE / 2;
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
DrawingPanel panel = new DrawingPanel(1000, 1000);
panel.setBackground(Color.CYAN);
Graphics pen = panel.getGraphics();
for (int i = 10; i<=i; i++) {
Color c = new Color(i*i, 0, 0);
pen.setColor(c);
pen.fillOval(500 - HALF, 500 - HALF, SIZE, SIZE);
double xDisplacement = 30 * Math.cos(30);
double yDisplacement = 30 * Math.sin(30) * -1;
double x = 500.0;
double y = 500.0;
for (int j = 1; j <= 100; j++) {
x = x + xDisplacement;
y = y + yDisplacement;
if (x <= 0 || x >= 1000) {
xDisplacement = xDisplacement * -1;
}
if (y <= 0 || y >= 1000) {
yDisplacement = yDisplacement * -1;
}
pen.fillOval((int) x - HALF, (int) y - HALF, SIZE, SIZE);
panel.sleep(50);
}
}
}
}
I hope that's simplified enough.
After having some issues in the following code, I was able to create a color-changing ball example.
First of all, having panel.sleep(50);
makes me think (and I confirm with the DrawingPanel class link you posted in the comments) could become dangerous, it would be better to use a Swing Timer
instead, however I don't pretend on using or read all the class as it's too long, so in the example I post here I'll be using the Swing Timer
approach.
Also, I'm not sure why calling new Color(int rgb)
constructor with a random int
(between 0 and 255) doesn't update or create a new Color
with those settings, then after reading this answer and another one (I lost its link, sorry), you can use new Color(float r, float g, float b)
, so you may use it with a random number up to 256
.
You can also base your approach to a MVC pattern, having a Model Ball
class which contains the coords and the Color
it will have, a View JPanel
that will draw the ball over time and a Controller that will change the ball's coords and color overtime as well.
Disclaimer: This example just moves the ball horizontally and doesn't validate whether it's on the screen or not, you need to adapt this example to your own needs.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ChangingColorBall {
private JFrame frame;
private Timer timer;
private BallPane ballPane;
private Ball ball;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ChangingColorBall()::createAndShowGui); //We place our program on the EDT
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
ball = new Ball();
ballPane = new BallPane(ball);
timer = new Timer(100, e -> { //This Timer will execute every 100ms and will increase ball's X coord and paint it again.
ball.increaseX(); //This method increases X coord and changes ball's color on the model
ballPane.revalidate();
ballPane.repaint();
});
frame.add(ballPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer.start(); //We start the timer
}
class Ball {
private int xCoord;
private static final int Y = 50;
private static final int SIZE = 20;
private Color color;
private Random r;
public void increaseX() {
xCoord += 10; //Increases X coord
r = new Random();
color = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); //Generates a new random color
}
public int getXCoord() {
return xCoord;
}
public void setXCoord(int xCoord) {
this.xCoord = xCoord;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
@SuppressWarnings("serial")
class BallPane extends JPanel {
private Ball ball;
public BallPane(Ball ball) {
this.ball = ball;
}
@Override
protected void paintComponent(Graphics g) { //This method paints the ball according to the color it has and the actual coords it has
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(ball.getColor());
g2d.fillOval(ball.getXCoord(), Ball.Y, Ball.SIZE, Ball.SIZE);
}
@Override
public Dimension getPreferredSize() { //We should not call `.setSize(...)` method, so we override this one and call `.pack();`
return new Dimension(200, 100);
}
}
}
Note
Be aware to not call your coords as x
or y
or at least don't call their getters and setters as getX()
or getY()
or you could run into the issue I linked at the beginning of this answer.
Here's an example of how the GUI looks like, I can't do GIFs in my computer but it's better if you copy-paste the code and see how it works.
For a deeper understanding on how custom painting works in Swing, check Oracle's Lesson: Performing Custom Painting and Painting in AWT and Swing tutorials.