I've been working on a cell evolution simulation in Java. Just so everyone knows, I'm a beginner/intermediate Java programmer. I know pretty much all the basics and then a little bit, but I don't quite have the skills to write code from scratch. The code I have here is roughly based on a source I found online, I added my own touches and some other pieces I found online as well. It seems to work just fine, except the screen flickers. It seems every time the repaint() is called it flickers, probably clearing and redrawing. It creates something that is practically impossible to look at. There are no errors in my code. I am new to using applets, so if there is a better way to do this, please let me know. How can I stop the screen from flickering? Is there an easy way to buffer the images to prevent that? Here's the class that draws the applet
/* <!-- Defines the applet element used by the appletviewer. -->
<applet code='CellLife.java' width='1920' height='1080'></applet> */
import java.applet.Applet;
import java.awt.Event;
import java.awt.Graphics;
import java.util.Enumeration;
import java.util.Vector;
public class CellLife extends Applet implements Runnable {
// ========================================================================
// VARIABLES
// ========================================================================
// Data
/** Thread object for CellLife applet */
private Thread m_cellLife = null;
// Static constants
/**
* the maximum number of creatures in the world. When the number of
* creatures alive drops below half this, a new one is created to bring the
* numbers back up.
*/
protected static final int MAX_CREATURES = 60;
// Data
/**
* A list of the creatures currently alive. Stores CLCreature references.
*/
protected Vector creatures;
/** The world is a rectangle from (0,0) to (limit.x,limit,y) */
protected CL2dVector limit;
/**
* The number of creatures that have been born since the simulation started
*/
protected long generations;
/** A test creature controllable by the user to allow response testing */
private CLCreature testCreature;
/** space-partitioning structure to speed collision detection */
protected CLBuckets buckets;
// ========================================================================
// METHODS
// ========================================================================
public CellLife() {
creatures = new Vector();
limit = new CL2dVector(500.0F, 500.0F);
generations = 0;
// initilaize our bucket structure
float bucketScale = CLCell.RADIUS; // could stretch to root-two times
// this
buckets = new CLBuckets(bucketScale, (int) Math.ceil(limit.x / bucketScale), (int) Math.ceil(limit.y / bucketScale));
}
public String getAppletInfo() {
return "Name: Cell Evolution\r\n" + "Author: Josh Marchand\r\n" + "Made in Eclipse";
}
// first time initialazion
public void init() {
resize((int) limit.x, (int) limit.y);
for (int i = 0; i < MAX_CREATURES; i++) {
CLCreature new_creature = new CLCreature();
new_creature.InitSimple(limit, buckets);
creatures.addElement(new_creature);
}
}
public void destroy() {
// TODO: Place applet cleanup code here
}
public void paint(Graphics g) {
g.drawString("No. creatures: " + creatures.size(), 0, 11);
g.drawString("Births: " + generations, 0, 22);
// draw cells
for (int i = 0; i < creatures.size(); i++) {
((CLCreature) creatures.elementAt(i)).Draw(g);
}
// DEBUG: also indicate the contents of the buckets
// buckets.Draw(g);
// get all creatures to do their stuff
CLCreature creature;
for (int i = 0; i < creatures.size(); i++) {
creature = (CLCreature) creatures.elementAt(i);
if (creature.DoTimeStep(g, buckets, limit) && creatures.size() < MAX_CREATURES) {
// inherit new creature from current
CLCreature newCreature = new CLCreature();
newCreature.InheritFrom(creature, buckets, limit);
creatures.addElement(newCreature);
generations++;
}
}
// delete the ones that died doing it
for (Enumeration e = creatures.elements(); e.hasMoreElements();) {
creature = (CLCreature) e.nextElement();
if (creature.hasDied) creatures.removeElement(creature);
}
// breed nwe creatures if pop. is low
if (creatures.size() < MAX_CREATURES / 2) {
// just add one for now,fix later
CLCreature newCreature = new CLCreature();
newCreature.InheritFrom((CLCreature) creatures.elementAt((int) Math.random() * creatures.size()), buckets, limit);
creatures.addElement(newCreature);
generations++;
}
}
public void start() {
if (m_cellLife == null) {
m_cellLife = new Thread(this);
m_cellLife.start();
}
// TODO: place any additional startup code here
}
public void stop() {
if (m_cellLife != null) {
m_cellLife.stop();
m_cellLife = null;
}
}
public void run() {
while (true) {
try {
repaint();
// quick nap here to allow user interface to catch up
Thread.sleep(100);
} catch (InterruptedException e) {
stop();
}
}
}
public boolean mouseDown(Event e, int x, int y) {
// create a single celled creature at specific loc
testCreature = new CLCreature();
testCreature.rootCell.location.x = x;
testCreature.rootCell.location.y = y;
testCreature.rootCell.type = CLGene.RED;
creatures.addElement(testCreature);
buckets.PutCell(testCreature.rootCell);
return true;
}
public boolean mouseDrag(Event e, int x, int y) {
testCreature.rootCell.location.x = x;
testCreature.rootCell.location.y = y;
return true;
}
public boolean mouseUp(Event evt, int x, int y) {
creatures.removeElement(testCreature);
buckets.RemoveCell(testCreature.rootCell);
return true;
}
}
Thank you all so much for the help, and I'm very sorry about my "noobiness", I am doing my best to teach myself!
I would consider using technique called double buffering, where you create an offscreen Graphics object bound to and Image, perform all the drawing on that then paint the result to screen. You can find a handy tutorial on creating graphics from image here. More complete sample can be found here.