Two problems. Flickering despite buffer, and I can't get sizes.

(Code at the end of my post)

I'm new to Java! Heh, so I have decided to set little goals for myself in an attempt to learn common practice and to get a handle on how everything is supposed to work in the language.

I've started working on a little program that makes snowflakes fall down in a window. I use transparent PNG images to save myself some work. Eventually I'd like to use a JPG for a backdrop, but let's not overcomplicate things.

I managed to get flakes falling down, that's easy enough with an image and some threads. Even at different speeds! Wee!

The problem was that they flickered, so aha- double buffering!

I wish.

It doesn't work, and I'm not sure if I'm doing it right and I'd really like to get some overall pointers on my code as well.

Another problem is that I can't seem to get this.WIDTH or this.getWidth to return the width of the window? It always comes back as zero, even when called in addNotify?! What's up with that?

Please, any knowledgeable and kind gurus would be of great help to give me a few badly needed kicks.

(There are three classes, one for my JFrame, one for the scene itself, and one to act as a sorta "individual snowflake")

package snow_flakes;

import java.awt.*;

import javax.swing.*;

publicclass MainFrameextends JFrame{

JPanel contentPane;

BorderLayout borderLayout1 =new BorderLayout();

public MainFrame(){

// Make our program.

try{

setLayout(new BorderLayout());

setDefaultCloseOperation(EXIT_ON_CLOSE);

setSize(new Dimension(600, 350));

setTitle("Snowflakes!");

// Add my little custom snow-scene to the frame.

add(new SnowFlakesScene(), BorderLayout.CENTER);

setVisible(true);

}

// Something big went down in the program.

catch (Exception somethingBig){

somethingBig.printStackTrace();

}

}

publicstaticvoid main(String[] argh){

new MainFrame();

}

}

package snow_flakes;

import java.awt.Canvas;

import java.awt.Color;

import java.awt.Point;

import java.awt.Graphics;

import javax.swing.ImageIcon;

import java.awt.Toolkit;

import java.awt.Image;

import javax.swing.JFrame;

publicclass SnowFlakesSceneextends Canvasimplements Runnable{

Thread meThreadded;

Image mySnowFlake;

Image myBuffer;

Toolkit toolKit;

Graphics bufferDraw;

SnowFlake[] sceneFlakes =new SnowFlake[8];

SnowFlakesScene(){

super();

// Set up the toolkit?! WTF is that?

toolKit = Toolkit.getDefaultToolkit();

// Set up the canvas's appearance.

setBackground(new Color(255, 255, 255));

// Set up the snowflakes.

mySnowFlake = toolKit.getImage("snowflake.png");

sceneFlakes[0] =new SnowFlake(this, 15,new Point(0, 0));

sceneFlakes[1] =new SnowFlake(this, 14,new Point(150, 0));

sceneFlakes[2] =new SnowFlake(this, 17,new Point(200, 0));

sceneFlakes[3] =new SnowFlake(this, 9,new Point(95, 0));

sceneFlakes[4] =new SnowFlake(this, 16,new Point(30, 0));

sceneFlakes[5] =new SnowFlake(this, 21,new Point(28, 0));

sceneFlakes[6] =new SnowFlake(this, 19,new Point(15, 0));

sceneFlakes[7] =new SnowFlake(this, 10,new Point(103, 0));

//for(int currentFlake = 0; currentFlake < sceneFlakes.length; currentFlake++) {

//sceneFlakes[currentFlake] = new SnowFlake(this, 1, new Point(0,0));

//}

// Set up the redrawing thread.

meThreadded =new Thread(this);

}

publicvoid addNotify(){

super.addNotify();

// Start the thread once the component is initiated.

meThreadded.start();

// Peer problematic.

myBuffer = createImage(200, 200);

bufferDraw = myBuffer.getGraphics();

System.out.println(this);

}

publicvoid paint(Graphics drawTime){

// Pull the buffer onto the canvas.

drawTime.drawImage(myBuffer, 0, 0,this);

}

// To eliminate flickering.

publicvoid update(){

repaint();

}

publicvoid run(){

while(myBuffer !=null){

try{

bufferDraw.clearRect(0, 0, 200, 200);

for(int currentFlake = 0; currentFlake < sceneFlakes.length; currentFlake++){

bufferDraw.drawImage(mySnowFlake, sceneFlakes[currentFlake].getX(), sceneFlakes[currentFlake].getY(),this);

}

repaint();

// Sleep the minimum amount of time possible.

meThreadded.sleep(1);

}

catch(InterruptedException whoCares){

}

}

}

}

