I'm trying to make a Brick Breaker game where the ball which is initially on the paddle(referred to as BAR in the code below) is launched with a speed(approx 100) in some random direction, if it hits any brick on the screen the brick disappears and the ball changes direction accordingly.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.event.KeyEvent;
import java.awt.event.*;
public class Brick_Breaker extends Canvas implements KeyListener{
int BRICK_WIDTH=60,BRICK_HEIGHT=30,X=0,Y=0;
int BAR_X = 390,BAR_Y=560,BAR_WIDTH=120,BAR_HEIGHT=20,BAR_DX=10;
int BALL_X=440,BALL_Y=540,BALL_SIZE=20,BALL_DX=0,BALL_DY=0;
int LEFT_WALL=100,RIGHT_WALL=800,TOP_WALL=10;
boolean GAME_STATE=false;
int BAR_STATE=0;
static int[][] y = new int[10][5];
static int[][] x = new int[10][5];
static int[][] status = new int[10][5];
static Canvas canvas;
static JFrame frame;
#Override
public void keyReleased(KeyEvent ke){}
#Override
public void keyTyped(KeyEvent ke){}
public void STaRT(){
frame = new JFrame("My Drawing");
frame.addKeyListener(this);
canvas = new Brick_Breaker();
canvas.setSize(900, 600);
frame.add(canvas);
frame.pack();
frame.setVisible(true);
}
#Override
public void update(Graphics g){
BALL_X += BALL_DX;
BALL_Y += BALL_DY;
for(int i=0;i<10;i++){
for(int j=0;j<5;j++){
if(BALL_X>x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y<=y[i][j]+BAR_HEIGHT+BALL_SIZE && BALL_Y>y[i][j]&&BALL_DY<0){
BALL_DY=-BALL_DY;
status[i][j]-=1;
}else if(BALL_X>x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j]-BALL_SIZE && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY>0){
BALL_DY=-BALL_DY;
status[i][j]-=1;
}else if(BALL_X+BALL_SIZE>=x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j] && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY<0){
BALL_DX=-BALL_DX;
status[i][j]-=1;
}else if(BALL_X>x[i][j]&&BALL_X-BALL_SIZE<=(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j] && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY<0){
BALL_DX=-BALL_DX;
status[i][j]-=1;
}else if(BALL_X-BALL_SIZE<LEFT_WALL||BALL_X+BALL_SIZE>RIGHT_WALL){
BALL_DX=-BALL_DX;
}else if(BALL_Y-BALL_SIZE<TOP_WALL){
BALL_DY=-BALL_DY;
}
}
}
BAR_X = BAR_X +BAR_STATE*BAR_DX;
repaint();
}
public static void main(String[] args) {
Brick_Breaker bb = new Brick_Breaker();
bb.STaRT();
for(int i=0;i<10;i++){
for(int j=0;j<5;j++){
x[i][j] = 300+60*j;
y[i][j] = 50+30*i;
status[i][j] = 1;
}
}
}
#Override
public void keyPressed(KeyEvent ke){
if(!GAME_STATE){
BALL_DX = (int)(100*Math.random());
BALL_DY = (int)(Math.sqrt(100*100-BALL_DX*BALL_DX));
GAME_STATE = true;
}else if(ke.getKeyCode() == KeyEvent.VK_LEFT){
BAR_STATE=-1;
}else if(ke.getKeyCode()==KeyEvent.VK_RIGHT){
BAR_STATE=1;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.white);
g.drawLine(LEFT_WALL,600, LEFT_WALL, TOP_WALL);
g.drawLine(RIGHT_WALL, 600, RIGHT_WALL, TOP_WALL);
g.drawLine(LEFT_WALL,TOP_WALL,RIGHT_WALL,TOP_WALL);
g.fillRect(BAR_X,BAR_Y,BAR_WIDTH,BAR_HEIGHT);
g.setColor(Color.red);
g.fillOval(BALL_X, BALL_Y, BALL_SIZE, BALL_SIZE);
for(int i=0;i<10;i++){
for(int j=0;j<5;j++){
if(status[i][j]>0){
X = x[i][j];Y=y[i][j];
g.setColor(Color.white);
g.fillRect(X, Y, BRICK_WIDTH, BRICK_HEIGHT);
g.setColor(Color.red);
g.fillRect(X+3, Y+3, BRICK_WIDTH-6, BRICK_HEIGHT-6);
}
}
}
setBackground(Color.black);
}
}
Here the update function doesn't seem to update at all.
I'm not really sure on how the method works as well.
Any help would be appreciated
Canvas is a pretty low level component and one which I'd only consider using if I needed to use a BufferStrategy.
update is called as part of the paint phase and because you've overridden it without calling it's super implementation, you broke the paint workflow.
AWT and Swing generally employ a passive rendering system, this means that updates only occur when the system decides it needs to happen, so overriding update the way you have doesn't really make sense and isn't going to help you.
A better place to start is with a JPanel, the main reason is because it's double buffered and saves you hassles of trying to figure out how to eliminate flickering.
A good place to start is Performing Custom Painting and Painting in AWT and Swing to gain a better understanding of how painting works (and how you should work with it).
KeyListener is also a poor choice for input monitoring, seriously, just do some searching on SO for all the reasons why.
A better, and generally less problematic approach is to use key bindings as well.
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.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
int BRICK_WIDTH = 60, BRICK_HEIGHT = 30, X = 0, Y = 0;
int BAR_X = 390, BAR_Y = 560, BAR_WIDTH = 120, BAR_HEIGHT = 20, BAR_DX = 1;
int BALL_X = 440, BALL_Y = 540, BALL_SIZE = 20, BALL_DX = 0, BALL_DY = 0;
int LEFT_WALL = 100, RIGHT_WALL = 800, TOP_WALL = 10;
boolean GAME_STATE = false;
int BAR_STATE = 0;
int[][] y = new int[10][5];
int[][] x = new int[10][5];
int[][] status = new int[10][5];
private Timer timer;
public TestPane() {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
x[i][j] = 300 + 60 * j;
y[i][j] = 50 + 30 * i;
status[i][j] = 1;
}
}
BALL_DX = 0; //(int) (100 * Math.random());
BALL_DY = -1;//(int) (Math.sqrt(100 * 100 - BALL_DX * BALL_DX));
setBackground(Color.BLACK);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
ActionMap am = getActionMap();
am.put("left", new KeyAction(this, -1));
am.put("right", new KeyAction(this, 1));
}
#Override
public void addNotify() {
super.addNotify(); //To change body of generated methods, choose Tools | Templates.
if (timer == null) {
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tick();
}
});
timer.start();
}
}
#Override
public void removeNotify() {
super.removeNotify();
if (timer != null) {
timer.stop();
timer = null;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(900, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.white);
g2d.drawLine(LEFT_WALL, 600, LEFT_WALL, TOP_WALL);
g2d.drawLine(RIGHT_WALL, 600, RIGHT_WALL, TOP_WALL);
g2d.drawLine(LEFT_WALL, TOP_WALL, RIGHT_WALL, TOP_WALL);
g2d.fillRect(BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT);
g2d.setColor(Color.red);
g2d.fillOval(BALL_X, BALL_Y, BALL_SIZE, BALL_SIZE);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
if (status[i][j] > 0) {
X = x[i][j];
Y = y[i][j];
g2d.setColor(Color.white);
g2d.fillRect(X, Y, BRICK_WIDTH, BRICK_HEIGHT);
g2d.setColor(Color.red);
g2d.fillRect(X + 3, Y + 3, BRICK_WIDTH - 6, BRICK_HEIGHT - 6);
}
}
}
g2d.dispose();
}
protected void tick() {
BALL_X += BALL_DX;
BALL_Y += BALL_DY;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
if (BALL_X > x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y <= y[i][j] + BAR_HEIGHT + BALL_SIZE && BALL_Y > y[i][j] && BALL_DY < 0) {
BALL_DY = -BALL_DY;
status[i][j] -= 1;
} else if (BALL_X > x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] - BALL_SIZE && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY > 0) {
BALL_DY = -BALL_DY;
status[i][j] -= 1;
} else if (BALL_X + BALL_SIZE >= x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY < 0) {
BALL_DX = -BALL_DX;
status[i][j] -= 1;
} else if (BALL_X > x[i][j] && BALL_X - BALL_SIZE <= (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY < 0) {
BALL_DX = -BALL_DX;
status[i][j] -= 1;
} else if (BALL_X - BALL_SIZE < LEFT_WALL || BALL_X + BALL_SIZE > RIGHT_WALL) {
BALL_DX = -BALL_DX;
} else if (BALL_Y - BALL_SIZE < TOP_WALL) {
BALL_DY = -BALL_DY;
}
}
}
BAR_X = BAR_X + BAR_STATE * BAR_DX;
repaint();
}
class KeyAction extends AbstractAction {
private TestPane source;
private int delta;
public KeyAction(TestPane source, int delta) {
this.source = source;
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
source.BAR_STATE = delta;
}
}
}
}
I've messed with delta values, because the ball and bar disappeared real quick
Related
I tried to make a tetris game. But my jframe GUI is blinking continuosuly. But when i comment the below line in the code, its not blinking. Could someone please help?
map.draw((Graphics2D) g);
JDK Version - 1.8
NetBeans - 7.4
Code file links are below.
package GUI;
import Maps.MapGenerator;
import java.awt.Color;
import java.awt.Font;
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 javax.swing.Timer;
public class BrickBreaker extends javax.swing.JFrame implements KeyListener, ActionListener {
private MapGenerator map;
public BrickBreaker() {
initComponents();
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
this.setTitle("Test Tetris");
//Map
map = new MapGenerator(3, 7);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
time = new Timer(delay, this);
time.start();
}
public void paint(Graphics g) {
//background
g.setColor(Color.black);
g.fillRect(1, 1, 692, 592);
//map
map.draw((Graphics2D) g);
//score
g.setColor(Color.white);
g.setFont(new Font("serif", Font.BOLD, 25));
g.drawString("" + score, 560, 30);
//border
g.setColor(Color.yellow);
g.fillRect(0, 0, 3, 592);
g.fillRect(0, 0, 692, 3);
g.fillRect(691, 0, 3, 592);
//paddle
g.setColor(Color.green);
g.fillRect(playerPosX, 550, 100, 8);
//ball
g.setColor(Color.red);
g.fillOval(ballPosX, ballPosY, 20, 20);
g.dispose();
}
private boolean play = false;
private int score = 0;
private int totalBricks = 21;
private Timer time;
private int delay = 8;
private int playerPosX = 310;
private int ballPosX = 210;
private int ballPosY = 350;
private int ballXDir = -1;
private int ballYDir = -2;
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new java.awt.Dimension(700, 600));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 525, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 403, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new BrickBreaker().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
try {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
if (playerPosX >= 600) {
playerPosX = 600;
} else {
moveRight();
}
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
if (playerPosX < 10) {
playerPosX = 10;
} else {
moveLeft();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void moveRight() {
play = true;
playerPosX += 20;
}
public void moveLeft() {
play = true;
playerPosX -= 20;
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void actionPerformed(ActionEvent e) {
time.start();
if (play) {
if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
ballYDir = -ballYDir;
}
A:
for (int i = 0; i < map.map.length; i++) {
for (int j = 0; j < map.map[0].length; j++) {
if (map.map[i][j] > 0) {
int brickX = j * map.brickWidth + 60;
int brickY = i * map.brickHeight + 50;
int brickWidht = map.brickWidth;
int brickHeight = map.brickHeight;
Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
Rectangle brickRect = rect;
if (ballRect.intersects(brickRect)) {
map.setBrickValue(0, i, j);
totalBricks--;
score += 2;
if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
ballXDir = -ballXDir;
} else {
ballYDir = -ballYDir;
}
break A;
}
}
}
}
ballPosX += ballXDir;
ballPosY += ballYDir;
if (ballPosX < 0) {
ballXDir = -ballXDir;
}
if (ballPosY < 0) {
ballYDir = -ballYDir;
}
if (ballPosX > 670) {
ballXDir = -ballXDir;
}
}
repaint();
}
}
Map generator
package Maps;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class MapGenerator {
public int map[][];
public int brickWidth;
public int brickHeight;
public MapGenerator(int row, int col) {
map = new int[row][col];
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = 1;
}
}
brickWidth = 240 / row;
brickHeight = 150 / col;
}
public void draw(Graphics2D g) {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] > 0) {
g.setColor(Color.black);
g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
g.setStroke(new BasicStroke(3));
g.setColor(Color.white);
g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
}
}
}
}
public void setBrickValue(int value, int row, int col) {
map[row][col] = value;
}
}
Top level containers, like JFrame are not double buffered, which is causing the flickering.
This is just one of many reasons why you should not override paint of top level containers. Instead, start with a JPanel and override it's paintComponent, Swing components, by default, are double buffered automatically for you.
Have a look at Performing Custom Painting and Painting in AWT and Swing for more details about how painting works in Swing.
A more suitable solution might start looking something like this...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private boolean play = false;
private int score = 0;
private int totalBricks = 21;
private Timer timer;
private int delay = 8;
private int playerPosX = 310;
private int ballPosX = 210;
private int ballPosY = 350;
private int ballXDir = -1;
private int ballYDir = -2;
private MapGenerator map;
public TestPane() {
setBackground(Color.BLACK);
map = new MapGenerator(3, 7);
timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (play) {
if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
ballYDir = -ballYDir;
}
for (int i = 0; i < map.map.length; i++) {
for (int j = 0; j < map.map[0].length; j++) {
if (map.map[i][j] > 0) {
int brickX = j * map.brickWidth + 60;
int brickY = i * map.brickHeight + 50;
int brickWidht = map.brickWidth;
int brickHeight = map.brickHeight;
Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
Rectangle brickRect = rect;
if (ballRect.intersects(brickRect)) {
map.setBrickValue(0, i, j);
totalBricks--;
score += 2;
if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
ballXDir = -ballXDir;
} else {
ballYDir = -ballYDir;
}
}
}
}
}
ballPosX += ballXDir;
ballPosY += ballYDir;
if (ballPosX < 0) {
ballXDir = -ballXDir;
}
if (ballPosY < 0) {
ballYDir = -ballYDir;
}
if (ballPosX > 670) {
ballXDir = -ballXDir;
}
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 600);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
//map
map.draw((Graphics2D) g);
//score
g.setColor(Color.white);
g.setFont(new Font("serif", Font.BOLD, 25));
g.drawString("" + score, 560, 30);
//border
g.setColor(Color.yellow);
g.fillRect(0, 0, 3, 592);
g.fillRect(0, 0, 692, 3);
g.fillRect(691, 0, 3, 592);
//paddle
g.setColor(Color.green);
g.fillRect(playerPosX, 550, 100, 8);
//ball
g.setColor(Color.red);
g.fillOval(ballPosX, ballPosY, 20, 20);
g2d.dispose();
}
}
public class MapGenerator {
public int map[][];
public int brickWidth;
public int brickHeight;
public MapGenerator(int row, int col) {
map = new int[row][col];
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = 1;
}
}
brickWidth = 240 / row;
brickHeight = 150 / col;
}
public void draw(Graphics2D g) {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] > 0) {
g.setColor(Color.black);
g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
g.setStroke(new BasicStroke(3));
g.setColor(Color.white);
g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
}
}
}
}
public void setBrickValue(int value, int row, int col) {
map[row][col] = value;
}
}
}
Observations...
This...
A:
for (int i = 0; i < map.map.length; i++) {
//...
//...
break A;
is a pretty good sign of a bad design. There should be no need for a "goto" or "label" based jumped in good code.
You have to think of you "main-loop" in a very linear set of operations, update the state, check for collisions, update the UI. Keep it simple, keep it quick
You will also find that the Key Bindings API will solve all the inherit issues of KeyListener
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
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.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;
public class FinalFlappy implements ActionListener, MouseListener,
KeyListener
{
public static FinalFlappy finalFlappy;
public final int WIDTH = 800, HEIGHT = 800;
public FinalFlappyRend renderer;
public Rectangle bee;
public ArrayList<Rectangle> rect_column;
public int push, yMotion, score;
public boolean gameOver, started;
public Random rand;
public FinalFlappy()
{
JFrame jframe = new JFrame();
Timer timer = new Timer(16, this);
renderer = new FinalFlappyRend();
rand = new Random();
jframe.add(renderer);
jframe.setTitle("Flappy Bee");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.addMouseListener(this);
jframe.addKeyListener(this);
jframe.setResizable(false);
jframe.setVisible(true);
bee = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 40, 40);
rect_column = new ArrayList<Rectangle>();
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
timer.start();
}
public void addColumn(boolean start)
{
int space = 300;
int width = 60;
int height = 50 + rand.nextInt(300);
if (start)
{
rect_column.add(new Rectangle(WIDTH + width + rect_column.size() * 300, HEIGHT - height - 120, width, height));
rect_column.add(new Rectangle(WIDTH + width + (rect_column.size() - 1) * 300, 0, width, HEIGHT - height - space));
}
else
{
rect_column.add(new Rectangle(rect_column.get(rect_column.size() - 1).x + 600, HEIGHT - height - 120, width, height));
rect_column.add(new Rectangle(rect_column.get(rect_column.size() - 1).x, 0, width, HEIGHT - height - space));
}
}
public void jump()
{
if (gameOver)
{
bee = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 40, 40);
rect_column.clear();
yMotion = 0;
score = 0;
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
gameOver = false;
}
if (!started)
{
started = true;
}
else if (!gameOver)
{
if (yMotion > 0)
{
yMotion = 0;
}
yMotion -= 10;
}
}
#Override
public void actionPerformed(ActionEvent e)
{
int speed = 10;
push++;
if (started)
{
for (int i = 0; i < rect_column.size(); i++)
{
Rectangle column = rect_column.get(i);
column.x -= speed;
}
if (push % 2 == 0 && yMotion < 15)
{
yMotion += 2;
}
for (int i = 0; i < rect_column.size(); i++)
{
Rectangle column = rect_column.get(i);
if (column.x + column.width < 0)
{
rect_column.remove(column);
if (column.y == 0)
{
addColumn(false);
}
}
}
bee.y += yMotion;
for (Rectangle column : rect_column)
{
if (column.y == 0 && bee.x + bee.width / 2 > column.x + column.width / 2 - 10 && bee.x + bee.width / 2 < column.x + column.width / 2 + 10)
{
score++;
}
if (column.intersects(bee))
{
gameOver = true;
if (bee.x <= column.x)
{
bee.x = column.x - bee.width;
}
else
{
if (column.y != 0)
{
bee.y = column.y - bee.height;
}
else if (bee.y < column.height)
{
bee.y = column.height;
}
}
}
}
if (bee.y > HEIGHT - 120 || bee.y < 0)
{
gameOver = true;
}
if (bee.y + yMotion >= HEIGHT - 120)
{
bee.y = HEIGHT - 120 - bee.height;
gameOver = true;
}
}
renderer.repaint();
}
public void paintColumn(Graphics g, Rectangle column)
{
g.setColor(Color.green.darker());
g.fillRect(column.x, column.y, column.width, column.height);
g.fillRect(column.x-20, column.y+column.height-10, column.width+40, 10);
g.fillRect(column.x-20, column.y-10, column.width+40, 10);
}
public void repaint(Graphics g)
{
g.setColor(new Color(153,204,255));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(new Color(255,255,255));
g.fillOval(50, 50, 100, 100);
g.setColor(Color.YELLOW);
g.fillOval(600, 50, 100, 100);
g.setColor(new Color(156,93,82));
g.fillRect(0, HEIGHT - 120, WIDTH, 120);
g.setColor(new Color(128,255,0));
g.fillRect(0, HEIGHT - 120, WIDTH, 20);
g.setColor(Color.YELLOW);
g.fillRect(bee.x, bee.y, bee.width, bee.height);
for (Rectangle column : rect_column)
{
paintColumn(g, column);
}
g.setColor(Color.white);
g.setFont(new Font("Times New Roman", 1, 100));
if (!started)
{
g.drawString("Push A to start", 100, HEIGHT / 2 - 50);
}
if (gameOver)
{
g.drawString("Game Over", 100, HEIGHT / 2 - 50);
g.drawString("A to replay", 100, HEIGHT / 2 + 90);
}
}
public static void main(String[] args)
{
finalFlappy = new FinalFlappy();
}
#Override
public void mouseClicked(MouseEvent e)
{
jump();
}
#Override
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_A)
{
jump();
}
}
#Override
public void mousePressed(MouseEvent e)
{
}
#Override
public void mouseReleased(MouseEvent e)
{
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
}
import java.awt.Graphics;
import javax.swing.JPanel;
public class FinalFlappyRend extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
FinalFlappy.finalFlappy.repaint(g);
}
}
I am working on making a Flappy bird game and I am stuck on how to make and display a timer that updates every second onto the screen
How do I make it start as the game starts and end as the game over pops up?
There are a few ways you might achieve what you're asking. The important thing to remember is, any solution is going to have a degree of drift, meaning that it's unlikely to absolutely accurate, the degree of drift will depend on a lot of factors, so just beware.
You could use a Swing Timer
It's among the safest means for updating the UI on a regular basis, it's also useful if your main loop is already based on a Swing Timer
See How to Use Swing Timers for more details
You could...
Maintain some kind of counter within in your main loop. This assumes that you're using a separate thread (although you can do the same thing with a Swing Timer) and are simply looping at some consistent rate
long tick = System.nanoTime();
long lastUpdate = -1;
while (true) {
long diff = System.nanoTime() - tick;
long seconds = TimeUnit.SECONDS.convert(diff, TimeUnit.NANOSECONDS);
if (seconds != lastUpdate) {
lastUpdate = seconds;
updateTimerLabel(seconds);
}
Thread.sleep(100);
}
This basically runs a while-loop, which calculates the difference between a given point in time (tick) and now, if it's a "second" difference, it then updates the UI (rather than constantly updating the UI with the same value)
The updateTimerLabel method basically updates the label with the specified time, but does so in a manner which is thread safe
protected void updateTimerLabel(long seconds) {
if (EventQueue.isDispatchThread()) {
timerLabel.setText(Long.toString(seconds));
} else {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
updateTimerLabel(seconds);
}
});
}
}
To make and display a timer that updates every second, Put this code in your main class:
private Timer timer = new Timer();
private JLabel timeLabel = new JLabel(" ", JLabel.CENTER);
timer.schedule(new UpdateUITask(), 0, 1000);
private class UpdateUITask extends TimerTask {
int nSeconds = 0;
#Override
public void run() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
timeLabel.setText(String.valueOf(nSeconds++));
}
});
}
}
I have been working on a simple Java game and have done so successfully using shapes, but the next big step is to do so using images. I was wondering whether there was a method where I could simply place an image over a shape such as a rectangle, which would make the process much easier and doesn't require me to re-write most of my code.
Here's the two classes of my game for reference:
The first class named "Flappy Bird"
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
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.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.Timer;
public class FlappyBird implements ActionListener, MouseListener, KeyListener {
public static FlappyBird flappyBird;
public final int WIDTH = 800, HEIGHT = 800;
public Renderer renderer;
public Rectangle bird;
public ArrayList<Rectangle> columns;
public int ticks, yMotion, score;
public boolean gameOver, started;
public Random rand;
public FlappyBird() {
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
rand = new Random();
jframe.add(renderer);
jframe.setTitle("Flappy Bird");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.addMouseListener(this);
jframe.addKeyListener(this);
jframe.setResizable(false);
jframe.setVisible(true);
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
columns = new ArrayList<Rectangle>();
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
timer.start();
}
public void addColumn(boolean start) {
int space = 300;
int width = 100;
int height = 50 + rand.nextInt(300);
if (start) {
columns.add(new Rectangle(WIDTH + width + columns.size() * 300, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(WIDTH + width + (columns.size() - 1) * 300, 0, width, HEIGHT - height - space));
} else {
columns.add(new Rectangle(columns.get(columns.size() - 1).x + 600, HEIGHT - height - 120, width, height));
columns.add(new Rectangle(columns.get(columns.size() - 1).x, 0, width, HEIGHT - height - space));
}
}
public void paintColumn(Graphics g, Rectangle column) {
g.setColor(Color.green.darker());
g.fillRect(column.x, column.y, column.width, column.height);
}
public void jump() {
if (gameOver) {
bird = new Rectangle(WIDTH / 2 - 10, HEIGHT / 2 - 10, 20, 20);
columns.clear();
yMotion = 0;
score = 0;
addColumn(true);
addColumn(true);
addColumn(true);
addColumn(true);
gameOver = false;
}
if (!started)
started = true;
else if (!gameOver) {
if (yMotion > 0)
yMotion = 0;
yMotion -= 10;
}
}
#Override
public void actionPerformed(ActionEvent e) {
int speed = 10;
ticks++;
if (started) {
for (int i = 0; i < columns.size(); i++) {
Rectangle column = columns.get(i);
column.x -= speed;
}
if (ticks % 2 == 0 && yMotion < 15)
yMotion += 2;
for (int i = 0; i < columns.size(); i++) {
Rectangle column = columns.get(i);
if (column.x + column.width < 0) {
columns.remove(column);
if (column.y == 0)
addColumn(false);
}
}
bird.y += yMotion;
for (Rectangle column : columns) {
if (column.y == 0 && bird.x + bird.width / 2 > column.x + column.width / 2 - 10 && bird.x + bird.width / 2 < column.x + column.width / 2 + 10) {
score++;
}
if (column.intersects(bird)) {
gameOver = true;
if (bird.x <= column.x)
bird.x = column.x - bird.width;
else
if (column.y != 0)
bird.y = column.y - bird.height;
else if (bird.y < column.height)
bird.y = column.height;
}
}
if (bird.y > HEIGHT - 120 || bird.y < 0)
gameOver = true;
if (bird.y + yMotion >= HEIGHT - 120) {
bird.y = HEIGHT - 120 - bird.height;
gameOver = true;
}
}
renderer.repaint();
}
public void repaint(Graphics g) {
g.setColor(Color.cyan);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.orange);
g.fillRect(0, HEIGHT - 120, WIDTH, 120);
g.setColor(Color.green);
g.fillRect(0, HEIGHT - 120, WIDTH, 20);
g.setColor(Color.red);
g.fillRect(bird.x, bird.y, bird.width, bird.height);
for (Rectangle column : columns)
paintColumn(g, column);
g.setColor(Color.white);
g.setFont(new Font("Arial", 1, 100));
if (!started)
g.drawString("Click to start!", 75, HEIGHT / 2 - 50);
if (gameOver)
g.drawString("Game Over!", 100, HEIGHT / 2 - 50);
if (!gameOver && started)
g.drawString(String.valueOf(score), WIDTH / 2 - 25, 100);
}
public static void main(String[] args) {
flappyBird = new FlappyBird();
}
#Override
public void mouseClicked(MouseEvent e) {
jump();
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE)
jump();
}
#Override
public void mousePressed(MouseEvent e){
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e){
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
}
The second class named "Renderer":
import java.awt.Graphics;
import javax.swing.JPanel;
public class Renderer extends JPanel {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
FlappyBird.flappyBird.repaint(g);
}
}
I know this is a massive ask and I would like to give a HUGE thank you to everyone who replies and to the wonderful community here :-)
I made 2 objects that moves with keylisteners. They move correctly, but in the console I receive this error every time I press a button:
Exception in thread "AWT-EventQueue-0"
java.lang.UnsupportedOperationException: Not supported yet. at
CatchMe.CatchMe.keyTyped(CatchMe.java:197)
My code is as follows:
package CatchMe;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class CatchMe extends JFrame implements ActionListener, KeyListener {
private Image dbImage;
private Graphics dbg;
int x = 200, y = 300;
int velX, velY;
int velX1, velY1;
int ScoreB1 = 0;
int ScoreR1 = 0;
Timer tm = new Timer(5, this);
long startTime = System.currentTimeMillis();
long onGoing;
String onG;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) screenSize.getWidth();
int height = (int) screenSize.getHeight();
int recX = (width + 100) / 2, recY = (height + 100) / 2;
public CatchMe() {
setSize(width, height);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
tm.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
Rectangle r1 = new Rectangle(recX, recY, 25, 25);
Rectangle r2 = new Rectangle(x, y, 25, 25);
g.setColor(Color.BLUE);
g.fillRect(r1.x, r1.y, r1.width, r1.height);
g.setColor(Color.RED);
g.fillRect(r2.x, r2.y, r2.width, r2.height);
g.setColor(Color.BLACK);
g.fillRect(0, 20, 100, 50);
g.fillRect(100, 20, 100, 50);
g.fillRect(200, 20, 50, 50);
g.setColor(Color.YELLOW);
g.drawString("Score of Blue", 5, 40);
String ScoreB = ScoreB1 + "";
g.drawString(ScoreB, 5, 55);
g.drawString("Score of Red", 110, 40);
String ScoreR = ScoreR1 + "";
g.drawString(ScoreR, 110, 55);
g.drawLine(95, 20, 95, 69);
g.drawLine(200, 20, 200, 69);
g.setColor(Color.RED);
onGoing = (System.currentTimeMillis() - startTime) / 1000;
onG = onGoing + "";
g.setColor(Color.YELLOW);
g.drawString(onG, 220, 50);
System.out.println(onGoing);
if (r1.intersects(r2)) {
if (onGoing <= 60 || (onGoing >= 120 && onGoing < 180)) {
g.setColor(Color.BLUE);
g.drawString("Blue Caught You!", 175, 90);
ScoreB1++;
} else if (onGoing >= 240) {
if (ScoreB1 > ScoreR1) {
Font font = new Font("Jokerman", Font.PLAIN, 50);
g.setColor(Color.BLUE);
g.drawString("BLUE WINS", 600, 400);
} else if (ScoreB1 < ScoreR1) {
Font font = new Font("Jokerman", Font.PLAIN, 50);
g.setColor(Color.RED);
g.drawString("RED WINS", 600, 400);
}
} else {
g.setColor(Color.RED);
g.drawString("Red Caught You!", 175, 90);
ScoreR1++;
}
if (onGoing == 245) {
System.exit(245);
}
repaint();
}
}
#Override
public void actionPerformed(ActionEvent e) {
x = x + velX;
y = y + velY;
recY += velY1;
recX += velX1;
if (x < 0) {
velX = 0;
x = 0;
}
if (x > width - 50) {
velX = 0;
x = width - 50;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (y > height - 40) {
velY = 0;
y = height - 40;
}
//Second square
if (recX < 0) {
velX1 = 0;
recX = 0;
}
if (recX > width - 50) {
velX1 = 0;
recX = width - 50;
}
if (recY < 0) {
velY1 = 0;
recY = 0;
}
if (recY > height - 40) {
velY1 = 0;
recY = height - 40;
}
repaint();
}
#Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_LEFT) {
velX = -5;
velY = 0;
}
if (code == KeyEvent.VK_UP) {
velX = 0;
velY = -5;
}
if (code == KeyEvent.VK_RIGHT) {
velX = 5;
velY = 0;
}
if (code == KeyEvent.VK_DOWN) {
velX = 0;
velY = 5;
}
//Second Rect
if (code == KeyEvent.VK_A) {
velX1 = -5;
velY1 = 0;
}
if (code == KeyEvent.VK_W) {
velX1 = 0;
velY1 = -5;
}
if (code == KeyEvent.VK_D) {
velX1 = 5;
velY1 = 0;
}
if (code == KeyEvent.VK_S) {
velX1 = 0;
velY1 = 5;
}
}
#Override
public void keyReleased(KeyEvent e) {
velX = 0;
velY = 0;
velX1 = 0;
velY1 = 0;
}
public static void main(String[] args) {
CatchMe main = new CatchMe();
}
#Override
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
The keyTyped method throws an UnsupportedOperationException because you implemented it this way(or it was automatically generated this way):
#Override
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
Whenever a key is typed, this method is called, so it throws an exception.
To fix it, you need to change the body of this method. If you don't want it to do anything, just leave its body empty:
#Override
public void keyTyped(KeyEvent e) {
}
If you want to do something, you should implement this method according to the desired behavior. For example, this implementation prints a message every time a key is typed:
#Override
public void keyTyped(KeyEvent e) {
System.out.println("A key was typed");
}
#Override
public void keyTyped(KeyEvent e) {
}
Will fix it, you were manually throwing exception when keyTyped is called.
the following code draws a square with two smaller square rotating inside it. whenever you click an arrow on the keyboard, the whole system will move in that direction. however i'm having some problems with the image tearing and at times skipping (its small but still there). i was wondering if anybody knew how i could fix these issues w/o massively altering the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static java.awt.Color.*;
public class GUI extends JPanel implements ActionListener, KeyListener
{
int x, y, x1, y1, x2, y2, changeX, changeY, changeX2, changeY2;
JFrame frame;
Runtime r;
public static void main(String[] args)
{
new GUI();
}
public GUI()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e)
{
e.printStackTrace();
}
setSize(1020,770);
setBackground(WHITE);
setOpaque(true);
setVisible(true);
x = 0;
y = 0;
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
changeX=1;
changeY=0;
changeX2=1;
changeY2=0;
r = Runtime.getRuntime();
frame = new JFrame();
frame.setSize(1020,819);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(createMenuBar());
frame.validate();
frame.setBackground(WHITE);
frame.addKeyListener(this);
frame.setTitle("GUI");
frame.setContentPane(this);
frame.setVisible(true);
frame.createBufferStrategy(2);
Timer t = new Timer(100,this);
t.setActionCommand("Draw");
t.start();
repaint();
}
public JMenuBar createMenuBar()
{
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem save = new JMenuItem("Save");
save.setMnemonic(KeyEvent.VK_S);
save.setContentAreaFilled(false);
save.setOpaque(false);
save.addActionListener(this);
JMenuItem load = new JMenuItem("Load");
load.setMnemonic(KeyEvent.VK_L);
load.setContentAreaFilled(false);
load.setOpaque(false);
load.addActionListener(this);
JMenuItem quit = new JMenuItem("Quit");
quit.setMnemonic(KeyEvent.VK_Q);
quit.setContentAreaFilled(false);
quit.setOpaque(false);
quit.addActionListener(this);
fileMenu.add(save);
fileMenu.add(load);
fileMenu.addSeparator();
fileMenu.add(quit);
fileMenu.setContentAreaFilled(false);
fileMenu.setBorderPainted(false);
fileMenu.setOpaque(false);
JMenu editMenu = new JMenu("Edit");
JMenuItem undo = new JMenuItem("Undo");
undo.setMnemonic(KeyEvent.VK_U);
undo.setContentAreaFilled(false);
undo.setOpaque(false);
undo.addActionListener(this);
JMenuItem redo = new JMenuItem("Redo");
redo.setMnemonic(KeyEvent.VK_R);
redo.setContentAreaFilled(false);
redo.setOpaque(false);
redo.addActionListener(this);
editMenu.add(undo);
editMenu.add(redo);
editMenu.setContentAreaFilled(false);
editMenu.setBorderPainted(false);
editMenu.setOpaque(false);
JMenu helpMenu = new JMenu("Help");
JMenuItem controls = new JMenuItem("Controls");
controls.setMnemonic(KeyEvent.VK_C);
controls.setContentAreaFilled(false);
controls.setOpaque(false);
controls.addActionListener(this);
JMenuItem about = new JMenuItem("About");
about.setMnemonic(KeyEvent.VK_A);
about.setContentAreaFilled(false);
about.setOpaque(false);
about.addActionListener(this);
helpMenu.add(controls);
helpMenu.addSeparator();
helpMenu.add(about);
helpMenu.setContentAreaFilled(false);
helpMenu.setBorderPainted(false);
helpMenu.setOpaque(false);
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(helpMenu);
return menuBar;
}
public void paintComponent(Graphics g)
{
g.clearRect(0, 0, 1020, 770);
g.setColor(BLACK);
g.fillRect(x,y,100,100);
g.setColor(RED);
g.fillRect(x1,y1,50,50);
g.setColor(BLUE);
g.fillRect(x2,y2,25,25);
g.dispose();
}
public void change()
{
if(x1>=x+50&&changeY==0&&changeX==1)
{
changeX=0;
changeY=1;
}
else if(y1>=y+50&&changeX==0&&changeY==1)
{
changeX=-1;
changeY=0;
}
else if(x1<=x&&changeX==-1&&changeY==0)
{
changeX=0;
changeY=-1;
}
else if(y1<=y&&changeY==-1&&changeX==0)
{
changeX=1;
changeY=0;
}
x1+=changeX*5;
y1+=changeY*5;
}
public void change2()
{
if(x2>=x1+25&&changeY2==0&&changeX2==1)
{
changeX2=0;
changeY2=1;
}
else if(y2>=y1+25&&changeX2==0&&changeY2==1)
{
changeX2=-1;
changeY2=0;
}
else if(x2<=x1&&changeX2==-1&&changeY2==0)
{
changeX2=0;
changeY2=-1;
}
else if(y2<=y1&&changeY2==-1&&changeX2==0)
{
changeX2=1;
changeY2=0;
}
x2+=changeX2*2;
y2+=changeY2*2;
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equalsIgnoreCase("Draw"))
{
r.runFinalization();
r.gc();
change();
change2();
repaint();
}
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()==KeyEvent.VK_UP)
{
if(y-10>=0)
{
y-=10;
y1-=10;
y2-=10;
}
}
if(e.getKeyCode()==KeyEvent.VK_DOWN)
{
if(y+110<=getHeight())
{
y+=10;
y1+=10;
y2+=10;
}
}
if(e.getKeyCode()==KeyEvent.VK_LEFT)
{
if(x-10>=0)
{
x-=10;
x1-=10;
x2-=10;
}
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT)
{
if(x+110<=getWidth())
{
x+=10;
x1+=10;
x2+=10;
}
}
repaint();
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
}
You are not constructing on the EDT. An instance of javax.swing.Timer makes this easy, as the action event handler executes on the EDT.
Addendum 1: You may decide you need double buffering, but first compare the code below to yours and see. If you go that route, you might look at this tutorial.
Addendum 2: The example below shows how to maintain an offscreen buffer, but it is sometimes easier to use the JPanel(boolean isDoubleBuffered) constructor for a similar effect.
import java.awt.event.KeyAdapter;
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import static java.awt.Color.*;
/** #see http://stackoverflow.com/questions/2114455 */
public class GUI extends JPanel implements ActionListener {
int x, y, x1, y1, x2, y2, changeY, changeY2;
int changeX = 1; int changeX2 = 1;
Timer t = new Timer(100, this);
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new GUI(true).display();
}
});
}
public GUI(boolean doubleBuffered) {
super(doubleBuffered);
this.setPreferredSize(new Dimension(320, 240));
}
private void display() {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener(new KeyListener());
frame.add(this);
frame.pack();
frame.setVisible(true);
t.start();
}
#Override
public void paintComponent(Graphics g) {
g.setColor(WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(BLACK);
g.fillRect(x, y, 100, 100);
g.setColor(RED);
g.fillRect(x1, y1, 50, 50);
g.setColor(BLUE);
g.fillRect(x2, y2, 25, 25);
}
public void change() {
if (x1 >= x + 50 && changeY == 0 && changeX == 1) {
changeX = 0;
changeY = 1;
} else if (y1 >= y + 50 && changeX == 0 && changeY == 1) {
changeX = -1;
changeY = 0;
} else if (x1 <= x && changeX == -1 && changeY == 0) {
changeX = 0;
changeY = -1;
} else if (y1 <= y && changeY == -1 && changeX == 0) {
changeX = 1;
changeY = 0;
}
x1 += changeX * 5;
y1 += changeY * 5;
}
public void change2() {
if (x2 >= x1 + 25 && changeY2 == 0 && changeX2 == 1) {
changeX2 = 0;
changeY2 = 1;
} else if (y2 >= y1 + 25 && changeX2 == 0 && changeY2 == 1) {
changeX2 = -1;
changeY2 = 0;
} else if (x2 <= x1 && changeX2 == -1 && changeY2 == 0) {
changeX2 = 0;
changeY2 = -1;
} else if (y2 <= y1 && changeY2 == -1 && changeX2 == 0) {
changeX2 = 1;
changeY2 = 0;
}
x2 += changeX2 * 2;
y2 += changeY2 * 2;
}
#Override
public void actionPerformed(ActionEvent e) {
change();
change2();
repaint();
}
private class KeyListener extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int d = 5;
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (y - d >= 0) {
y -= d;
y1 -= d;
y2 -= d;
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (y + 100 + d <= getHeight()) {
y += d;
y1 += d;
y2 += d;
}
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
if (x - d >= 0) {
x -= d;
x1 -= d;
x2 -= d;
}
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
if (x + 100 + d <= getWidth()) {
x += d;
x1 += d;
x2 += d;
}
}
}
}
}
I would take a look at double buffering. Basically, you draw to an offscreen graphics object and then draw the offscreen graphics object onto the JPanel's graphics object.
~Bolt