I have a frame that I painted half black and half white with Java Swing's grid methods. And on this frame, there is a white ball that starts moving on the black part and a black ball that starts moving on the white part. I want these balls to bounce back if they touch grids that are the same color as them and paint the grid they touch in the opposite color. I have completed everything except the last feature, but I can't figure out how to implement the last feature in the application.
Interface.java
import javax.swing.*;
import java.awt.*;
public class Interface extends JFrame{
private int frameHeight = 637;
private int frameWidth = 1214;
public Interface() {
setSize(frameWidth, frameHeight);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setTitle("Bouncing Ball");
add(new Core());
setVisible(true);
}
public static void main(String[] args){
new Interface();
}
}
Core.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Core extends JPanel{
int xw = 10, yw = 10, xb = 1000, yb = 400;
int bounds = 20, gridSize = 20;
int vxw = 5, vyw = 5, vxb = 5, vyb = 5;
int rows, columns;
public Core() {
rows = getHeight() / gridSize;
columns = getWidth() / gridSize;
Timer timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(getHeight());
System.out.println(getWidth());
xw += vxw;
yw += vyw;
xb -= vxb;
yb -= vyb;
if (xw > getWidth() - bounds || xw < 0) {vxw = -vxw;}
if (yw > getHeight() - bounds || yw < 0) {vyw = -vyw;}
if (xb > getWidth() - bounds || xb < 0) {vxb = -vxb;}
if (yb > getHeight() - bounds || yb < 0) {vyb = -vyb;}
repaint();
}
});
timer.start();
}
public void paintComponent(Graphics g) {
Graphics2D g2dw = (Graphics2D) g;
Graphics2D g2db = (Graphics2D) g;
Graphics2D grid = (Graphics2D) g;
super.paintComponent(g);
for (int k = 0; k < getWidth(); k += gridSize) {
for (int z = 0; z < getHeight(); z += gridSize) {
grid.drawRect(k, z, gridSize, gridSize);
if (k < getWidth() / 2) {
grid.setColor(Color.BLACK);
grid.fillRect(k, z, gridSize, gridSize);
} else {
grid.setColor(Color.WHITE);
grid.fillRect(k, z, gridSize, gridSize);
}
}
}
g2dw.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2dw.setColor(Color.white);
g2dw.fillOval(xw, yw, bounds, bounds);
//g2d.dispose();
g2db.setColor(Color.black);
g2db.fillOval(xb, yb, bounds, bounds);
}
public static void main(String[] args){
}
}
Example Output: https://github.com/vnglst/pong-wars
I'm trying to learn how to write a feature that will make the balls bounce when they touch a grid with the same color as them and paint the grid they touch with the opposite color. Any hints or guidance would be much appreciated too, if you don't want to bother with writing Java code.
I tried creating a 2D array that contains 1 or 0 values (1 for white grid, 0 for black) but encountered with IndexBound errors.
According to camickr's instructions, there is the Java code:
Core.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
class Core extends JPanel {
//Adjusting the starting points of balls and other variables
protected int xw = Interface.frameWidth / 2 - 40, yw = Interface.frameHeight / 2, xb = Interface.frameWidth / 2 + 40, yb = Interface.frameHeight / 2;
private int bounds;
private int rows, columns, tileSize;
private ArrayList<ColoredShape> tiles;
private ArrayList<Ball> balls;
public Core(int rows, int columns, int tileSize) {
this.rows = rows;
this.columns = columns;
this.tileSize = tileSize;
this.bounds = tileSize / 2;
this.tiles = new ArrayList<>();
this.balls = new ArrayList<>();
// Creating tiles
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
int x = j * tileSize;
int y = i * tileSize;
Shape rect = new Rectangle(x, y, tileSize, tileSize);
Color color = (j < columns / 2) ? Color.BLACK : Color.WHITE;
tiles.add(new ColoredShape(rect, color));
}
}
// Creating balls
balls.add(new Ball(xw, yw, bounds, Color.WHITE, 10, 3));
balls.add(new Ball(xb, yb, bounds, Color.BLACK, 10, -3));
// Animation part
Timer timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
moveBalls();
checkCollision();
repaint();
}
});
timer.start();
}
//Moving balls
private void moveBalls() {
for (Ball ball : balls) {
ball.setX(ball.getX() + ball.getVx());
ball.setY(ball.getY() + ball.getVy());
// Bouncing back from walls
if (ball.getX() > getWidth() - ball.getShape().width || ball.getX() < 0) {
ball.setVx(-ball.getVx());
}
if (ball.getY() > getHeight() - ball.getShape().height || ball.getY() < 0) {
ball.setVy(-ball.getVy());
}
}
}
private void checkCollision() {
for (Ball ball : balls) {
for (ColoredShape tile : tiles) {
if (ball.getShape().getBounds().intersects(tile.getShape().getBounds())) {
if (ball.getColor().equals(tile.getColor())) {
tile.setColor(ball.getColor().equals(Color.WHITE) ? Color.BLACK : Color.WHITE);
// Calculating the angle of incidence
double tileCenterX = tile.getShape().getBounds2D().getCenterX();
double tileCenterY = tile.getShape().getBounds2D().getCenterY();
double ballCenterX = ball.getShape().getCenterX();
double ballCenterY = ball.getShape().getCenterY();
double angle = Math.atan2(ballCenterY - tileCenterY, ballCenterX - tileCenterX);
// Adjusting velocity based on angle of incidence
if (Math.abs(angle) < Math.PI / 4 || Math.abs(angle) > 3 * Math.PI / 4) {
// Adjusting x velocity
ball.setVx(-ball.getVx());
} else {
// Adjusting y velocity
ball.setVy(-ball.getVy());
}
}
}
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// Drawing tiles
for (ColoredShape tile : tiles) {
g2d.setColor(tile.getColor());
g2d.fill(tile.getShape());
}
// Drawing balls
for (Ball ball : balls) {
g2d.setColor(ball.getColor());
g2d.fill(ball.getShape());
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(columns * tileSize, rows * tileSize);
}
}
Interface.java
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class Interface extends JFrame {
protected static int frameHeight = 637;
protected static int frameWidth = 637;
private int tileSize = 30;
public Interface() {
setSize(frameWidth, frameHeight);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setTitle("Bouncing Ball");
add(new Core(frameHeight / tileSize, frameWidth / tileSize, tileSize)); // Rows, Columns, TileSize
setVisible(true);
}
public static void main(String[] args) {
new Interface();
}
}
class ColoredShape {
private Shape shape;
private Color color;
public ColoredShape(Shape shape, Color color) {
this.shape = shape;
this.color = color;
}
public Shape getShape() {
return shape;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
class Ball {
private Ellipse2D.Double shape;
private Color color;
private int vx;
private int vy;
public Ball(int x, int y, int diameter, Color color, int vx, int vy) {
this.shape = new Ellipse2D.Double(x, y, diameter, diameter);
this.color = color;
this.vx = vx;
this.vy = vy;
}
public Ellipse2D.Double getShape() {
return shape;
}
public Color getColor() {
return color;
}
public int getVx() {
return vx;
}
public void setVx(int vx) {
this.vx = vx;
}
public int getVy() {
return vy;
}
public void setVy(int vy) {
this.vy = vy;
}
public int getX() {
return (int) shape.x;
}
public void setX(int x) {
shape.x = x;
}
public int getY() {
return (int) shape.y;
}
public void setY(int y) {
shape.y = y;
}
}
There was a logic error in your code, I fixed it: