I'm new to java and trying yo create a basic game and right now and trying to program the player class. However only the JFRame appears when i run the game. These are my thress classes and they show no errors.
import java.awt.Color;
import javax.swing.JFrame;
public class Game extends JFrame {
public
final static int WIDTH = 700, HEIGHT = 450;
public
GamePanel panel;
public Game() {
setSize(WIDTH, HEIGHT);
setTitle("Game");
setBackground(Color.WHITE);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
}
public GamePanel getPanel() {
return panel;
}
public static void main(String[] args) {
new Game();
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener, KeyListener {
public
Game game;
public
Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
addKeyListener(this);
setFocusable(true);
}
public
void update() {
player.update();
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
public Player getPlayer(int playerNo) {
return player;
}
public void keyPressed(KeyEvent e) {
player.pressed(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
player.released(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {
;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
player.paint(g);
}
}
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Color;
public class Player {
public
static final int WIDTH = 50, HEIGHT = 50;
public
Game game;
public
int left, right;
public
int y;
public
int x, xa;
public Player(Game game, int left, int right, int x) {
this.game = game;
this.x = x;
y = game.getHeight() - 20;
this.left = left;
this.right = right;
this.y = y;
x = game.getWidth() - 36;
}
public void update() {
if (x > 0 && x < game.getWidth() - WIDTH - 36)
x += xa;
else if (x == 0)
x++;
else if (x == game.getWidth() - WIDTH - 36)
x--;
}
public void pressed(int keyCode) {
if (keyCode == left)
xa = -1;
else if (keyCode == right)
xa = 1;
}
public void released(int keyCode) {
if (keyCode == left || keyCode == right)
xa = 0;
}
public Rectangle getBounds() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public void paint(Graphics g) {
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(Color.ORANGE);
}
}
Take setVisible(true); and move it it to the last of the Game constructor. Also you should make sure you're working within the context of the EDT when building your UI's, see Initial Threads for more details
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game extends JFrame {
public final static int WIDTH = 700, HEIGHT = 450;
public GamePanel panel;
public Game() {
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
setSize(WIDTH, HEIGHT);
setVisible(true);
}
public GamePanel getPanel() {
return panel;
}
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();
}
new Game();
}
});
}
}
Basically, Swing's layout management is lazy, it won't try to update the container hierarchy until you tell it (revalidate) or it becomes realised or resized, this is a good thing, as the operation can be expensive.
Next, take a look at player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
You're setting the position of the player to be 36 pixels less than the components width, but when this is called, the width will be 0.
Basically, you need to allow the UI to "settle" before making this types of calls. This is actually not that easy. You could use a ComponentListener and monitor for the componentResized event, but a window can be resized a number of times when it's first initialized, to this end, you need to "wait" until the size is "settled", for example...
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
Then you would need to update GamePanel to provide an init method...
public class GamePanel extends JPanel implements ActionListener, KeyListener {
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
public void init() {
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
repaint();
}
//...
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (player != null) {
player.paint(g);
}
}
}
You have a wide range of "magic" numbers, which don't equate to what you're actually trying to do, for example...
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
shouldn't that be game.getWidth() - Player.WIDTH?
And then in Player...
public Player(Game game, int left, int right, int x) {
this.game = game;
this.x = x;
y = game.getHeight() - 20;
//...
this.y = y;
x = game.getWidth() - 36;
}
You assign the parameter x to the field x, but then change it at the end of the constructor? Also, this.y = y makes no sense!?
Now, let's talk about what a bad idea setSize(WIDTH, HEIGHT);, which relates to why your player doesn't appear where you want it to...
Windows have decorations, so your viewable area will ALWAYS be smaller than the actual window size, what's worse, the size of the decorations are variable. Instead, you should use JFrame#pack to pack the window around it's contents and have the contents provide hints about big it wants to be.
Have a look at How can I set in the midst? for more details.
Instead of setting the size of the frame, you should be using pack...
public class Game extends JFrame {
public GamePanel panel;
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
pack();
setVisible(true);
}
And allowing GamePanel to make decisions about how big it wants to be...
public static class GamePanel extends JPanel implements ActionListener, KeyListener {
public final static int WIDTH = 700, HEIGHT = 450;
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
This also means that instead of passing Game to your objects, you should be passing GamePanel to them and using its dimensions, for example...
public static class Player {
//...
public Player(GamePanel game, int left, int right, int x) {
this.game = game;
this.left = left;
this.right = right;
this.x = x;
y = game.getHeight() - HEIGHT;
}
You should also not be using KeyListener and instead should be using the Key Bindings API instead, which will solve the focus related issue and make it easier to configure the key strokes
Basically, you're missing some core understandings about how the Swing framework works, which is causing no end of issues, I'd take the time to learn more about how the framework works generally before diving into something as complex as game development
Runnable example...
Now, because I've basically butchered your code to get it to work...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game extends JFrame {
public GamePanel panel;
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
pack();
setVisible(true);
}
public GamePanel getPanel() {
return panel;
}
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();
}
new Game();
}
});
}
public static class GamePanel extends JPanel implements ActionListener, KeyListener {
public final static int WIDTH = 700, HEIGHT = 450;
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
public void init() {
System.out.println("!!");
player = new Player(this, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, getWidth() - 50);
repaint();
}
public void update() {
player.update();
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
public Player getPlayer(int playerNo) {
return player;
}
public void keyPressed(KeyEvent e) {
player.pressed(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
player.released(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {
;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (player != null) {
player.paint(g);
}
}
}
public static class Player {
public static final int WIDTH = 50, HEIGHT = 50;
public GamePanel game;
public int left, right;
public int y;
public int x, xa;
public Player(GamePanel game, int left, int right, int x) {
this.game = game;
this.left = left;
this.right = right;
this.x = x;
y = game.getHeight() - HEIGHT;
}
public void update() {
if (x > 0 && x < game.getWidth() - WIDTH - 36) {
x += xa;
} else if (x == 0) {
x++;
} else if (x == game.getWidth() - WIDTH - 36) {
x--;
}
}
public void pressed(int keyCode) {
if (keyCode == left) {
xa = -1;
} else if (keyCode == right) {
xa = 1;
}
}
public void released(int keyCode) {
if (keyCode == left || keyCode == right) {
xa = 0;
}
}
public Rectangle getBounds() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public void paint(Graphics g) {
System.out.println(x + "x" + y);
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(Color.ORANGE);
}
}
}
Related
So I am creating a brick breaker game. I got the paddle moving using key listeners, however I got some advice to use key bindings instead. I've been reading and looking everywhere on this and I think I've kinda got the idea but the implementation is confusing me a bit.
For my paddle, I created it with the paint component. Hence this is what I want to be able to move left and right with the arrow keys. However, all the key bindings explanations I find seem to use JComponent which the paddle is not. Is there a way around it or will I have to make my paddle a JComponent image icon instead? If so would I just load the image into my Paddle class?
Also what's the best way of structuring my code to contain the key bindings? For instance am I better off creating a whole new class for it, or putting it in e.g. my GamePanel class
Any tips?
Here is some of my code so you can get an idea:
Main Class:
public class BrickBreakerGameApp {
public static void main(String[] args) {
int pw = 500;
int ph = 900;
GamePanel gPanel = new GamePanel(pw,ph);
GameFrame gFrame = new GameFrame();
gFrame.getContentPane().add(gPanel); //add game panel to frame
// gFrame.addKeyListener(gPanel); //adds the key listener for the game panel frame
gFrame.pack();
gFrame.setVisible(true); //make frame visible
}
}
GameFrame class:
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
//Global Variables
public int frameWidth = 500;
public int frameHeight = 800;
//create constructor
GameFrame () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //so app closes properly
this.setPreferredSize(new Dimension(frameWidth, frameHeight)); //set frame size
this.setTitle("Brick Breaker Game");
ImageIcon icon = new ImageIcon("res/brick-breaker-logo.jpg"); //create image icon
this.setIconImage(icon.getImage()); //update frame icon
this.pack();
}
}
GamePanel Class
import java.awt.Color;
import java.awt.event.*;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.*;
/**
* This class handles the game panel as a whole
*/
public class GamePanel extends JPanel {
// Global Variables
private Ball ball;
private Paddle paddle;
private Bricks bricks;
private GameFrame gameFrame;
private int width;
private int height;
private int[] bArray = new int[20];
// create a constructor
GamePanel (int gamePanelWidth, int gamePanelHeight) {
this.setWidth(gamePanelWidth);
this.setHeight(gamePanelHeight);
initialiseGame();
this.isVisible();
}
private void initialiseGame() {
ball = new Ball(10, 520, 30, 30); //create the ball object
paddle = new Paddle(this, 50, 700, 100, 10); //creates paddle object
bricks = new Bricks(10, 10, 60, 30, bArray); //creates the bricks object
//for key binding initialisation
MotionAction motion = new MotionAction(paddle, 24);
}
// paint all the elements in
public void paintComponent(Graphics g) {
super.paintComponent(g);
// background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// paddle
// g.setColor(Color.CYAN);
// g.fillRect(paddle.getPaddleX(), paddle.getPaddleY(), paddle.getPaddleWidth(), paddle.getPaddleHeight());
// ball
g.setColor(Color.MAGENTA);
g.fillOval(ball.getBallX(), ball.getBallY(), ball.getBallWidth(), ball.getBallHeight());
// brick
g.setColor(Color.GREEN);
g.fillRect(bricks.getBrickX(), bricks.getBrickY(), bricks.getBrickWidth(), bricks.getBrickHeight());
}
//add any unimplemented methods because we are using an interface
/* #Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
paddle.moveLeft();
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
paddle.moveRight();
}
this.repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
} */
//create get and set methods for all panel attributes
public int getWidth() {
return width;
}
public void setWidth(int pWidth) {
this.width = pWidth;
}
public int getHeight() {
return height;
}
public void setHeight(int pHeight) {
this.height = pHeight;
}
}
Paddle class:
import javax.swing.AbstractAction;
import java.awt.event.*;
public class Paddle extends AbstractAction implements ActionListener {
//Global Variables
private int paddleWidth;
private int paddleHeight;
private int paddleX; //paddle x position
private int paddleY;
private GamePanel gamePanel;
//create paddle constructor
Paddle() {
}
//create a paddle constructor based off parameters
Paddle(GamePanel gPanel, int pX, int pY, int pWidth, int pHeight) {
//set the values
this.setPaddleWidth(pWidth);
this.setPaddleHeight(pHeight);
this.setPaddleX(pX);
this.setPaddleY(pY);
this.setGamePanel(gPanel);
}
//create get and set methods for all paddle attributes
public int getPaddleWidth() {
return paddleWidth;
}
public void setPaddleWidth(int pWidth) {
this.paddleWidth = pWidth;
}
public int getPaddleHeight() {
return paddleHeight;
}
public void setPaddleHeight(int pHeight) {
this.paddleHeight = pHeight;
}
public int getPaddleX() {
return paddleX;
}
public void setPaddleX(int pX) {
this.paddleX = pX;
}
public int getPaddleY() {
return paddleY;
}
public void setPaddleY(int pY) {
this.paddleY = pY;
}
public GamePanel getGamePanel() {
return gamePanel;
}
public void setGamePanel(GamePanel gPanel) {
this.gamePanel = gPanel;
}
//move the paddle left if it is not already positoned at 0 (far left)
public void moveLeft() {
try {
if(getPaddleX() <= 0) {
setPaddleX(0);
System.out.println("less than 0, x: " + getPaddleX());
}
else if (getPaddleX() > 0) {
setPaddleX(getPaddleX()-10); //to move paddle left -10
// gamePanel.repaint(getPaddleX()+10, getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint old position
// gamePanel.repaint(getPaddleX(), getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint new position
System.out.println("left, x: " + getPaddleX());
}
}
catch (Exception e) {
}
}
//move the paddle right if it is not already positioned to the far right of the panel
public void moveRight() {
if(getPaddleX() >= gamePanel.getWidth() - getPaddleWidth()) { //dont move the paddle if it is on the right edge of the panel
setPaddleX(gamePanel.getWidth() - getPaddleWidth());
System.out.println("right1, x:" + getPaddleX());
}
else if ((getPaddleX()+getPaddleWidth()) <= gamePanel.getWidth()){ //if the paddle is within the panel bounds
setPaddleX(getPaddleX() + 10); //to move paddle right +10
System.out.println("right, x:" + getPaddleX());
}
}
}
Here are some of the main resources I've being trying:
This one I tried but got really confused on the best way to integrate it into my own code --> https://tips4java.wordpress.com/2013/06/09/motion-using-the-keyboard/
This one I tried until I realised I don't have jcomponent --> https://coderanch.com/t/606742/java/key-bindings
You could register the key bindings with the GamePanel, or the frame content pane (both extend from JComponent). E.g.:
public class DemoFrame extends JFrame {
public static void main(String[] args) throws Exception {
new DemoFrame().setVisible(true);
}
public DemoFrame() {
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
{
String actionId = "left";
KeyStroke keyStroke = KeyStroke.getKeyStroke("LEFT");
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, actionId);
getRootPane().getActionMap().put(actionId, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
actionLeft();
}
});
}
}
private void actionLeft() {
System.out.println("left");
}
}
I'm making a brick breaker game and I'm stuck on getting the repaint() method working. I've used the debugger and it's not calling the paintComponent method. I am trying to get the paddle to move left or right when the left/right arrow keys are pressed. Hence I am trying to repaint the graphics, but have no luck in it working and can't figure out what I'm doing wrong.
My main class:
public class BrickBreakerGameApp {
public static void main(String[] args) {
int pw = 500;
int ph = 900;
GamePanel gPanel = new GamePanel(pw,ph);
GameFrame gFrame = new GameFrame();
gFrame.getContentPane().add(gPanel); //add game panel to frame
gFrame.addKeyListener(new GamePanel(pw,ph)); //adds the key listener for the game panel frame
gFrame.pack();
gFrame.setVisible(true); //make frame visible
}
}
My frame class:
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
//Global Variables
public int frameWidth = 500;
public int frameHeight = 800;
//create constructor
GameFrame () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //so app closes properly
this.setPreferredSize(new Dimension(frameWidth, frameHeight)); //set frame size
this.setTitle("Brick Breaker Game");
ImageIcon icon = new ImageIcon("res/brick-breaker-logo.jpg"); //create image icon
this.setIconImage(icon.getImage()); //update frame icon
this.pack();
}
}
My panel class:
import java.awt.Color;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.*;
/**
* This class handles the game panel as a whole
*/
public class GamePanel extends JPanel implements ActionListener, KeyListener {
// Global Variables
private Ball ball;
private Paddle paddle;
private GameFrame gameFrame;
private int width;
private int height;
// create a constructor
GamePanel (int gamePanelWidth, int gamePanelHeight) {
this.setWidth(gamePanelWidth);
this.setHeight(gamePanelHeight);
initialiseGame();
this.isVisible();
}
private void initialiseGame() {
ball = new Ball(10, 520, 30, 30); //create the ball object
paddle = new Paddle(this, 50, 550, 100, 10); //creates paddle object
}
// paint all the elements in
public void paintComponent(Graphics g) {
super.paintComponent(g);
// background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// paddle
g.setColor(Color.CYAN);
g.fillRect(paddle.getPaddleX(), paddle.getPaddleY(), paddle.getPaddleWidth(), paddle.getPaddleHeight());
// ball
g.setColor(Color.MAGENTA);
g.fillOval(ball.getBallX(), ball.getBallY(), ball.getBallWidth(), ball.getBallHeight());
}
//add any unimplemented methods because we are using an interface
#Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
paddle.moveLeft();
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
paddle.moveRight();
}
this.repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
//create get and set methods for all paddle attributes
public int getWidth() {
return width;
}
public void setWidth(int pWidth) {
this.width = pWidth;
}
public int getHeight() {
return height;
}
public void setHeight(int pHeight) {
this.height = pHeight;
}
}
My Paddle class:
public class Paddle {
//Global Variables
private int paddleWidth;
private int paddleHeight;
private int paddleX; //paddle x position
private int paddleY;
private GamePanel gamePanel;
//create paddle constructor
Paddle() {
}
//create a paddle constructor based off parameters
Paddle(GamePanel gPanel, int pX, int pY, int pWidth, int pHeight) {
//set the values
this.setPaddleWidth(pWidth);
this.setPaddleHeight(pHeight);
this.setPaddleX(pX);
this.setPaddleY(pY);
this.setGamePanel(gPanel);
}
//create get and set methods for all paddle attributes
public int getPaddleWidth() {
return paddleWidth;
}
public void setPaddleWidth(int pWidth) {
this.paddleWidth = pWidth;
}
public int getPaddleHeight() {
return paddleHeight;
}
public void setPaddleHeight(int pHeight) {
this.paddleHeight = pHeight;
}
public int getPaddleX() {
return paddleX;
}
public void setPaddleX(int pX) {
this.paddleX = pX;
}
public int getPaddleY() {
return paddleY;
}
public void setPaddleY(int pY) {
this.paddleY = pY;
}
public GamePanel getGamePanel() {
return gamePanel;
}
public void setGamePanel(GamePanel gPanel) {
this.gamePanel = gPanel;
}
//move the paddle left if it is not already positoned at 0 (far left)
public void moveLeft() {
try {
if(getPaddleX() <= 0) {
setPaddleX(0);
System.out.println("less than 0, x: " + getPaddleX());
}
else if (getPaddleX() > 0) {
setPaddleX(getPaddleX()-10); //to move paddle left -10
// gamePanel.repaint(getPaddleX()+10, getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint old position
// gamePanel.repaint(getPaddleX(), getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint new position
System.out.println("left, x: " + getPaddleX());
}
}
catch (Exception e) {
}
}
//move the paddle right if it is not already positioned to the far right of the panel
public void moveRight() {
if(getPaddleX() >= gamePanel.getWidth() - getPaddleWidth()) { //dont move the paddle if it is on the right edge of the panel
setPaddleX(gamePanel.getWidth() - getPaddleWidth());
System.out.println("right1, x:" + getPaddleX());
}
else if ((getPaddleX()+getPaddleWidth()) <= gamePanel.getWidth()){ //if the paddle is within the panel bounds
setPaddleX(getPaddleX() + 10); //to move paddle right +10
System.out.println("right, x:" + getPaddleX());
}
}
}
After a little bite of debugging/testing I found out that in your main method:
public class BrickBreakerGameApp {
public static void main(String[] args) {
int pw = 500;
int ph = 900;
GamePanel gPanel = new GamePanel(pw,ph);
GameFrame gFrame = new GameFrame();
gFrame.getContentPane().add(gPanel); //add game panel to frame
gFrame.addKeyListener(new GamePanel(pw,ph)); //adds the key listener for the game panel frame
gFrame.pack();
gFrame.setVisible(true); //make frame visible
}
}
to the gFrame.addKeyListener method call do not add a new GamePanel but the one that you created already, namely:
gFrame.addKeyListener(gPanel); //adds the key listener for the game panel frame
I have the following three classes:
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
public class Racquet {
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game= game;
}
public void move() {
if (x + xa > 0 && x + xa < game.getWidth()-60)
x = x + xa;
}
public void paint(Graphics2D g) {
g.fillRect(x, 330, 60, 10);
}
public void keyReleased(KeyEvent e) {
xa = 0;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
}
import java.awt.Graphics2D;
public class Ball {
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game) {
this.game= game;
}
void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > game.getWidth() - 30)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > game.getHeight() - 30)
ya = -1;
x = x + xa;
y = y + ya;
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Game extends JPanel {
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
private void move() {
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
racquet.paint(g2d);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Mini Tennis");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
for(long i=0;i<=100000*100;i++)
{
}
}
}
}
import javax.swing.*;
import java.awt.event.*;
class T extends JFrame implements ActionListener
{
public T()
{
setVisible(true);
setSize(300,300);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
JButton b1=new JButton("Click me");
b1.setBounds(150,150,50,50);
b1.addActionListener(this);
add(b1);
}
public void actionPerformed(ActionEvent a)
{
Game ob=new Game();
ob.main(null);
}
public static void main(String args[])
{
T obj=new T();
}
}
When I execute the class T, I am supposed to get the Game but I don't know why I get the blank screen and not the game. I am new to Java so could someone help me out?
The reason that the T class doesn't work is that your code uses bad code to run the game loop, a while (true) loop that if called on the Swing event thread (as T does), will completely block the this thread, preventing it from performing its necessary functions including drawing the GUI.
The solution is to use a Swing Timer to drive your game loop, not a while (true) loop. To gain a better understanding of Swing threading issues, please read: Lesson: Concurrency in Swing
I have created a program that just moves a ball across a screen. I used to have it all in one class, but decided that it looked too messy so I split it up into three different classes: Main... initializes everything, Game... which paints everything and is a JPanel, and AL which is a KeyListener (which is also where the problem is). The problem is that I can't get the program to repaint from my AL class no matter what I try to pass into it. Can anyone help with this? Here are my three classes:
import java.awt.Color;
import javax.swing.JFrame;
public class Main {
static Game game;
static JFrame frame;
public static void main(String[] args) {
game = new Game();
frame = new JFrame();
frame.getContentPane().add(game);
frame.addKeyListener(new AL(game, frame));
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.setVisible(true);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
-
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
JFrame frame;
public void changeCoord() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
x = 250;
y = 250;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run() {
try {
while (true) {
changeCoord();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
-
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class AL extends KeyAdapter {
Game game;
JFrame frame;
public AL(Game game, JFrame frame) {
this.game = game;
this.frame = frame;
}
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
game.setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
game.setXCoord(+1);
}
if (keyCode == e.VK_UP) {
game.setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
game.setYCoord(+1);
}
game.repaint();
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
game.setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
game.setXCoord(0);
}
if (keyCode == e.VK_UP) {
game.setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
game.setYCoord(0);
}
game.repaint();
}
}
Let's start with the obvious....
This is problematic...
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
There's no need to implement double buffering in Swing components, they already are. Also, you're breaking the painting contract, by not call the paint methods super methods
The whole thing should be...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
See Painting in AWT and Swing and Performing Custom Painting for more details
KeyListener is well known for been problematic. It will only raise key events if the component it registered to is focuable AND has keyboard focus. A JPanel by default, is not focusable. Before you run of and try and make it focusable (and get bitterly disappointed), you should be using the Key Bindings API instead, which was designed to over come the limitations of KeyListener
As a basic example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Game extends JPanel {
int x, y, xCoord, yCoord;
public Game() {
x = 250;
y = 250;
addKeyBinding(KeyEvent.VK_LEFT, "move.left", new MoveAction(this, -1, 0));
addKeyBinding(KeyEvent.VK_RIGHT, "move.right", new MoveAction(this, 1, 0));
addKeyBinding(KeyEvent.VK_UP, "move.up", new MoveAction(this, 0, -1));
addKeyBinding(KeyEvent.VK_DOWN, "move.down", new MoveAction(this, 0, 1));
}
protected void addKeyBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
}
protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public void changeCoord() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
repaint();
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
changeCoord();
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
changeCoord();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(480, 480);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
}
public class MoveAction extends AbstractAction {
private int xDelta;
private int yDelta;
// I'd prefer an interface with just the "move" methods, but
// that's more time I don't have
private Game game;
public MoveAction(Game game, int xDelta, int yDelta) {
this.xDelta = xDelta;
this.yDelta = yDelta;
this.game = game;
}
#Override
public void actionPerformed(ActionEvent e) {
game.setXCoord(xDelta);
game.setYCoord(yDelta);
}
}
}
But, wait, that isn't exactly what you want (trust me, I'm an anoymouse person on the Internet ;)), a better example might be...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Direction {
UP,
LEFT,
DOWN,
RIGHT;
}
public class Game extends JPanel {
int x, y, xCoord, yCoord;
private Set<Direction> movement;
public Game() {
x = 250;
y = 250;
movement = new HashSet<>(4);
addKeyPressedBinding(KeyEvent.VK_LEFT, "left.pressed", new MoveAction(movement, Direction.LEFT, true));
addKeyReleasedBinding(KeyEvent.VK_LEFT, "left.released", new MoveAction(movement, Direction.LEFT, false));
addKeyPressedBinding(KeyEvent.VK_RIGHT, "right.pressed", new MoveAction(movement, Direction.RIGHT, true));
addKeyReleasedBinding(KeyEvent.VK_RIGHT, "right.released", new MoveAction(movement, Direction.RIGHT, false));
addKeyPressedBinding(KeyEvent.VK_UP, "up.pressed", new MoveAction(movement, Direction.UP, true));
addKeyReleasedBinding(KeyEvent.VK_UP, "up.released", new MoveAction(movement, Direction.UP, false));
addKeyPressedBinding(KeyEvent.VK_DOWN, "down.pressed", new MoveAction(movement, Direction.DOWN, true));
addKeyReleasedBinding(KeyEvent.VK_DOWN, "down.released", new MoveAction(movement, Direction.DOWN, false));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
changeCoord();
}
});
timer.start();
}
protected void addKeyBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
}
protected void addKeyPressedBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
}
protected void addKeyReleasedBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
}
protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public void changeCoord() {
if (movement.contains(Direction.UP)) {
y--;
} else if (movement.contains(Direction.DOWN)) {
y++;
}
if (movement.contains(Direction.LEFT)) {
x--;
} else if (movement.contains(Direction.RIGHT)) {
x++;
}
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
repaint();
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
changeCoord();
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
changeCoord();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(480, 480);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
}
public class MoveAction extends AbstractAction {
private Set<Direction> movement;
private Direction direction;
private boolean pressed;
public MoveAction(Set<Direction> movement, Direction direction, boolean pressed) {
this.movement = movement;
this.direction = direction;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
movement.add(direction);
} else {
movement.remove(direction);
}
}
}
}
What this does is simply activates a flag when a key is pressed (and deactivates it when it's released), then in a Swing Timer, we check which keys are "active" and update the location of the ball.
What this does is, eliminates the key "stutter" which is caused by the OS when a key is first pressed and held. A delay is inserted between the first key and the repeated key events. Instead, we just turn the flag on and off as we like.
It also allows you to move in two directions at the same time (horizontally and vertically)
Have a look at Concurrency in Swing and How to use Swing Timers for more details
I am trying to make a program that has a moving ball and a platform that it will sit on. I am new too java and I cant figure out how to detect when 2 swing objects are overlapping. My code it below and I am wondering what the best way is to detect overlapping objects.
KeyDemo.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class KeyDemo
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel panel = new JPanel();
LayoutManager overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Move the Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WallComponent wc1 = new WallComponent(400, 400);
final BallComponent bc = new BallComponent(400, 300);
panel.add(wc1);
panel.add(bc);
frame.add(panel);
KeyboardController kc = new KeyboardController(bc);
frame.addKeyListener(kc);
frame.setVisible(true);
class AnimationListener implements ActionListener{
public void actionPerformed(ActionEvent event){
bc.tick();
//wc1.checkOverlap(bc);
}
}
ActionListener aListener = new AnimationListener();
final Timer timer = new Timer(1, aListener);
timer.start();
}
}
KeyboardController.java:
import java.awt.*;
import java.awt.event.*;
public class KeyboardController implements KeyListener
{
BallComponent bComp;
public KeyboardController(BallComponent t)
{
bComp = t;
}
/** Handle the key pressed event from the text field. */
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == 38)
{
System.out.println("Pressed Up!");
bComp.moveUp();
}
if(keyCode == 37)
{
System.out.println("Pressed Left!");
bComp.moveLeft();
}
if(keyCode == 39)
{
System.out.println("Pressed Right!");
bComp.moveRight();
}
if(keyCode == 40)
{
System.out.println("Pressed Down!");
bComp.moveDown();
}
}
/** Handle the key released event from the text field. */
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == 38)
{
System.out.println("Released Up!");
bComp.stopY();
}
if(keyCode == 37)
{
System.out.println("Released Left!");
bComp.stopX();
}
if(keyCode == 39)
{
System.out.println("Released Right!");
bComp.stopX();
}
if(keyCode == 40)
{
System.out.println("Pressed Down!");
bComp.stopY();
}
}
public void keyTyped(KeyEvent e) {
}
}
BallComponent.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class BallComponent extends JComponent
{
int xSpeed;
int ySpeed;
int x;
int y;
public BallComponent(int x, int y)
{
super();
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Ellipse2D.Double ball = new Ellipse2D.Double(x-10,y-10,10,10);
g2.setColor(Color.RED);
g2.fill(ball);
g2.draw(ball);
}
public void moveLeft()
{
xSpeed=-1;
}
public void moveRight()
{
xSpeed=1;
}
public void moveUp()
{
ySpeed=-1;
}
public void moveDown()
{
ySpeed=1;
}
public void tick()
{
x=x+xSpeed;
y=y+ySpeed;
repaint();
}
public void stopY()
{
ySpeed=0;
}
public void stopX()
{
xSpeed=0;
}
}
WallComponent.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class WallComponent extends JComponent
{
int x;
int y;
public WallComponent(int x, int y)
{
super();
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Rectangle wall = new Rectangle(x-40,y-40,40,40);
g2.setColor(Color.YELLOW);
g2.fill(wall);
g2.draw(wall);
}
public void checkOverlap(BallComponent bc){
if (this.contains(bc.getLocation())){
bc.stopY();
bc.stopX();
}
}
}
All Swing components have a concept of "bounds". This is a rectangular area within which they are "drawn".
If you are controlling the size and position correctly, you should be able to use the contains method of the Rectangle which is returned from calling Component#getBounds
So you checkOverlap method could look like...
public void checkOverlap(BallComponent bc){
if (getBounds().intersects(bc.getBounds())){
bc.stopY();
bc.stopX();
}
}
You will also want to make sure that you are calling super.paintComponent before performing any custom painting, espeically when using components that extend from JComponent. This will ensure that the Graphics context is prepared for painting correctly...
Updated
There's a cascade of issues. Basically, instead of positing the components within the parent container yourself (which is how I thought you had done it), you've laid each component out to fill the parent container and only "painted" the objects...This makes life more difficult
Instead, if you are going to use components, I would use a null layout (or even possibly use a JLayeredPane as the parent container).
I would then change the physical position of the components, for example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
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.geom.Ellipse2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGame {
public static void main(String[] args) {
new TestGame();
}
public TestGame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(null);
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Move the Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WallComponent wc1 = new WallComponent(400, 400);
final BallComponent bc = new BallComponent(400, 300);
panel.add(wc1);
panel.add(bc);
frame.add(panel);
KeyboardController kc = new KeyboardController(bc);
frame.addKeyListener(kc);
frame.setVisible(true);
class AnimationListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
bc.tick();
wc1.checkOverlap(bc);
}
}
ActionListener aListener = new AnimationListener();
final Timer timer = new Timer(1, aListener);
timer.start();
}
});
}
public class KeyboardController implements KeyListener {
BallComponent bComp;
public KeyboardController(BallComponent t) {
bComp = t;
}
/**
* Handle the key pressed event from the text field.
*/
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) {
System.out.println("Pressed Up!");
bComp.moveUp();
}
if (keyCode == 37) {
System.out.println("Pressed Left!");
bComp.moveLeft();
}
if (keyCode == 39) {
System.out.println("Pressed Right!");
bComp.moveRight();
}
if (keyCode == 40) {
System.out.println("Pressed Down!");
bComp.moveDown();
}
}
/**
* Handle the key released event from the text field.
*/
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) {
System.out.println("Released Up!");
bComp.stopY();
}
if (keyCode == 37) {
System.out.println("Released Left!");
bComp.stopX();
}
if (keyCode == 39) {
System.out.println("Released Right!");
bComp.stopX();
}
if (keyCode == 40) {
System.out.println("Pressed Down!");
bComp.stopY();
}
}
public void keyTyped(KeyEvent e) {
}
}
public class BallComponent extends JComponent {
int xSpeed;
int ySpeed;
public BallComponent(int x, int y) {
super();
setBounds(x, y, 10, 10);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double ball = new Ellipse2D.Double(0, 0, 9, 9);
g2.setColor(Color.RED);
g2.fill(ball);
g2.draw(ball);
}
public void moveLeft() {
xSpeed = -1;
}
public void moveRight() {
xSpeed = 1;
}
public void moveUp() {
ySpeed = -1;
}
public void moveDown() {
ySpeed = 1;
}
public void tick() {
int x = getX() + xSpeed;
int y = getY() + ySpeed;
setLocation(x, y);
repaint();
}
public void stopY() {
ySpeed = 0;
}
public void stopX() {
xSpeed = 0;
}
}
public class WallComponent extends JComponent {
public WallComponent(int x, int y) {
super();
setBounds(x, y, 40, 40);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle wall = new Rectangle(0, 0, 40, 40);
g2.setColor(Color.YELLOW);
g2.fill(wall);
g2.draw(wall);
}
public void checkOverlap(BallComponent bc) {
System.out.println(" me: " + getBounds());
System.out.println("you: " + bc.getBounds());
if (getBounds().intersects(bc.getBounds())) {
bc.stopY();
bc.stopX();
}
}
}
}
Now, you could use "painted" objects, but in that case I would have a virtual concept of a Ball and Wall which you could paint within a single component. These objects would need to provide information about there position and size, which you could, again, check using Rectangle#intersects...
Generally, just try to make a "bounding box" for your objects. This will be the invisible rectangle that goes with the object. Then just do
if(rectangle1.intersects(rectangle2)) ...
The intersects method only works with rectangles, and that's why you need a bounding box.