ContentPane background color changes when adding object - java

I have the following code:
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
public class Ball extends JPanel implements Runnable {
List<Ball> balls = new ArrayList<Ball>();
Color color;
int diameter;
long delay;
private int x;
private int y;
private int vx;
private int vy;
public Ball(String ballcolor, int xvelocity, int yvelocity) {
color = Color.PINK;
diameter = 30;
delay = 40;
x = 1;
y = 1;
vx = xvelocity;
vy = yvelocity;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
g.fillOval(x,y,50,50); //adds color to circle
g.setColor(Color.pink);
g2.drawOval(x,y,50,50); //draws circle
}
public void run() {
while(isVisible()) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
System.out.println("interrupted");
}
move();
repaint();
}
}
public void move() {
if(x + vx < 0 || x + diameter + vx > getWidth()) {
vx *= -1;
}
if(y + vy < 0 || y + diameter + vy > getHeight()) {
vy *= -1;
}
x += vx;
y += vy;
}
private void start() {
while(!isVisible()) {
try {
Thread.sleep(25);
} catch(InterruptedException e) {
System.exit(1);
}
}
Thread thread = new Thread(this);
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
public static void main(String[] args) {
Ball ball1 = new Ball("pink",6,6);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setBackground(Color.BLACK);
f.getContentPane().add(ball1);
f.setSize(1000,500);
f.setLocation(200,200);
new Thread(ball1).start();
f.setVisible(true);
}
}
I would like to make the background black instead of the default grey one, but this only works if I get the ball out of the code, basically deleting f.getContentPane().add(ball1);. What I want is a pink ball bouncing on a black background, but it keeps going back to grey when adding the ball.
What is the problem?

Ball which extends from JPanel is opaque (not see through), so it is filling it's own background with it's default color...
You could make Ball transparent by using setOpaque(false) or set the Ball's background color to BLACK using setBackground(Color.BLACK) for example...
ps- I should add, because JFrame uses a BorderLayout, your Ball pane will occupy the entire available space within the center of the frame (CENTER being the default position and the frame not containing any other components)

Related

Using Mouse Click to Generate Balls