package snow_flakes;

import java.awt.Image;

import java.awt.Toolkit;

import java.awt.Point;

publicclass SnowFlakeextends Thread{

// Me honkies.

Image myImage;

SnowFlakesScene myScene;

Point myCoords;

Boolean falling;

// Smaller number, faster fall for flake. Bruhaha!

int myFallSpeed;

// Constructor accepting a string to define the image.

SnowFlake(SnowFlakesScene mySceneSource,int myFallSpeedSource, Point myStartCoords){

myScene = mySceneSource;

//System.out.println("Scene info: " + myScene);

myFallSpeed = myFallSpeedSource;

//System.out.println("Flake fall speed: " + myFallSpeed);

myCoords = myStartCoords;

//System.out.println("Flake starts @: " + myStartCoords);

falling =true;

this.start();

System.out.println("Flake falling.");

}

publicint getX(){

return(myCoords.x);

}

publicint getY(){

return(myCoords.y);

}

publicvoid run(){

while(falling){

// Always move the flake down one.

myCoords.y++;

// Move the flake over left or right, randomly.

try{

sleep(myFallSpeed);

}

catch(InterruptedException whoCares){

}

}

}

}

[10965 byte] By [SniperSlapa] at [2007-10-2 2:30:57]
# 1

About the flickering, there are several problems.

1. You generally shouldn't mix Swing and AWT classes. Use either Frame and Canvas or JFrame and JPanel.

2. If you use Canvas, than update(g) should call paint(g), not repaint(). Calling repaint means that the event queue will keep repainting as fast as possible, meaning it may repaint between the calls to bufferDraw.clearRect(0, 0, 200, 200); and repaint(); in SnowFlakesScene's run method.

3. Don't use one thread for each snowflake. Instead change SnowFlakeScene's run to look like this:

public void run() {

while(myBuffer != null) {

try {

bufferDraw.clearRect(0, 0, 200, 200);

for(int currentFlake = 0; currentFlake < sceneFlakes.length; currentFlake++) {

sceneFlakes[currentFlake].step()

bufferDraw.drawImage(mySnowFlake, sceneFlakes[currentFlake].getX(), sceneFlakes[currentFlake].getY(), this);

}

repaint();

// fallSpeed is constant and determines your FPS

// Change the amout each falls instead

meThreadded.sleep(fallSpeed);

}

catch(InterruptedException whoCares) {

}

}

}

SnowFlake.step(){

// Always move the flake down one.

myCoords.y++;

// Move the flake over left or right, randomly.

if(Math.random()<.5){

myCoords.x++;

}else{

myCoords.x--;

}

}

4. You may want to use ImageIO and BufferedImage rather than Toolkit and createImage

5. Move the call to getWidth() to either the paint method, where you could check if you already have the correct width + height for your buffer and if not, recreate it, or to an init method. Move all the constructor and addNotify stuff to the init method, and call init from MainFrame after you call setVisible (or pack if you use that later).

6. Move all of SnowFlakesScene's run method to paint() and instead have your run method call paint(getGraphics()) or repaint. This avoids having it repaint because you move another window over your app and it repainting when your buffer is blank.

7. If you do #6 and use Swing instead of AWT, you don't need another buffer: Swing double buffers by default unless you turn it off by calling some method.

Talchasa at 2007-7-15 20:22:47 > top of Java-index,Other Topics,Java Game Development...
# 2

That's wicked advice, I was worried about using both Swing and AWT, so it makes sense.

My concern with what you've suggested is that, won't it lock each flake into travelling at the same speed?

I wanted to thread each flake because then they could be responsible for handling their fall speed. The scene was merley responsible for drawing them out at their desired speed.

The other one is, where I have (200, 200), you'll notice that it's only a portion of my window...This is because I can't seem to get getWidth or .WIDTH on my scene to return anything except 0 or 1?!

SniperSlapa at 2007-7-15 20:22:47 > top of Java-index,Other Topics,Java Game Development...
# 3

Ooh, I just went & re did everything, and I realized what you were saying about the whole step & controlling the descent by number.

Everything is working PERFECTLY now!

I get a great deal of slowdown one I hit around 100 snowflakes. Every other problem is solved though.

Any ideas on how to get the performance to go up with more flakes, or am I at my limit given my current (obvious) skill level?

(this is awesome, I've found my new home!!)

SniperSlapa at 2007-7-15 20:22:47 > top of Java-index,Other Topics,Java Game Development...