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
Related
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
So I'm new at java and need some help with my breakout game. My JFrame is just blank and i don't know how to fix it?
So I have a ball class, paddle class, canvas class and a brick class as well as a main class. In my canvas class I set all functions the ball, paddle and bricks has etc. In brick class I draw the bricks. And in my main I do the JFrame but it's blank
Main class :
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame();
Canvas c = new Canvas();
frame.add(c);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I expect the JFrame to show the game instead of just blank window
package breakout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyEvent;
import breakout.Bricks.Type;
public class Canvas extends JPanel implements ActionListener, MouseMotionListener, MouseListener, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int HEIGHT = 600;
public static final int WIDTH = 720;
private int horizontalCount;
private BufferedImage image;
private Graphics2D bufferedGraphics;
private Timer time;
private static final Font endFont = new Font(Font.SANS_SERIF, Font.BOLD, 20);
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private Paddle player;
private Ball ball;
ArrayList<ArrayList<Bricks>> bricks;
public Canvas() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
bufferedGraphics = image.createGraphics();
time = new Timer (15, this);
player = new Paddle((WIDTH/2)-(Paddle.PADDLE_WIDTH/2));
ball = new Ball (((player.getX() + (Paddle.PADDLE_WIDTH / 2 )) - (Ball.DIAMETER / 2)), (Paddle.Y_POS - (Ball.DIAMETER + 10 )), -5, -5);
bricks = new ArrayList<ArrayList<Bricks>>();
horizontalCount = WIDTH / Bricks.BRICK_WIDTH;
for(int i = 0; i < 8; ++i) {
ArrayList<Bricks> temp = new ArrayList<Bricks>();
#SuppressWarnings("unused")
Type rowColor = null;
switch(i) {
case 0 :
case 2:
rowColor = Type.LOW;
break;
case 1 :
case 3 :
case 5 :
rowColor = Type.MEDIUM;
break;
case 4 :
case 6 :
rowColor = Type.HIGH;
break;
case 7 :
default :
rowColor = Type.ULTRA;
break;
}
for(int j = 0; j < horizontalCount; ++j) {
Bricks tempBrick = new Bricks();
temp.add(tempBrick);
}
bricks.add(temp);
addMouseMotionListener(this);
addMouseListener(this);
addKeyListener(this);
requestFocus();
}
}
public void actionPerformed(ActionEvent e) {
checkCollisions();
ball.Move();
for(int i = 0; i < bricks.size(); ++i) {
ArrayList<Bricks> al = bricks.get(i);
for(int j = 0; j < al.size(); ++j) {
Bricks b = al.get(j);
if(b.dead()) {
al.remove(b);
}
}
}
repaint();
}
private void checkCollisions() {
if(player.hitPaddle(ball)) {
ball.setDY(ball.getDY() * -1);
return;
}
if(ball.getX() >= (WIDTH - Ball.DIAMETER) || ball.getX() <= 0) {
ball.setDX(ball.getDX() * -1);
}
if(ball.getY() > (Paddle.Y_POS + Paddle.PADDLE_HEIGHT + 10)) {
resetBall();
}
if(ball.getY() <= 0) {
ball.setDY(ball.getDY() * -1);
}
int brickRowActive = 0;
for(ArrayList<Bricks> alb : bricks) {
if(alb.size() == horizontalCount) {
++brickRowActive;
}
}
for(int i = (brickRowActive==0) ? 0 : (brickRowActive - 1); i < bricks.size(); ++i) {
for(Bricks b : bricks.get(i)) {
if(b.hitBy(ball)) {
player.setScore(player.getScore() + b.getBrickType().getPoints());
b.decrementType();
}
}
}
}
private void resetBall() {
if(gameOver()) {
time.stop();
return;
}
ball.setX(WIDTH/2);
ball.setDY((HEIGHT/2) + 80);
player.setLives(player.getLives() -1);
player.setScore(player.getScore() <= 1);
}
private boolean gameOver() {
if(player.getLives() <= 1) {
return true;
}
return false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
bufferedGraphics.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(bufferedGraphics);
player.drawBall(bufferedGraphics);
for(ArrayList<Bricks> row : bricks) {
for(Bricks b : row) {
b.drawBrick(bufferedGraphics);
}
}
bufferedGraphics.setFont(scoreFont);
bufferedGraphics.drawString("Score: " + player.getScore(), 10, 25);
if(gameOver() && ball.getY() >= HEIGHT) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("Game Over Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT/2));
}
if(empty()) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("You won. Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT /2));
time.stop();
}
g.drawImage(image, 0, 0, this);
Toolkit.getDefaultToolkit().sync();
}
private boolean empty() {
for(ArrayList<Bricks> al : bricks) {
if(al.size() != 0) {
return false;
}
}
return true;
}
#Override
public void mouseMoved(MouseEvent e) {
player.setX(e.getX() - (Paddle.PADDLE_WIDTH / 2));
}
#Override
public void mouseClicked(MouseEvent e) {
if(time.isRunning()) {
return;
}
time.start();
}
#Override
public void mouseDragged(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
#Override
public void keyPressed(KeyEvent arg0) {}
#Override
public void keyReleased(KeyEvent arg0) {}
#Override
public void keyTyped(KeyEvent arg0) {}
}
Preparing an MCVE, as required in SO, not only it makes helping much easier.
In many case, while preparing one, you are likely to find the problem, so it is a good debugging tool.
To answer "why is my JFrame blank ?" you could create the minimal code example like the following (copy-paste the entire code into GameBoard.java and run):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
static final int HEIGHT = 600, WIDTH = 720, BRICK_ROWS = 8;
private final int horizontalCount;
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private final Paddle player;
private final Ball ball;
ArrayList<ArrayList<Brick>> bricks;
public GameBoard() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
player = new Paddle(WIDTH/2-Paddle.PADDLE_WIDTH/2);
ball = new Ball (player.getX() + Paddle.PADDLE_WIDTH / 2 - Ball.DIAMETER / 2,
Paddle.Y_POS - (Ball.DIAMETER + 10 ));
bricks = new ArrayList<>();
horizontalCount = WIDTH / Brick.BRICK_WIDTH;
for(int i = 0; i < BRICK_ROWS; ++i) {
ArrayList<Brick> temp = new ArrayList<>();
for(int j = 0; j < horizontalCount; ++j) {
Brick tempBrick = new Brick(j*Brick.BRICK_WIDTH , Brick.BRICK_YPOS + i*Brick.BRICK_HEIGHT);
temp.add(tempBrick);
}
bricks.add(temp);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(g2D);
ball.drawBall(g2D);
for(ArrayList<Brick> row : bricks) {
for(Brick b : row) {
b.drawBrick(g2D);
}
}
g2D.setFont(scoreFont);
g2D.drawString("Score: " + player.getScore(), 10, 25);
}
}
class Paddle{
public final static int PADDLE_WIDTH = 100, PADDLE_HEIGHT= 30, Y_POS = GameBoard.HEIGHT - 2* PADDLE_HEIGHT;
private int xPos, score;
Paddle(int xPos) {
this.xPos = xPos;
}
void setX(int xPos) {this.xPos = xPos;}
int getX() {return xPos;}
String getScore() {
return String.valueOf(score);
}
void drawPaddle(Graphics2D g2D) {
g2D.setColor(Color.GREEN);
g2D.fillRect(xPos, Y_POS, PADDLE_WIDTH, PADDLE_HEIGHT);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400,250);
frame.add(new GameBoard());
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
class Brick{
final static int BRICK_WIDTH = 80, BRICK_HEIGHT = 15, BRICK_YPOS = 50;
int xPos, yPos;
Brick(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBrick(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fillRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
g2D.setColor(Color.BLACK);
g2D.drawRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
}
}
class Ball{
final static int DIAMETER = 40;
int xPos, yPos;
Ball(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBall(Graphics2D g2D) {
g2D.setColor(Color.BLUE);
g2D.fillOval(xPos, yPos, DIAMETER, DIAMETER);
}
}
This produces the following result, which I believe can serve as the basis of what you wanted to achieve:
Now start adding the missing functionality and see what breaks it.
So I'm making a game where you jump on rocks and you must not jump on rock which is covered by water. I'm stuck at the part where rocks (circles) randomly disappear in water and randomly appear and around 1.5 seconds before they disappear make it change color. I think its best to use javax.swing.Timer.
Could you help me achieve that?
Here is my code so far:
Main class:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Menu;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferStrategy;
import java.util.Random;
import javax.swing.Timer;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = -7800496711589684767L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Random r;
private Handler handler;
//private HUD hud;
private Menu menu;
public enum STATE {
Menu,
Help,
Game
};
public STATE gameState = STATE.Menu;
public Game() {
handler = new Handler();
menu = new Menu(this, handler);
this.addKeyListener(new KeyInput(handler));
this.addMouseListener(menu);
new Window(WIDTH, HEIGHT, "My game", this);
//hud = new HUD();
r = new Random();
//if(gameState == STATE.Game) {
if(gameState == STATE.Game) { //handler.addObject(new Player(100, 200, ID.Player));
}
//handler.addObject(new Player(100, 200, ID.Player));
//handler.addObject(new BasicEnemy(100, 200, ID.BasicEnemy));
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
}catch(Exception ex) { ex.printStackTrace(); }
}
public void run()
{
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running)
{
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >=1)
{
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000)
{
timer += 1000;
//System.out.println("FPS: "+ frames);
frames = 0;
}
}
stop();
}
private void tick() {
handler.tick();
//hud.tick();
if(gameState == STATE.Game) {
Random r = new Random();
long now = System.currentTimeMillis();
int b = 0;
//System.out.println(now);
long extraSeconds = 500;
}else if(gameState == STATE.Menu) {
menu.tick();
}
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
long now = System.currentTimeMillis();
g.setColor(new Color(87, 124, 212));
g.fillRect(0, 0, WIDTH, HEIGHT);
if(gameState == STATE.Game) {
g.setColor(new Color(209, 155, 29));
for(int i = 0; i < 5; i++) {
g.fillOval(80 + (100 * i), 325, 70, 20);
}
if(gameState == STATE.Game) {
}else if(gameState == STATE.Menu || gameState == STATE.Help){
menu.render(g);
}
handler.render(g);
if(gameState == STATE.Game) {
}
//hud.render(g);
g.dispose();
bs.show();
}
public static int clamp(int var, int min, int max) {
if(var >= max)
return var = max;
else if(var <= max)
return var = min;
else
return var;
}
public static void main(String[] args) {
new Game();
}
}
GameObject class:
package com.pitcher654.main;
import java.awt.Graphics;
public abstract class GameObject {
protected static int x, y;
protected ID id;
protected int velX, velY;
public GameObject(int x, int y, ID id) {
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick();
public abstract void render(Graphics g);
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setID(ID id) {
this.id = id;
}
public ID getID() {
return id;
}
public void setVelX(int velX) {
this.velX = velX;
}
public void setVelY(int velY) {
this.velY = velY;
}
public int getVelX() {
return velX;
}
public int getVelY() {
return velY;
}
}
Handler class:
package com.pitcher654.main;
import java.awt.Graphics;
import java.util.LinkedList;
public class Handler {
LinkedList<GameObject> object = new LinkedList<GameObject>();
public void tick() {
for(int i = 0; i < object.size(); i++) {
GameObject tempObject = object.get( i );
tempObject.tick();
}
}
public void render(Graphics g) {
for(int i = 0; i < object.size(); i++) {
GameObject tempObject = object.get(i);
tempObject.render(g);
}
}
public void addObject(GameObject object) {
this.object.add(object);
}
public void removeObject(GameObject object) {
this.object.remove(object);
}
}
ID class:
package com.pitcher654.main;
public enum ID {
Player(),
Player2(),
BasicEnemy(),
Misc();
}
KeyInput class:
package com.pitcher654.main;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class KeyInput extends KeyAdapter{
private Handler handler;
public KeyInput(Handler handler) {
this.handler = handler;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
for(int i = 0; i < handler.object.size(); i++) {
GameObject tempObject = handler.object.get(i);
if(tempObject.getID() == ID.Player) {
//kez events for Player 1
//GameObject object = new GameObject(0, 0, ID.Misc);
//System.out.println(tempObject.getID());
if(GameObject.x != 500) {
if(key == KeyEvent.VK_RIGHT) {
Player.currentStone++;
tempObject.setX(tempObject.getX() + 100);
}
}
if(GameObject.x != 100){
if(key == KeyEvent.VK_LEFT) {
Player.currentStone--;
tempObject.setX(tempObject.getX() - 100);
}
}
}
}
if(key == KeyEvent.VK_ESCAPE) System.exit(1);
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
}
}
Menu class:
package com.pitcher654.main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import com.pitcher654.main.Game.STATE;
public class Menu extends MouseAdapter{
private Game game;
private Handler handler;
private GameObject Player;
public Menu(Game game, Handler handler) {
this.game = game;
this.handler = handler;
}
public void mouseClicked(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
if(game.gameState == STATE.Menu) {
//play 1 button
if(mouseOver(mx, my, (Game.WIDTH - 250) / 2, 150, 250, 64)) {
game.gameState = STATE.Game;
handler.addObject(new Player(100, 200, ID.Player));
//handler.addObject(new BasicEnemy(0, 0, ID.BasicEnemy));
}
//Instructions button
if(mouseOver(mx, my, (Game.WIDTH - 250) / 2, 250, 250, 64)) {
game.gameState = STATE.Help;
}
//Quit button
if(mouseOver(mx, my, (Game.WIDTH - 250) / 2, 350, 250, 64)) {
System.exit(1);
}
}
//Bacl to menu in game button
if(game.gameState == STATE.Help) {
if(mouseOver(mx, my, 23, 395, 100, 32)) {
game.gameState = STATE.Menu;
//handler.object.remove(Player);
}
}
}
public void mouseReleased(MouseEvent e) {
}
private boolean mouseOver(int mx, int my, int x, int y, int width, int height) {
if(mx > x && mx < x + width) {
if(my > y && my < y + height) {
return true;
}else return false;
}else return false;
}
public void tick() {
}
public void render(Graphics g) {
if(game.gameState == STATE.Menu) {
Font fnt = new Font("Trebuchet MS", 30, 15);
g.setColor(new Color(87, 124, 212));
g.fillRect(0, 0, game.WIDTH, game.HEIGHT);
g.setColor(Color.white);
g.setFont(new Font("Papyrus", 1, 50));
g.drawString("Price iz davnine", (Game.WIDTH - 250) / 2 - 50, 70);
g.drawRect((Game.WIDTH - 250) / 2, 150, 250, 64);
g.drawRect((Game.WIDTH - 250) / 2, 250, 250, 64);
g.drawRect((Game.WIDTH - 250) / 2, 350, 250, 64);
g.setFont(new Font("Trebuchet MS", 5000, 20));
g.drawString("Play", (Game.WIDTH - 250) / 2 + 110, 190);
g.setFont(fnt);
g.drawString("How to Play", (Game.WIDTH - 250) / 2 + 85, 290);
g.drawString("Quit", (Game.WIDTH - 250) / 2 + 105, 390);
}else if(game.gameState == STATE.Help) {
g.setColor(Color.white);
g.setFont(new Font("Papyrus", 1, 50));
g.drawString("How to play", (Game.WIDTH - 250) / 2 - 50, 70);
g.setFont(new Font("Trebuchetr MS", 30, 10));
g.drawRect(23, 395, 100, 32);
g.setColor(Color.black);
g.drawString("Back to Menu", 33, 415);
}
}
}
Player class:
package com.pitcher654.main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Timer;
import com.pitcher654.main.Game.STATE;
public class Player extends GameObject {
Random r = new Random();
public static int currentStone = 1;
public Player(int x, int y, ID id) {
super(x, y, id);
//velX = r.nextInt(5) + 1;
//velY = r.nextInt(5);
}
public void tick() {
x += velX;
y += velY;
//System.out.println(x);
//if(x == 500) x = 500;
}
public void render(Graphics g) {
if(id == ID.Player) g.setColor(Color.white);
g.fillRect(x, y, 32, 32);
g.drawLine(x + 15, y, x + 15, y + 100);
g.drawLine(x + 15, y + 100, x, y + 135);
g.drawLine(x + 15, y + 100, x + 33, y + 135);
g.drawLine(x + 15, y + 70, x - 35, y + 30);
g.drawLine(x + 15, y + 70, x + 65, y + 30);
/*if(game.gameState == STATE.Menu) {
g.setColor(new Color(87, 124, 212));
g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
}*/
}
}
And window class:
package com.pitcher654.main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends Canvas{
private static final long serialVersionUID = 9086330915853125521L;
BufferedImage image = null;
URL url = null;
public Window(int width, int height, String title, Game game) {
JFrame frame = new JFrame(title);
try {
image = ImageIO.read(new URL("https://static.wixstatic.com/media/95c249_b887de2536aa48cb962e2336919d2693.png/v1/fill/w_600,h_480,al_c,usm_0.66_1.00_0.01/95c249_b887de2536aa48cb962e2336919d2693.png"));
} catch (IOException e) {
e.printStackTrace();
}
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(game);
frame.setIconImage(image);
//DrawingPanel panel = new DrawingPanel();
//frame.getContentPane().add(panel);
frame.setVisible(true);
frame.requestFocus();
game.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -7662876024842980779L;
public void paintComponent(Graphics g) {
g.setColor(new Color(209, 155, 29));
g.fillOval(100, 100, 100, 100);
}
}
}
Based on you code, a Swing Timer isn't what you want. You already have a "game/main" loop which should be updating the current state of the game on each cycle and rendering it, you simply need to devise a means by which you can create a "rock", with a given life span, each time it's rendered, it needs to check if it's life span is nearly over and have it removed when it dies.
The rock is really just another entity in your game, which can be updated and rendered.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.event.ComponentAdapter;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RockyRoad {
public static void main(String[] args) {
new RockyRoad();
}
public RockyRoad() {
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 static class Game extends Canvas implements Runnable {
private static final long serialVersionUID = -7800496711589684767L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Random rnd;
private List<Entity> entities = new ArrayList<>(25);
public enum STATE {
Menu,
Help,
Game
};
public STATE gameState = STATE.Game;
public Game() {
rnd = new Random();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
start();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running) {
update();
render();
}
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
//System.out.println("FPS: "+ frames);
frames = 0;
}
}
stop();
}
private void tick() {
//hud.tick();
}
protected void update() {
if (gameState == STATE.Game) {
if (rnd.nextBoolean()) {
System.out.println("New...");
int x = rnd.nextInt(getWidth() - Rock.SIZE);
int y = rnd.nextInt(getHeight() - Rock.SIZE);
int lifeSpan = 4000 + rnd.nextInt(6000);
entities.add(new Rock(lifeSpan, x, y));
}
List<Entity> toRemove = new ArrayList<>(entities.size());
List<Entity> control = Collections.unmodifiableList(entities);
for (Entity entity : entities) {
if (entity.update(control, this) == EntityAction.REMOVE) {
System.out.println("Die...");
toRemove.add(entity);
}
}
entities.removeAll(toRemove);
}
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
long now = System.currentTimeMillis();
g.setColor(new Color(87, 124, 212));
g.fillRect(0, 0, WIDTH, HEIGHT);
if (gameState == STATE.Game) {
g.setColor(new Color(209, 155, 29));
if (gameState == STATE.Game) {
for (Entity entity : entities) {
entity.render(g, this);
}
}
g.dispose();
bs.show();
}
}
public static int clamp(int var, int min, int max) {
if (var >= max) {
return var = max;
} else if (var <= max) {
return var = min;
} else {
return var;
}
}
}
public interface Renderable {
public void render(Graphics2D g2d, Component parent);
}
public enum EntityAction {
NONE,
REMOVE;
}
public interface Entity extends Renderable {
// In theory, you'd pass the game model which would determine
// all the information the entity really needed
public EntityAction update(List<Entity> entities, Component parent);
}
public static class Rock implements Renderable, Entity {
protected static final int SIZE = 20;
private int lifeSpan;
private long birthTime;
private int x, y;
public Rock(int lifeSpan, int x, int y) {
if (lifeSpan <= 1500) {
throw new IllegalArgumentException("Life span for a rock can not be less then or equal to 1.5 seconds");
}
this.lifeSpan = lifeSpan;
birthTime = System.currentTimeMillis();
this.x = x;
this.y = y;
}
#Override
public void render(Graphics2D g2d, Component parent) {
long age = System.currentTimeMillis() - birthTime;
if (age < lifeSpan) {
if (age < lifeSpan - 1500) {
g2d.setColor(Color.BLUE);
} else {
g2d.setColor(Color.RED);
}
g2d.fillOval(x, y, SIZE, SIZE);
}
}
#Override
public EntityAction update(List<Entity> entities, Component parent) {
EntityAction action = EntityAction.NONE;
long age = System.currentTimeMillis() - birthTime;
System.out.println("Age = " + age + "; lifeSpan = " + lifeSpan);
if (age >= lifeSpan) {
action = EntityAction.REMOVE;
}
return action;
}
}
}
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.