I have below code, I need to alter it so that the balls are generated with a mouse click rather than all of them generating at once. I know I need to use a mouse listener but I do not know how I can integrate that into what I have without "breaking" the app.
No changes needed
import javax.swing.JFrame;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
public class Display {
public final int width;
public final int height;
private JFrame frame;
private boolean closeRequested;
private long lastFrameTime;
private BufferStrategy bufferStrategy;
private Graphics2D graphics;
public Display(int width, int height){
this.width = width;
this.height = height;
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setAutoRequestFocus(true);
frame.setResizable(false);
frame.addWindowListener(new WindowAdapter(){
#Override
public void windowClosing(WindowEvent e){
closeRequested = true;
}
});
Canvas canvas = new Canvas();
canvas.setIgnoreRepaint(true);
canvas.setPreferredSize(new Dimension(width, height));
frame.getContentPane().add(canvas);
frame.setVisible(true);
frame.pack();
frame.setLocationRelativeTo(null);
canvas.createBufferStrategy(2);
bufferStrategy = canvas.getBufferStrategy();
graphics = (Graphics2D) bufferStrategy.getDrawGraphics();
lastFrameTime = System.currentTimeMillis();
}
public boolean isCloseRequested(){
return closeRequested;
}
public void destroy() {
frame.dispose();
}
public void update(){
if (bufferStrategy.contentsLost()){
graphics.dispose();
graphics = (Graphics2D) bufferStrategy.getDrawGraphics();
}
bufferStrategy.show();
}
public Graphics2D getGraphics() {
return graphics;
}
public void sync(int fps) {
if (fps < 1){
return;
}
long currentFrameTime = System.currentTimeMillis();
long deltaTime = currentFrameTime - lastFrameTime;
long timeToSleep = (1000/fps) - deltaTime;
while (System.currentTimeMillis() - currentFrameTime < timeToSleep){
try{
Thread.sleep(1L);
} catch (InterruptedException e) {
}
}
lastFrameTime = System.currentTimeMillis();
}
}
No changes needed
import java.awt.Color;
public class Ball {
public float x;
public float y;
public float sX;
public float sY;
public int radius;
public Color color;
public Ball(float x, float y, float sX, float sY, int radius, Color color){
this.x = x;
this.y = y;
this.sX = sX;
this.sY = sY;
this.radius = radius;
this.color = color;
}
}
This is where I think the mouse listener would be added in for generating the new balls.
How to change addBalls() logic to generate ball with mouse click?
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Random;
public class BouncingBallsApp {
private Display display;
private ArrayList<Ball> balls = new ArrayList<>();
public BouncingBallsApp() {
display = new Display(800,600);
addBalls();
mainLoop();
display.destroy();
}
private void mainLoop() {
while (!display.isCloseRequested()){
updatePhysics();
draw(display.getGraphics());
display.update();
display.sync(60);
}
}
//Question????How to change this logic to generate ball with mouse click
private void addBalls() {
int numberOfBalls = 20;
Random random = new Random();
for (int i = 0; i < numberOfBalls; i++){
int radius = random.nextInt(40) + 10;
int x = random.nextInt(display.width - radius * 2) + radius;
int y = random.nextInt(display.height - radius * 2) + radius;
float sX = random.nextFloat() * 10f + 3f;
float sY = random.nextFloat() * 10f + 3f;
Color color;
switch (random.nextInt(4)){
case 0:
color = Color.red;
break;
case 1:
color = Color.green;
break;
case 2:
color = Color.yellow;
break;
default:
color = Color.blue;
break;
}
Ball ball = new Ball(x, y, sX, sY, radius, color);
balls.add(ball);
}
}
private void updatePhysics() {
for (Ball ball : balls){
ball.x += ball.sX;
ball.y += ball.sY;
if (ball.x - ball.radius < 0){
ball.sX = Math.abs(ball.sX);
} else if (ball.x + ball.radius > display.width){
ball.sX = -Math.abs(ball.sX);
}
if (ball.y - ball.radius < 0){
ball.sY = Math.abs(ball.sY);
} else if (ball.y + ball.radius > display.height){
ball.sY = -Math.abs(ball.sY);
}
}
}
private void draw(Graphics2D g) {
g.setBackground(Color.black);
g.clearRect(0,0, display.width, display.height);
for (Ball ball : balls){
g.setColor(ball.color);
int x = (int) (ball.x - ball.radius);
int y = (int) (ball.y - ball.radius);
int size = ball.radius * 2;
g.fillOval(x, y, size, size);
}
}
public static void main(String[] args) {
new BouncingBallsApp();
}
}
In BouncingBallsApp constructor do the following changes:
public BouncingBallsApp() {
display = new Display(800,600);
//instead of calling add balls directly, use a mouse listener
//addBalls();
display.addMouseListener(getListener());
mainLoop();
display.destroy();
}
Add getListener() method to BouncingBallsApp:
private MouseListener getListener() {
return new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
addBalls(1); //call add balls when mouse pressed
}
};
}
And slightly change addBalls() so that numberOfBalls becomes an argument:
private void addBalls(int numberOfBalls) {
//int numberOfBalls = 20;
.....
Add mouse listener support to Display:
//add mouse listener to canvas
void addMouseListener(MouseListener listener) {
canvas.addMouseListener(listener); //requiers to make canvas a field
}
All done.
To generate balls, simply click the canvas.
(A link to the full code (you can run it online). )

Java: drawing multiple sprites in different threads at a time

I need to create a JPanel, where upon a mouse click a new Sprite must appear in a new thread. This is what I have:
public class BouncingSprites {
private JFrame frame;
private SpritePanel panel = new SpritePanel();
private Sprite ball;
public BouncingSprites() {
frame = new JFrame("Bouncing Sprite");
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public void start(){
panel.animate(); // never returns due to infinite loop in animate method
}
public static void main(String[] args) {
new BouncingSprites().start();
}
}
Class SpritePanel:
public class SpritePanel extends JPanel
{
Sprite sprite;
public SpritePanel()
{
addMouseListener(new Mouse());
}
//method for creating a new ball
private void newSprite (MouseEvent event)
{
sprite = new Sprite(this);
}
public void animate()
{
}
private class Mouse extends MouseAdapter
{
#Override
public void mousePressed( final MouseEvent event )
{
newSprite(event);
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (sprite != null)
{
sprite.draw(g);
}
}
}
Class Sprite :
public class Sprite implements Runnable
{
public final static Random random = new Random();
final static int SIZE = 10;
final static int MAX_SPEED = 5;
SpritePanel panel;
private int x;
private int y;
private int dx;
private int dy;
private Color color = Color.BLUE;
private Thread animation;
public Sprite (SpritePanel panel)
{
this.panel = panel;
x = random.nextInt(panel.getWidth());
y = random.nextInt(panel.getHeight());
dx = random.nextInt(2*MAX_SPEED) - MAX_SPEED;
dy = random.nextInt(2*MAX_SPEED) - MAX_SPEED;
animation = new Thread(this);
animation.start();
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, SIZE, SIZE);
}
public void move()
{
// check for bounce and make the ball bounce if necessary
//
if (x < 0 && dx < 0){
//bounce off the left wall
x = 0;
dx = -dx;
}
if (y < 0 && dy < 0){
//bounce off the top wall
y = 0;
dy = -dy;
}
if (x > panel.getWidth() - SIZE && dx > 0){
//bounce off the right wall
x = panel.getWidth() - SIZE;
dx = - dx;
}
if (y > panel.getHeight() - SIZE && dy > 0){
//bounce off the bottom wall
y = panel.getHeight() - SIZE;
dy = -dy;
}
//make the ball move
x += dx;
y += dy;
}
#Override
public void run()
{
while (Thread.currentThread() == animation)
{
move();
panel.repaint();
try
{
Thread.sleep(40);
}
catch ( InterruptedException exception )
{
exception.printStackTrace();
}
}
}
}
This code creates a new moving sprite. However, the previous sprite gets removed from the panel. What I need to do is to add a new sprite with a mouse click, so that the previous sprite is not removed. If I click three times, three sprites should be painted.
How do I change my code to implement that?
Many thanks!
You could replace Sprite sprite; in the SpritePanel class with List<Sprite> sprites = new ArrayList<>();. Then, when you make a new Sprite, add it to the list. Then in your paintComponent method, you could iterate through the list, drawing all of the sprites.

Creating my own paint method in java

I want to create a method that creates 5 balls on a panel. Can somebody please help me get around this using the paint component method or creating my own draw method. As you can see bellow, i have a paint component method with a for loop that will loop 5 and create a ball in a random location, but unfortunately only one ball is being created.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class AllBalls extends JPanel {
int Number_Ball=5;
int x,y;
Graphics g;
AllBalls(){
Random r = new Random();
x=r.nextInt(320);
y=r.nextInt(550);
}
public static JFrame frame;
public static void main(String[] args) {
AllBalls a= new AllBalls();
frame= new JFrame("Bouncing Balls");
frame.setSize(400,600);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(a);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(int i=0;i<Number_Ball;i++){
g.fillOval(x, y, 30, 30);
}
repaint();
}
}
In my paintComponent method, i created a for loop in which i wanted 5 ball to be created, but only one is being created on the screen.
Recommendations as per my comments:
Get rid of the Graphics g variable as that will only hurt you.
Consider creating a non-GUI Ball class, one that does not extend any Swing component and has its own paint(Graphics) method.
If you need 5 balls, create an array of Ball objects in your AllBalls class.
In paintComponent, iterate through the Balls painting each one by calling its paint or draw method (whatever you name the method).
If you need to move the balls, do so in a Swing Timer that moves the balls and then calls repaint(). Whatever you do, do not call repaint() within the paintComponent method as this results in a bastardization of the method, and results in a completely uncontrolled animation. This method should be for painting and painting only and not for animation or code logic. Use the Swing Timer instead.
Also don't randomize your ball locations within paintComponent, another recommendation made in a now-deleted answer. Again, paintComponent should be for painting and painting only and not for program logic or to change the state of your class. The randomization should be within your Swing Timer or game loop.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings({"serial", "unused"})
public class BallImages extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final int BALL_COUNT = 15;
private static final Color[] COLORS = { Color.RED, Color.BLACK, Color.BLUE,
Color.CYAN, Color.GREEN, Color.ORANGE, Color.PINK, Color.WHITE,
Color.MAGENTA, Color.YELLOW };
private static final int MIN_SPEED = 2;
private static final int MAX_SPEED = 10;
private static final int MIN_WIDTH = 10;
private static final int MAX_WIDTH = 30;
private static final int TIMER_DELAY = 15;
private List<Ball> balls = new ArrayList<>();
private Random random = new Random();
public BallImages() {
for (int i = 0; i < BALL_COUNT; i++) {
int ballWidth = MIN_WIDTH + random.nextInt(MAX_WIDTH - MIN_WIDTH);
Color ballColor = COLORS[random.nextInt(COLORS.length)];
int ballX = ballWidth / 2 + random.nextInt(PREF_W - ballWidth / 2);
int ballY = ballWidth / 2 + random.nextInt(PREF_H - ballWidth / 2);
double direction = 2 * Math.PI * Math.random();
double speed = MIN_SPEED + random.nextInt(MAX_SPEED - MIN_SPEED);
Ball ball = new Ball(ballWidth, ballColor, ballX, ballY, direction,
speed);
balls.add(ball);
}
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ball ball : balls) {
ball.draw(g2);
}
}
#Override
// set the component's size in a safe way
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (!BallImages.this.isDisplayable()) {
((Timer) e.getSource()).stop();
}
for (Ball ball : balls) {
ball.move(PREF_W, PREF_H);
}
repaint();
}
}
private class Ball {
private int width;
private Color color;
private double x;
private double y;
private double direction;
private double speed;
private double deltaX;
private double deltaY;
public Ball(int width, Color color, int x, int y, double direction,
double speed) {
this.width = width;
this.color = color;
this.x = x;
this.y = y;
this.direction = direction;
this.speed = speed;
deltaX = speed * Math.cos(direction);
deltaY = speed * Math.sin(direction);
}
public int getWidth() {
return width;
}
public Color getColor() {
return color;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getDirection() {
return direction;
}
public double getSpeed() {
return speed;
}
public void draw(Graphics2D g2) {
g2.setColor(color);
int x2 = (int) (x - width / 2);
int y2 = (int) (y - width / 2);
g2.fillOval(x2, y2, width, width);
}
public void move(int containerWidth, int containerHeight) {
double newX = x + deltaX;
double newY = y + deltaY;
if (newX - width / 2 < 0) {
deltaX = Math.abs(deltaX);
newX = x + deltaX;
}
if (newY - width / 2 < 0) {
deltaY = Math.abs(deltaY);
newY = y + deltaY;
}
if (newX + width / 2 > containerWidth) {
deltaX = -Math.abs(deltaX);
newX = x + deltaX;
}
if (newY + width / 2 > containerHeight) {
deltaY = -Math.abs(deltaY);
newY = y + deltaY;
}
x = newX;
y = newY;
}
}
private static void createAndShowGui() {
BallImages mainPanel = new BallImages();
JFrame frame = new JFrame("BallImages");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

creating many objects with collision properties. JAVA

I have a simple program with three rectangles: one that can move with the push of the arrow keys, and two that are already moving back and forth on their own.
When the 'player' rectangle and top red collide, the player driven rectangle gets put back to (0,0). When I try to collide the player rectangle with the bottom red rectangle, it does not have those collision properties and I have no idea why.
What am I missing?
import java.awt.*;//needed for graphics
import javax.swing.*;//needed for JFrame window
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class javaapplication23 extends JFrame implements KeyListener, ActionListener {
public static int x = 0;
public static int y = 0;
public static int x2 = 100;
public static int y2 = 100;
public javaapplication23() {//constructor for JPanel
add(new JP());
}//close Jpanel Contructor
public static void main(String[] args) {
javaapplication23 w = new javaapplication23();
w.setTitle("MIKE IS AWESOME");
w.setSize(Toolkit.getDefaultToolkit().getScreenSize());
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.setVisible(true);
w.addKeyListener(w);
}
public class JP extends JPanel {//start JPanel CLass
public JP() {
Container c = getContentPane();
c.setBackground(Color.white);//backgraund color can be changed
}
public void paint(Graphics g) {//opens paint method
super.paint(g);
player(g, x, y);
g.setColor(Color.RED);
enemylevel1(g, x2, y2);
Rectangle enemyblocks = new Rectangle(x2, y2, 25, 25);
Rectangle player = new Rectangle(x, y, 25, 25);
enemyblocks.contains(x2, y2);
player.contains(x, y);
if (player.getBounds().intersects(enemyblocks.getBounds())) {
x = 0;
y = 0;
}
pause(1);
repaint();
}//close paint method
}//close JPanel Class
public static void pause(int time) {
try //opens an exception handling statement
{
Thread.sleep(time);
} catch (InterruptedException e) {
} //captures the exception
}
public void actionPerformed(ActionEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_RIGHT) {
x += 20;//global variable controlling right movement
repaint();
}
if (e.getKeyCode() == e.VK_LEFT) {
x -= 20;//global variable controlling left movement
repaint();
}
if (e.getKeyCode() == e.VK_UP) {
y -= 20;//global variable controlling up movement
repaint();
}
if (e.getKeyCode() == e.VK_DOWN) {
y += 20;//global variable controlling down movement
repaint();
}
}
public void player(Graphics g, int x, int y) {
g.fillRect(x, y, 30, 30);
}
public void enemylevel1(Graphics g, int x, int y) {
g.fillRect(x2, y2, 25, 25);
g.fillRect(x2, y2 + 100, 25, 25);
if (x2 < 200 && y2 == 100) {
x2 += 1;
}
if (x2 == 200 && y2 >= 100) {
y2 += 1;
}
if (x2 <= 200 && y2 >= 101) {
x2 -= 1;
}
if (x2 == 100 && y2 <= 101) {
y2 -= 1;
}
pause(10);
repaint();
}
}
Start by having a look at Working with Geometry, this will allow you to reduce much of the code complexity.
Basically, a enemy is just a Rectangle, Graphics2D can paint these without to much of an issue. What you need to do is create an instance which can also update it's position based on your needs
public class Enemy extends Rectangle {
private int xDelta;
public Enemy(int x, int y) {
super(x, y, 20, 20);
if (x == 0) {
xDelta = 1;
} else {
xDelta = -1;
}
}
public void update(Rectangle bounds) {
x += xDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x > bounds.x + bounds.width - width) {
x = bounds.x + bounds.width - width;
xDelta *= -1;
}
}
}
So, this creates a single unit of work, which is isolated from everything else and carries it's own logic with it. This makes updating it, painting and generally working with much simpler.
Next, you need to create a List of these
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
//...
public Bounce() {
enemies = new ArrayList<>(5);
int y = 100;
for (int index = 0; index < 5; index++) {
int x = (index % 2 == 0) ? 0 : 200;
Enemy enemy = new Enemy(x, y);
enemies.add(enemy);
y += 60;
}
This creates a List of Enemys which are distributed evenly within the container.
Now, we need to paint them....
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
}
}//close paint method
nb: General convention suggests that you should override paintComponent when you want to perform custom painting
But they don't move, that kind of sucks. So we need a way to, on a regular bases, update the position of the enemies...
First, we create a simple method which we can call to update the enemies, remember, they are capable of updating themselves, we just need to tell them when
public void updateState() {
Rectangle bounds = new Rectangle(20, 20, 200, 200);
for (Enemy enemy : enemies) {
enemy.update(bounds);
}
}
Remember, the Enemy is self contained, it knows how to update itself based on the constraints you have provided.
And now, we need to call this method on a regular bases...
javax.swing.Timer timer = new javax.swing.Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
repaint();
}
});
timer.start();
Okay, this will schedule a callback every 40 milliseconds which will allow us to call the updateState method and repaint the component. This is neat because it won't block the Event Dispatching Thread (making our program look like it's hung) but which notifies us within the context of the EDT, making it safe to update the UI from within - WIN/WIN :)
Take a look at Concurrency in Swing and How to use Swing Timers for more details.
Okay, but that doesn't solve the collision...
The player is also a Rectangle, so why not use the same concept we have with the enemies...
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
private Rectangle player;
//...
public Bounce() {
player = new Rectangle(0, 0, 30, 30);
enemies = new ArrayList<>(5);
//...
}
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawPlayer(g2d);
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
if (player.intersects(enemy)) {
player.x = 0;
player.y = 0;
}
}
}//close paint method
public void drawPlayer(Graphics2D g) {
g.fill(player);
}
Which ends up with something like...
This allows you to add/remove enemies as you want and also change the way in which the enemies move, simply and easily
An my "awesome" test code...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
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 java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
private Rectangle player;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Bounce());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public Bounce() {
player = new Rectangle(0, 0, 30, 30);
enemies = new ArrayList<>(5);
int y = 100;
for (int index = 0; index < 5; index++) {
int x = (index % 2 == 0) ? 0 : 200;
Enemy enemy = new Enemy(x, y);
enemies.add(enemy);
y += 60;
}
setBackground(Color.white);//backgraund color can be changed
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
repaint();
}
});
timer.start();
setFocusable(true);
requestFocusInWindow();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
});
addKeyListener(this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 400);
}
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawPlayer(g2d);
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
if (player.intersects(enemy)) {
player.x = 0;
player.y = 0;
}
}
}//close paint method
public void actionPerformed(ActionEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_RIGHT) {
player.x += 20;//global variable controlling right movement
}
if (e.getKeyCode() == e.VK_LEFT) {
player.x -= 20;//global variable controlling left movement
}
if (e.getKeyCode() == e.VK_UP) {
player.y -= 20;//global variable controlling up movement
}
if (e.getKeyCode() == e.VK_DOWN) {
player.y += 20;//global variable controlling down movement
}
}
public void drawPlayer(Graphics2D g) {
g.fill(player);
}
public void updateState() {
Rectangle bounds = new Rectangle(20, 20, 200, 200);
for (Enemy enemy : enemies) {
enemy.update(bounds);
}
}
public class Enemy extends Rectangle {
private int xDelta;
public Enemy(int x, int y) {
super(x, y, 20, 20);
if (x == 0) {
xDelta = 1;
} else {
xDelta = -1;
}
}
public void update(Rectangle bounds) {
x += xDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x > bounds.x + bounds.width - width) {
x = bounds.x + bounds.width - width;
xDelta *= -1;
}
}
}
}

