1

I've got a problem with my Applet game in Java. It's flickering a lot when I run it. I have tried double buffering, but it didn't help. Here is a short coded version that shows the flickering...

public class Test extends JApplet implements ActionListener {

JButton start;

int delay;
Timer tm;

// Falling balls
int n; // Total balls
Ball[] ball; // Array with the balls in

int score;

// The amount of balls falling at the same time (increases by one every
// 10:th score)
int ballNr;

// Comment to the game
String comment;

public void init() {

    this.setLayout(null);
    this.setSize(600, 500);
    this.getContentPane().setBackground(Color.cyan);
    this.setFocusable(true);

    score = 0;
    ballNr = 3;
    comment = "Avoid the balls!";

    // Buttons
    start = new JButton("START");
    add(start);
    start.setBounds(0, 400, 200, 100);
    start.addActionListener(this);

    // The timer
    delay = 12;
    tm = new Timer(delay, this);

    // The falling balls
    n = 12; // Number of balls in total
    ball = new Ball[n];
    // Declaring twelve new instances of the ball-object with a
    // "reference array"
    for (int i = 0; i < n; i++) {
        ball[i] = new Ball();
    }
}

// Paint-method //
public void paint(Graphics g) {
    super.paint(g);

    // Every 10:th score, the game adds one ball until you reach 100 =
    // win! (ballNr + (int)(score * 0.1) -> ballNr increases by one
    // every 10:th score
    for (int i = 0; i < ballNr + (int) (score * 0.1); i++) {
        // Score can't be higher than 100
        if (score < 100) {
            g.setColor(ball[i].getCol());
            g.fillOval(ball[i].getXLoc(), ball[i].getYLoc(),
                    ball[i].getSize(), ball[i].getSize());
        }
    }

    // Draw the score and the comment
    g.setColor(Color.black);
    g.setFont(new Font("Arial", Font.BOLD, 24));
    g.drawString("SCORE: " + score, 440, 40);

    g.setColor(Color.red);
    g.setFont(new Font("Arial", Font.BOLD + Font.ITALIC, 28));
    g.drawString(comment, 0, 40);

}

// ACTIONLISTENER //
public void actionPerformed(ActionEvent e) {

    if (e.getSource() == start) {
        tm.start();
        this.requestFocusInWindow(); // Make the runner component have focus
    }

    // Every 10:th score, the game adds one ball until you reach 100 =
    // win! (ballNr + (int)(score * 0.1) -> ballNr increases by one
    // every 10:th score
    for (int i = 0; i < ballNr + (int) (score * 0.1); i++) {
        // Score can't pass 100, because then you have won the game
        if (score < 100) {
            ball[i].setYLoc(ball[i].getYLoc() + ball[i].getVel());
        }
    }

    // If any ball is out of bounds (then the score increases by one)
    for (int i = 0; i < n; i++) {
        if (outOfBounds(ball[i])) {
            ball[i] = new Ball();
        }
    }
    repaint();
}

// If the ball is out of the screen
public boolean outOfBounds(Ball ball) {
    if (ball.getYLoc() >= 500) {
        score++;
        return true;
    } else {
        return false;
    }
}

// Updates new balls
public void updateBalls() {
    for (int i = 0; i < n; i++) {
        ball[i] = new Ball();
    }
}
}

AND

public class Ball {
// Private variables
private Random r; // Generating random positions and
                    // sizes;
private int size; // Size of the ball
private int vel; // Ball velocity
private int nrOfCol; // Color code (see ballColor-method)
private Color col;
private int xLoc;
private int yLoc;

// Constructor
public Ball() {
    r = new Random();
    size = r.nextInt(40) + 10; // 10px - 50 px
    vel = r.nextInt(6) + 1; // Speed btw 1-5 px/delay
    nrOfCol = r.nextInt(8) + 1; // Specific nr from 1-9
    col = ballColor();
    xLoc = r.nextInt(550);
    yLoc = 0;
}

public Ball(int xPos, int yPos, int size, int vel, Color col) {
    this.xLoc = xPos;
    this.yLoc = yPos;
    this.size = size;
    this.vel = vel;
    this.col = col;
}

// A method to generate different colors of the balls
public Color ballColor() {
    Color col;
    switch (nrOfCol) {
    case 1:
        col = Color.black;
        break;
    case 2:
        col = Color.red;
        break;
    case 3:
        col = Color.green;
        break;
    case 4:
        col = Color.yellow;
        break;
    case 5:
        col = Color.pink;
        break;
    case 6:
        col = Color.magenta;
        break;
    case 7:
        col = Color.white;
        break;
    case 8:
        col = Color.orange;
        break;
    case 9:
        col = Color.blue;
        break;
    default:
        col = Color.black;
        // All colors except cyan as it is the background color
    }
    return col;
}

// Getters & setters

public int getXLoc() {
    return xLoc;
}

public int getYLoc() {
    return yLoc;
}

public void setYLoc(int y) {
    yLoc = y;
}

public int getSize() {
    return size;
}

public int getVel() {
    return vel;
}

public Color getCol() {
    return col;
}
}

