Putting sprites over background in a game - java

I'm having trouble loading a sprite into a game. I have the background done, but the sprite doesn't seem to be on the background. I want to assume you put it in the main constructor, but I don't think it will work.
package MyGamePKG;
import java.awt.BorderLayout;
public class GameJFrame extends JFrame {
private JPanel contentPane;
private int x,y,x_vel,y_vel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GameJFrame frame = new GameJFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public GameJFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 720, 520);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
GameJPanel Jpanel = new GameJPanel();
Jpanel.setBounds(0, 0, 720, 480);
contentPane.add(Jpanel);
Jpanel.setLayout(null);
JLabel lblNewLabel = new JLabel("New label");
lblNewLabel.setIcon(new ImageIcon(GameJFrame.class.getResource("/Resources/gamemap.png")));
lblNewLabel.setBounds(0, 0, 720, 480);
contentPane.add(lblNewLabel);
}
}
The JPanel class
package MyGamePKG;
import java.awt.BasicStroke;
public class GameJPanel extends JPanel implements ActionListener, KeyListener {
private int frameRate = 30;
private int x=0;
private int y=460;
private int x_vel, y_vel;
private Image map;
private Image character;
/**
* Create the panel.
*/
public GameJPanel() {
character = new ImageIcon(getClass().getResource("/resources/sprite-concepts.png")).getImage();
this.addKeyListener(this);
this.setFocusable(true);
Timer timer = new Timer(30, this);
timer.start();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
RenderingHints rh = new RenderingHints( RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(rh);
this.setOpaque(false);
myDrawBoxOvalsandRect(x,y,100,g2d);
//myDrawArc(x+25,y+40,50,50,550,170,g2d);
} // paintComponent
public void myDrawBoxOvalsandRect( int x, int y, int scale, Graphics my_g)
{
my_g.setColor(Color.cyan);
my_g.fillOval(x, y, 15, 15); //face
}
public void myDrawArc(int x, int y, int height, int width, int angle1, int angle2, Graphics my_g)
{
my_g.setColor(Color.red);
my_g.drawArc(x, y, 50, 50, 550, 170); //happy face
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
int c = e.getKeyCode();
if(c == KeyEvent.VK_LEFT)
{
x_vel = -2;
y_vel = 0;
}
if(c == KeyEvent.VK_UP)
{
x_vel = 0;
y_vel = -2;
}
if( c == KeyEvent.VK_RIGHT)
{
x_vel = 2;
y_vel = 0;
}
if( c == KeyEvent.VK_DOWN)
{
x_vel = 0;
y_vel = 2;
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
x_vel = 0;
y_vel = 0;
repaint();
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(x < 0)
{
x_vel = 0;
x = 0;
}
if(x > 720)
{
x_vel = 0;
x = 720;
}
if(y < 0)
{
y_vel = 0;
y = 0;
}
if(y > 480)
{
y_vel = 0;
y = 480;
}
x = x + x_vel;
y = y + y_vel;
repaint();
}
}

I suspect a number of things...
It's possible that the z-ordering of the components is rendering the background over the foreground components
The reliance on null layouts means that it's possible the window borders are taking up more space then you are allowing for, covering up portions of the content.
Don't rely on a null layout and guess work. Each platform/Look and Feel has different requirements when it comes to the frame border (amongst other things). Instead, you should consider...
Overriding getPreferredSize to provide better sizing hints
Use an OverlayLayout manager
Use JFrame#pack to pack the frame around the content instead of using setBounds
Consider painting the entire game state using a single paintComponent method, this would mean rendering the background, middleground and foreground within GameJPanel's paintComponent.
The benefit of this, is you gain complete control over the z-ordering process.
You should consider using key bindings over using KeyListener as it does not suffer from the same focus related issues and provides you with finer control over determining the level of focus that the component will raise key events

Related

Making a character land on a platform

Im trying to code a simple 2D game. I have a Square that you can move with a/w/d. I got jumping working with a sort of gravity but now I cant get myself to land on a platform. I know how to detect collision between two things but even still idk what to do. My gravity always pulls me down until I reach groundLevel which is part of the problem. Here is my code so far. There's a lot of experimenting happing so its pretty messy.
import javax.swing.Timer;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
/**
* Custom Graphics Example: Using key/button to move a line left or right.
*/
public class PlatformingGame extends JFrame implements ActionListener, KeyListener{
// Name-constants for the various dimensions
public static final int CANVAS_WIDTH = 800;
public static final int CANVAS_HEIGHT = 400;
public static final Color LINE_COLOR = Color.BLACK;
public static final Color CANVAS_BACKGROUND = Color.WHITE;
public int GRAVITY = 10;
public int TERMINAL_VELOCITY = 300;
public int vertical_speed = 0;
public int jumpSpeed;
public int groundLevel = CANVAS_HEIGHT;
int Shapes;
private DrawCanvas canvas; // the custom drawing canvas (extends JPanel)
public enum STATE {
PLAYING,
PAUSED,
ONGROUND,
INAIR
};
JButton btnStartRestat, btnExit;
Timer timer;
Rectangle2D.Double guy, platform, platform2;
Shape[] shapeArr = new Shape[10];
int dx, dy;
/** Constructor to set up the GUI */
ArrayList myKeys = new ArrayList<Character>();
public static STATE gameState = STATE.PAUSED;
//public static STATE playerState = STATE.ONGROUND;
public PlatformingGame() {
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( CANVAS_WIDTH/2 - 20, CANVAS_HEIGHT, 30, 20);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
timer = new Timer(10, this);
// Set up a panel for the buttons
JPanel btnPanel = new JPanel();
// btnPanel.setPreferredSize(new Dimension(CANVAS_WIDTH/2, CANVAS_HEIGHT));
btnPanel.setLayout(new FlowLayout());
btnStartRestat = new JButton("Start/Restart");
btnExit = new JButton("Exit");
btnPanel.add(btnStartRestat);
btnPanel.add(btnExit);
btnStartRestat.addActionListener(this);
btnExit.addActionListener(this);
// Set up a custom drawing JPanel
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Add both panels to this JFrame
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
// "this" JFrame fires KeyEvent
addKeyListener(this);
requestFocus(); // set the focus to JFrame to receive KeyEvent
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Handle the CLOSE button
pack(); // pack all the components in the JFrame
setVisible(true); // show it
}
public void generateSpikes(){
Rectangle2D.Double spikes = null;
for (int i = 0; i < 10; i++) {
spikes = new Rectangle2D.Double (CANVAS_WIDTH - 300 + i*20 , CANVAS_HEIGHT - 30 , 20, 30);
shapeArr[i] = spikes;
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==btnStartRestat)
{
generateSpikes();
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( 100, CANVAS_HEIGHT - guy.height, 15, 30);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
gameState = STATE.PLAYING;
}
else if (e.getSource()==btnExit)
{
// requestFocus(); // change the focus to JFrame to receive KeyEvent
}
else if (e.getSource()== timer){
if (isHitDetected(platform2, guy)){
// playerState = STATE.ONGROUND;
guy.y = platform2.y;
}
if (myKeys.contains('a')
&& (guy.x > 0)){
guy.x = guy.x - 5; }
if (myKeys.contains('d')
&& (guy.x < CANVAS_WIDTH - guy.width)){
guy.x = guy.x + 5; }
{
updateGuyPosition();
}
requestFocus();
canvas.repaint();
}
}
public void updateGuyPosition(){
double guyHeight = guy.height;
if (guy.x >= CANVAS_WIDTH - guy.width){
}
if(gameState == STATE.PLAYING) {
guy.y += jumpSpeed;
if (guy.y < groundLevel - guyHeight) {
// if(playerState == STATE.INAIR) {
jumpSpeed += 1;
}
// }
else {
// if(playerState == STATE.INAIR) {
//playerState = STATE.ONGROUND;
jumpSpeed = 0;
guy.y = groundLevel - guyHeight;
}
// }
if (myKeys.contains('w') == true && guy.y == groundLevel - guyHeight) {
jumpSpeed = -15;
// playerState = STATE.INAIR;
}
}
}
public static boolean isHitDetected(Shape shapeA, Shape shapeB) {
Area areaA = new Area(shapeA);
areaA.intersect(new Area(shapeB));
return !areaA.isEmpty();
}
public void keyPressed(KeyEvent evt) {
if (!myKeys.contains(evt.getKeyChar())){
myKeys.add(evt.getKeyChar());
}
}
public void keyReleased(KeyEvent evt) {
myKeys.remove(myKeys.indexOf(evt.getKeyChar()));
}
public void keyTyped(KeyEvent evt) {
}
/** The entry main() method */
public static void main(String[] args) {
PlatformingGame myProg = new PlatformingGame(); // Let the constructor do the job
myProg.timer.start();
}
/**
* DrawCanvas (inner class) is a JPanel used for custom drawing
*/
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(CANVAS_BACKGROUND);
g.setColor(LINE_COLOR);
Graphics2D g2d = (Graphics2D)g;
if(gameState == STATE.PLAYING) {
g2d.fill(guy);
g.setColor(Color.lightGray);
g2d.fill(platform);
g2d.fill(platform2);
for (int i = 0; i < 10; i++) {
g2d.fill(shapeArr[i]);
}
}
if(gameState == STATE.PAUSED) {
g.drawString("Game Paused", CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
}
}
}
}

How to implement a KeyListener to an object in a JFrame?

I'm attempting to make Frogger in java for a school project but I'm having a lot of difficulties setting up KeyListener for the actual frog character.
I've tried setting up key bindings, requesting focus for the JPanel and JFrame, moving around where the character is initiated but nothing has seemed to work. This is the remnants of my attempts.
This is the program that runs my game.
import javax.swing.*;
public class Frogger
{
JFrame frame = new JFrame("Frogger");
CPT c = new CPT();
public Frogger()
{
frame.setBounds(0,0,700,500);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(c);
}
public static void main(String[] args){
new Frogger();
}
}
The main game
public CPT() {
setLayout(new BorderLayout());
label = new JLabel("Frogger");
frame1 = new JFrame("Main");
label.setFont(new Font("Serif", Font.BOLD,50));
label.setBounds(275,10,250,250);
button1 = new JButton("PLAY");
button1.setBounds(300,350,100,50);
button1.setOpaque(false);
button1.setVisible(true);
this.setOpaque(false);
this.setLayout(null);
this.add(label);
button1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame1.setSize(700,500);
frame1.setResizable(false);
frame1.setFocusable(false);
button1.setVisible(false);
frame1.add(new TrainCanvas());
frame1.add(p1);
p1.requestFocus();
}
});
this.add(button1); }
This is the TrainCanvas class that Draws the cars in the games as well as the frog
class TrainCanvas extends JComponent
{
private int lastX = 0;
private int lastX_1 = 0;
private int lastX_2 = 0;
public TrainCanvas() {
Thread animationThread = new Thread(new Runnable() {
public void run() {
while (true) {
repaint();
try {Thread.sleep(10);} catch (Exception ex) {}
}
}
});
animationThread.start();
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
//Draws Train 1
int w = getWidth();
int h = getHeight();
int trainW_1 = 100;
int trainH_1 = 5;
int trainSpeed_1 = 3;
int x = lastX + trainSpeed_1;
if (x > w + trainW_1) {
x = -trainW_1;
}
gg.setColor(Color.BLACK);
gg.fillRect(x, h/2 + trainH_1, trainW_1, trainH_1);
lastX = x;
Graphics2D g3 = (Graphics2D) g;
frog = new Rectangle(f_x,f_y,25,25);
g3.fill(frog);
g3.setColor(Color.GREEN);
}
}
Finally, the Key Listener
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()== KeyEvent.VK_UP)
{
CPT.f_y -= 100;
repaint();
}
else if(e.getKeyCode()== KeyEvent.VK_RIGHT)
{
CPT.f_x += 100;
repaint();
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
CPT.f_x -= 100;
repaint();
}
else if(e.getKeyCode()==KeyEvent.VK_DOWN)
{
CPT.f_y += 100;
repaint();
}
else {}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
The program runs perfectly fine without giving me any errors, which is making this troublesome. Whenever it gets to the main game window, none of the keys seem to work.