Painting JFrame Difficulty

In my code I am trying to paint by JFrame but it is not painting correctly. I tell the frame to paint in the beginning where I create it however it is the normal grey color once it is created. I think it may have to do with the fact that I am repainting it, if so how can I make sure it is repainted yellow? Could someone try to figure out why my code is not painting the JFrame Yellow? Thank you!
public class EvolutionColor {
public static void main(String args[]) {
JFrame frame = new JFrame("Bouncing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BallPanel bp = new BallPanel();
frame.add(bp);
frame.setSize(600, 600); // set frame size
frame.setVisible(true); // display frame
frame.setBackground(Color.YELLOW);
}
class BallPanel extends JPanel implements ActionListener {
private int delay = 10;
protected Timer timer;
private int x = 0; // x position
private int y = 0; // y position
private int radius = 15; // ball radius
private int dx = 2; // increment amount (x coord)
private int dy = 2; // increment amount (y coord)
public BallPanel() {
timer = new Timer(delay, this);
timer.start(); // start the timer
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // call superclass's paintComponent
g.setColor(Color.red);
// check for boundaries
if (x < radius) {
dx = Math.abs(dx);
}
if (x > getWidth() - radius) {
dx = -Math.abs(dx);
}
if (y < radius) {
dy = Math.abs(dy);
}
if (y > getHeight() - radius) {
dy = -Math.abs(dy);
}
// adjust ball position
x += dx;
y += dy;
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
Don't set the JFrame to yellow, set the BallPanel object to yellow.
Make BallPanel transparent...
bp.setOpaque(false);
Don't make decisions about the state of your component within paintComponent method, these decisions should be made within you actionPerformed method
Painting is for painting and paintComponent may be called for any number of reasons, many which you don't control

Categories

Resources