I hope you can help me out as this is a very annoying issue I get on all my applets with animations. I would really appreciate help from you guys!

Andrew Thompson
  • 163,965
  • 36
  • 203
  • 405
CoderOgden
  • 357
  • 1
  • 4
  • 17
  • Why code an applet? If it is due to spec. by teacher, please refer them to [Why CS teachers should stop teaching Java applets](http://programmers.blogoverflow.com/2013/05/why-cs-teachers-should-stop-teaching-java-applets/). – Andrew Thompson Jun 22 '14 at 12:28
  • 2 tips. 1) Don't paint to a top level container like `JApplet`. Instead do custom painting in a `JPanel` and override the `paintComponent(..)` method instead of `paint()`. 2) Java GUIs might have to work on a number of platforms, on different screen resolutions & using different PLAFs. As such they are not conducive to exact placement of components. To organize the components for a robust GUI, instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556), along with layout padding & borders for [white space](http://stackoverflow.com/q/17874717/418556). – Andrew Thompson Jun 22 '14 at 12:30

2 Answers2

2

Some Points:

Please have a look at Painting in AWT and Swing that describes it in detail.


It's worth reading How paint method works?

Swing programs should override paintComponent() instead of overriding paint(). Although the API allows it, there is generally no reason to override paintBorder() or paintComponents() (and if you do, make sure you know what you're doing!). This factoring makes it easier for programs to override only the portion of the painting which they need to extend.

Sample code:

   JPanel panel = new JPanel() {
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            // custom painting code goes here
        }
    }
Community
  • 1
  • 1
Braj
  • 44,339
  • 5
  • 51
  • 69
2

Here is the code with the fix I suggested in comment.

Don't paint to a top level container like JApplet. Instead do custom painting in a JPanel and override the paintComponent(..) method instead of paint().

Note that a JComponent is double buffered by default, whereas a top-level container like JApplet typically isn't.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

/* <applet code=TestApplet width=600 height=500></applet> */
public class TestApplet extends JApplet {

@Override
public void init() {
    add(new PlayingArea());
}
}