Java Snake Game: Apple showing while snake is invisible

I am following a the following video to design a snake game:
https://www.youtube.com/watch?v=91a7ceECNTc
I am following it step by step, but when I run it, the snake does not show on my screen, just the apple. I think I have something wrong when implementing public void paint(Graphics g); Can someone help me?
This is the code my Main class
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame ();
GamePanel panel = new GamePanel();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Snake");
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
This is the Panel class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, KeyListener{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)
private Thread thread;
private boolean running;
private boolean right = true, left = false, up = false, down = false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 100, yCoor = 100, size = 10;
private int ticks = 0;
public GamePanel() {
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
r = new Random();
start();
}
public void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tick() {
if (snake.size() == 0) {
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if (ticks > 250000) {
if (right) {
xCoor++;
}
if (left) {
xCoor--;
}
if (up) {
yCoor--;
}
if (down) {
yCoor++;
}
ticks = 0;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if (snake.size() > size) {
snake.remove(0);
}
}
if (apples.size() == 0) {
int xCoor = r.nextInt(99);
int yCoor = r.nextInt(99);
apple = new Apple(xCoor, yCoor, 10);
apples.add(apple);
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
for (int i = 0; i < WIDTH/10; i++) {
g.drawLine(i*10, 0, i*10, HEIGHT);
}
for (int i = 0; i < HEIGHT/10; i++) {
g.drawLine(0, i*10, HEIGHT, i*10);
}
for (int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
#Override
public void run() {
while (running) {
tick();
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT && !left) {
right = true;
up = false;
down = false;
}
if (key == KeyEvent.VK_LEFT && !right) {
left = true;
up = false;
down = false;
}
if (key == KeyEvent.VK_UP && !down) {
up = true;
right = false;
left = false;
}
if (key == KeyEvent.VK_DOWN && !up) {
down = true;
right = false;
left = false;
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
The Snake's body parts class:
import java.awt.Color;
import java.awt.Graphics;
public class BodyPart {
public int xCoor, yCoor, width, height;
public BodyPart(int xCoor, int yCoor, int tileSize) {
this.xCoor = xCoor;
this.yCoor = yCoor;
width = tileSize;
height = tileSize;
}
public void tick() {
}
public void draw(Graphics g) {
g.setColor(Color.YELLOW);
g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getCoorX() {
return xCoor;
}
public void setCoorX (int xCoor) {
this.xCoor = xCoor;
}
public int getCoorY() {
return yCoor;
}
public void setCoorY(int yCoor) {
this.yCoor = yCoor;
}
}
And the Apple's Class:
import java.awt.Color;
import java.awt.Graphics;
public class Apple {
public int xCoor, yCoor, width, height;
public Apple(int xCoor, int yCoor, int tileSize) {
this.xCoor = xCoor;
this.yCoor = yCoor;
width = tileSize;
height = tileSize;
}
public void tick() {
}
public void draw(Graphics g) {
g.setColor(Color.RED);
g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getxCoor() {
return xCoor;
}
public void setxCoor(int xCoor) {
this.xCoor = xCoor;
}
public int getyCoor() {
return yCoor;
}
public void setyCoor(int yCoor) {
this.yCoor = yCoor;
}
}
Okay, so the issue comes down to some basic maths...
If we take a look at the draw method for BodyPart you will find...
g.fillRect(xCoor * width, yCoor * height, width, height);
Okay, pretty basic, but are all these values actually set too?
If we take a look at the tick method (where BodyParts are created), we can find...
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
Okay, so the width and height is 10, but what about xCoor and yCoor?
They're first initialised as instance fields along with the class...
private int xCoor = 100, yCoor = 100, size = 10;
So, a quick bit of maths tells us the initial location of the BodyPart is 100 * 10 which equals 1000x1000.
If we also take a look at ...
public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)
and
setPreferredSize(new Dimension(WIDTH, HEIGHT));
we can see that the BodyPart is actually been set off screen initially.
So, if we change the initial position to something more like...
private int xCoor = 10, yCoor = 10, size = 10;
you will find your missing snake.
General advice...
You should avoid overriding paint. It's to high in the paint chain and it's to easy to screw it up. Instead, prefer paintComponent instead (and make sure you're calling super.paintComponent). JPanel will then clear the Graphics context for you (with the background color of the component).
Swing is not thread safe. You should not be modify the UI or any state the UI relies on from outside the context of the Event Dispatching Thread.
The current "main" loop is in danger of introducing dirty updates which could cause issues later. See Concurrency in Swing. As a "general" preference, you should consider using a Swing Timer instead. It won't block the EDT, but's "ticks" are generated inside the EDT, making it safer to update the UI and/or its state from within.
You should avoid using "magic numbers" when performing your operations...
for (int i = 0; i < WIDTH/10; i++) {
g.drawLine(i*10, 0, i*10, HEIGHT);
}
Here, WIDTH and HEIGHT may not represent that actual size of the component. Instead make use of JPanel#getWidth and JPanel#getHeight instead.
As a general recommendation, you should avoid using setPreferred/Minimum/MaximumSize, it's to easy for someone else to change these to a state you don't want. Instead, override getPreferred/Minimum/MaximumSize instead, this way you maintain control.

Java Graphics Not Displaying In OS X

I'm a Computer Science student who uses a mid-2009 MacBook Pro running OS X Yosemite 10.10.3. I recently had a class activity in my Object-Oriented programming class where we went step-by-step in creating an interactive Java program in which the user simply clicks a football and watch it get kicked over the goalpost with a green background.
However, even though my Java code matched the code of my classmates' Windows computers with no syntax errors, there are some problems with my program properly running while theirs work perfectly fine:
While the window for the application opens with the title and green background, neither the football nor goalpost is displayed. However, if I manually stretch the window, they show back up. I've tried changing the window dimensions to see if that was causing it to no avail.
When the football is clicked, instead of moving towards the goalpost as intended, both the football and goalpost vanish and don't return. Only the green background is displayed, even when I try manually stretching the window again.
I still submitted the code to my instructor, which worked fine on his computer (he doesn't understand the problem either since he doesn't use OS X). I tried to run the code on two other IDE's to see if Eclipse was the problem, but they all produced the same results. If this is an OS X or computer-exclusive problem, how am I able to get around this?
This is my current code:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Football extends JFrame {
final int WINDOW_WIDTH = 800;
final int WINDOW_HEIGHT = 400;
private int x = 40; // Ball's X coordinate
private int y = 300; // Ball's Y coordinate
private final int WIDTH = 35; // Ball's width
private final int HEIGHT = 60; // Ball's height
private final int X_MOVE = 14; // Pixels to move ball
private final int Y_MOVE = 4;
private final int TIME_DELAY = 25; // Time delay
private Timer timer; // Timer object
/**
init method
*/
public Football() {
setTitle("Football");
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// Set Background to a Dark Green
getContentPane().setBackground(new Color(0, 220, 50));
// initTimer();
addMouseListener(new FbMouseListener());
}
public void paint(Graphics g)
{
// Call the superclass paint method.
super.paint(g);
// Set the color to Brown
g.setColor(new Color(129, 74, 25));
// Draw the football
g.fillOval(x, y, WIDTH, HEIGHT);
// Draw the Goalpost
g.setColor(Color.YELLOW);
g.fillRect(670, 240, 5, 140);
g.fillRect(610, 80, 5, 140);
g.fillRect(740, 120, 5, 140);
// Need Thicker line
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g2.drawLine(612, 220, 742, 260);
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
// Update the ball's position
y -= Y_MOVE;
x += X_MOVE;
// Force a call to the paint method
repaint();
}
}
public void initTimer()
{
timer = new Timer(TIME_DELAY, new TimerListener());
timer.start();
}
private class FbMouseListener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
if (e.getX() >= x && e.getX() <= (x + WIDTH) && e.getY() >= y && e.getY() <= (y + HEIGHT))
{
initTimer();
}
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public static void main(String[] args)
{
Football fb = new Football();
}
}
Any help or suggestions would be appreciated, as I would like to make sure this doesn't affect any future programs I create.
Generally, overriding paint of a top level container like JFrame is a bad idea, JFrame contains a bunch of child components that can be painted independently of the parent, which seems to be the case here
As you can see, there are (at least) 3 other components in between the frame and the user
Generally, you should create a custom class which extends from something like JPanel and override it's paintComponent and perform your custom painting there.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Football {
public static void main(String[] args) {
new Football();
}
public Football() {
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("Football");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FootballPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class FootballPane extends JPanel {
public static final int WINDOW_WIDTH = 800;
public static final int WINDOW_HEIGHT = 400;
private int x = 40; // Ball's X coordinate
private int y = 300; // Ball's Y coordinate
private static final int WIDTH = 35; // Ball's width
private static final int HEIGHT = 60; // Ball's height
private static final int X_MOVE = 14; // Pixels to move ball
private static final int Y_MOVE = 4;
private static final int TIME_DELAY = 25; // Time delay
private Timer timer; // Timer object
/**
* init method
*/
public FootballPane() {
// Set Background to a Dark Green
setBackground(new Color(0, 220, 50));
// initTimer();
addMouseListener(new FbMouseListener());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
// Call the superclass paint method.
super.paintComponent(g);
// Set the color to Brown
g.setColor(new Color(129, 74, 25));
// Draw the football
g.fillOval(x, y, WIDTH, HEIGHT);
// Draw the Goalpost
g.setColor(Color.YELLOW);
g.fillRect(670, 240, 5, 140);
g.fillRect(610, 80, 5, 140);
g.fillRect(740, 120, 5, 140);
// Need Thicker line
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
g2.drawLine(612, 220, 742, 260);
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Update the ball's position
y -= Y_MOVE;
x += X_MOVE;
// Force a call to the paint method
repaint();
}
}
public void initTimer() {
timer = new Timer(TIME_DELAY, new TimerListener());
timer.start();
}
private class FbMouseListener implements MouseListener {
public void mouseClicked(MouseEvent e) {
if (e.getX() >= x && e.getX() <= (x + WIDTH) && e.getY() >= y && e.getY() <= (y + HEIGHT)) {
initTimer();
}
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
}
See Painting in AWT and Swing and Performing Custom Painting for more details

Java Swing: JPanels painting over each other

Alright, so I have two JFrames each with a different implementation of JPanel sitting inside of them. When I call repaint() on the JPanels, what is painted on one JPanel also becomes painted on the other JPanel.
I know I could take care of this by calling something like g.clearRect(), but there are too many components to repaint every time.
Any idea why this is happening?
//This makes the two JFrames and JPanels, sets everything up
public void makeSpaceSimulation() {
int dimen = 10000;
int scale = 20;
int numOfClusters = 30;
int planPerCluster = 2000;
SpaceShip s = new SpaceShip(dimen, scale);
QuadTree t = new QuadTree(dimen, 20);
new PlanetCreationTest(t, dimen, scale, numOfClusters, planPerCluster);
makeMap(dimen, scale, s, t);
makePOV(s, t, scale, dimen);
}
public void makeMap(int dimen, int scale, SpaceShip s, QuadTree t) {
final JFrame f = new JFrame();
f.setSize(dimen / scale, dimen / scale);
f.setLocation(0, 0);
f.setTitle("Map Panel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mapP = new MapPanel(scale, s, dimen);
mapP.setLayout(new BorderLayout());
mapP.addTree(t);
f.add(mapP);
f.setVisible(true);
Insets i = f.getInsets();
f.setSize(dimen / scale + (i.left + i.right) + 2, dimen / scale
+ (i.top + i.bottom) + 2);
Thread th = new Thread() {
public void run() {
while (true) {
mapP.repaint();
}
}
};
th.start();
}
public void makePOV(final SpaceShip s, QuadTree t, int scale, int dimen) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
JFrame f = new JFrame();
f.setSize(500, 500);
f.setLocation(screenSize.width - 500, 0);
f.setTitle("POV Panel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
povP = new POVPanel(s, scale, dimen);
povP.setLayout(new BorderLayout());
povP.addTree(t);
povP.setFocusable(true);
povP.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent arg0) {
final int i = arg0.getKeyCode();
Thread th = new Thread() {
public void run() {
if (i == 39) {
s.moveRight();
} else if (i == 37) {
s.moveLeft();
} else if (i == 40) {
s.moveDown();
} else if (i == 38) {
s.moveUp();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
th.start();
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
});
f.add(povP);
f.setVisible(true);
Insets i = f.getInsets();
f.setSize(dimen / 20 + (i.left + i.right) + 2, dimen / 20
+ (i.top + i.bottom) + 2);
Thread th = new Thread() {
public void run() {
while (true) {
povP.repaint();
}
}
};
th.start();
}
//here's the MapPanel
public class MapPanel extends JPanel {
private QuadTree q;
private int scale;
private int dimen;
private SpaceShip s;
private boolean firstDraw;
public MapPanel(int scale, SpaceShip s, int dimen) {
this.dimen = dimen;
q = new QuadTree(0, 0);
this.scale = scale;
this.s = s;
firstDraw = true;
}
public void addTree(QuadTree q) {
this.q = q;
}
public void paintComponent(Graphics g) {
if (firstDraw) {
q.draw(g, scale, new Point(0, 0));
s.drawScaledGeometry(g);
System.out.println("Totally drew that");
firstDraw = false;
} else {
g.clearRect(s.viewDistance.x/scale, s.viewDistance.y/scale,
s.viewDistance.width/scale, s.viewDistance.height/scale);
q.quadDraw(g, scale, s.viewDistance, new Point(0, 0));
s.drawScaledGeometry(g);
}
}
}
//and this is the POVPanel
public POVPanel(SpaceShip s, int scale, int dimen) {
super();
this.s = s;
// this.scale = scale;
this.dimen = dimen;
}
public void addTree(QuadTree q) {
this.q = q;
}
public void paintComponent(Graphics g) {
g.clearRect(0, 0, dimen / 20, dimen / 20);
q.quadDraw(g, 1, s.viewDistance, s.getMoved());
s.drawGeometry(g);
}
This is (one) of your problems...
public void paintComponent(Graphics g) {
if (firstDraw) {
q.draw(g, scale, new Point(0, 0));
s.drawScaledGeometry(g);
System.out.println("Totally drew that");
firstDraw = false;
} else {
g.clearRect(s.viewDistance.x/scale, s.viewDistance.y/scale,
s.viewDistance.width/scale, s.viewDistance.height/scale);
q.quadDraw(g, scale, s.viewDistance, new Point(0, 0));
s.drawScaledGeometry(g);
}
}
The Graphics context is shared during the paint cycle, meaning when you get it, you will be getting the same context used to paint all the other components on the screen.
You MUST call super.paintComponent(g), which will take care of preparing the graphics context for this component to start painting.
Update #1
Again...
public void paintComponent(Graphics g) {
super.paintComponent(g); // <-- Call me instead...
//g.clearRect(0, 0, dimen / 20, dimen / 20);
q.quadDraw(g, 1, s.viewDistance, s.getMoved());
s.drawGeometry(g);
}
Update #2
I'm also seriously concerned by this
while (true) {
mapP.repaint();
}
This could seriously impact the performance of you application. You DO NOT control the paint cycle, that's the responsibility of the repaint manager. The repaint manager will decide when a repaint is required. Calling repaint repetitively like this could actually cause the repaint manager to delay actually scheduling a paint cycle.
Much better to use a javax.swing.Timer, it's simpler and safer...
Timer timer = new Timer(25, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
mapP.repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
You might find reading through
Performing Custom Painting
Painting in AWT and Swing
Helpful
Update #3
Avoid KeyListener, it will only make you cry. Instead, use the key bindings API

Categories

Resources