class PlayingArea extends JPanel  implements ActionListener {

JButton start;

int delay;
Timer tm;

// Falling balls
int n; // Total balls
Ball[] ball; // Array with the balls in

int score;

// The amount of balls falling at the same time (increases by one every
// 10:th score)
int ballNr;

// Comment to the game
String comment;

public PlayingArea() {
    setBackground(Color.cyan);
    setFocusable(true);
    score = 0;
    ballNr = 3;
    comment = "Avoid the balls!";

    // Buttons
    start = new JButton("START");
    add(start);
    start.setBounds(0, 400, 200, 100);
    start.addActionListener(this);

    // The timer
    delay = 12;
    tm = new Timer(delay, this);

    // The falling balls
    n = 12; // Number of balls in total
    ball = new Ball[n];
    // Declaring twelve new instances of the ball-object with a
    // "reference array"
    for (int i = 0; i < n; i++) {
        ball[i] = new Ball();
    }
}

@Override
public Dimension getPreferredSize() {
    return new Dimension(600,500);
}

// Paint-method //
public void paintComponent(Graphics g) {
    super.paintComponent(g);

    // Every 10:th score, the game adds one ball until you reach 100 =
    // win! (ballNr + (int)(score * 0.1) -> ballNr increases by one
    // every 10:th score
    for (int i = 0; i < ballNr + (int) (score * 0.1); i++) {
        // Score can't be higher than 100
        if (score < 100) {
            g.setColor(ball[i].getCol());
            g.fillOval(ball[i].getXLoc(), ball[i].getYLoc(),
                    ball[i].getSize(), ball[i].getSize());
        }
    }

    // Draw the score and the comment
    g.setColor(Color.black);
    g.setFont(new Font("Arial", Font.BOLD, 24));
    g.drawString("SCORE: " + score, 440, 40);

    g.setColor(Color.red);
    g.setFont(new Font("Arial", Font.BOLD + Font.ITALIC, 28));
    g.drawString(comment, 0, 40);

}

// ACTIONLISTENER //
public void actionPerformed(ActionEvent e) {

    if (e.getSource() == start) {
        tm.start();
        this.requestFocusInWindow(); // Make the runner component have focus
    }

    // Every 10:th score, the game adds one ball until you reach 100 =
    // win! (ballNr + (int)(score * 0.1) -> ballNr increases by one
    // every 10:th score
    for (int i = 0; i < ballNr + (int) (score * 0.1); i++) {
        // Score can't pass 100, because then you have won the game
        if (score < 100) {
            ball[i].setYLoc(ball[i].getYLoc() + ball[i].getVel());
        }
    }

    // If any ball is out of bounds (then the score increases by one)
    for (int i = 0; i < n; i++) {
        if (outOfBounds(ball[i])) {
            ball[i] = new Ball();
        }
    }
    repaint();
}

// If the ball is out of the screen
public boolean outOfBounds(Ball ball) {
    if (ball.getYLoc() >= 500) {
        score++;
        return true;
    } else {
        return false;
    }
}

// Updates new balls
public void updateBalls() {
    for (int i = 0; i < n; i++) {
        ball[i] = new Ball();
    }
}
}

class Ball {
// Private variables
private Random r; // Generating random positions and
                    // sizes;
private int size; // Size of the ball
private int vel; // Ball velocity
private int nrOfCol; // Color code (see ballColor-method)
private Color col;
private int xLoc;
private int yLoc;

// Constructor
public Ball() {
    r = new Random();
    size = r.nextInt(40) + 10; // 10px - 50 px
    vel = r.nextInt(6) + 1; // Speed btw 1-5 px/delay
    nrOfCol = r.nextInt(8) + 1; // Specific nr from 1-9
    col = ballColor();
    xLoc = r.nextInt(550);
    yLoc = 0;
}

public Ball(int xPos, int yPos, int size, int vel, Color col) {
    this.xLoc = xPos;
    this.yLoc = yPos;
    this.size = size;
    this.vel = vel;
    this.col = col;
}

// A method to generate different colors of the balls
public Color ballColor() {
    Color col;
    switch (nrOfCol) {
    case 1:
        col = Color.black;
        break;
    case 2:
        col = Color.red;
        break;
    case 3:
        col = Color.green;
        break;
    case 4:
        col = Color.yellow;
        break;
    case 5:
        col = Color.pink;
        break;
    case 6:
        col = Color.magenta;
        break;
    case 7:
        col = Color.white;
        break;
    case 8:
        col = Color.orange;
        break;
    case 9:
        col = Color.blue;
        break;
    default:
        col = Color.black;
        // All colors except cyan as it is the background color
    }
    return col;
}

// Getters & setters

public int getXLoc() {
    return xLoc;
}

public int getYLoc() {
    return yLoc;
}

public void setYLoc(int y) {
    yLoc = y;
}

public int getSize() {
    return size;
}

public int getVel() {
    return vel;
}

public Color getCol() {
    return col;
}
}
Andrew Thompson
  • 163,965
  • 36
  • 203
  • 405
  • Thanks a lot! It works good even with the whole program although it's a bit slower than as a JFrame application. The reason I'm using JApplet is because my friend and I wants to make a website with small Java games. Are Applets/JApplets the only version that works on websites? Or is it possible to upload a JFrame application on a website with HTML code? :) – CoderOgden Jun 22 '14 at 14:11
  • *"Or is it possible to upload a JFrame application on a website with HTML code?"* Launch the frame direct from a link using [Java Web Start](http://stackoverflow.com/tags/java-web-start/info). Take it from me, applets are a complete PITA and a maintenance nightmare. – Andrew Thompson Jun 22 '14 at 14:23