Background: I have a basic applet from various tutorials and books written that adheres to their instructions and, after much toil over getting it to display anything at all, I finally have it so that it displays fine in Applet viewer. It has 3 classes: Animation, Sprite, and spriteTest. Animation and Sprite classes have been thoroughly tested, and spriteTest works fine on BlueJ's appletviewer. All of the images are in "Images/" relative to the path of the code. I will mention later that I can only get an applet running at all on localhost--I am using LAMP on Ubuntu, and it is configured properly (I have had no trouble with php).
What's supposed to happen is that three sprites (from the sprite class) are created and drawn to the screen, and with a random initial location and velocity (x and y), they move about the screen, bouncing off of the walls. This code works fine. Each sprite has 8 animations (one for each direction, vertical, horizontal, and diagonals), each of which have 11 frames. These frames are each pictures of png format with transparency of a person walking. All of this has been tested thoroughly. For debugging purposes, there is a constantly updated text in the middle of the screen in the format (xposition,yposition)::(xvelocity,yvelocity) for just the first sprite element (sprite[0]). The background is set to blue, and the applet begins!
Problem: While it runs just fine on the appletviewer, when run on firefox it displays nothing but a gray box. Thankfully, it actually loads until the status bar says "Applet loaded." but it shows nothing. I have waited minutes for it to load, in case Firefox takes a lot longer to load the (89) .png images (and one background.jpg), to no avail. To complicate things:
- Sometimes, the blue background loads and the debug text will update (correctly), but alas, no pictures at all (background or sprite) are shown
- The entire applet only works if I'm on localhost--any applet at all only works upon this condition--is this normal? If I don't run on localhost, I get the enigmatic "Start: applet is not initialized" error.
- I use double-buffering, but even in appletviewer, everything flickers for the first 5 seconds. Also, all three sprites start in the same place. I cannot rationalize this at all! If I restart the applet from the appletviewer menu, however, flickering is resolved and they start in different places. It is worth mentioning that, even without a restart, the sprites have different initial velocities, but all start at (0,0).
The code follows:
Animation:
import java.awt.Image;
import java.util.ArrayList;
public class Animation
{
private ArrayList frames;
private int index;
private long animTime;
private long totalDuration;
public Animation()
{
frames=new ArrayList();
totalDuration=0;
start();
}
public synchronized void addFrame(Image image, long duration)
{
totalDuration+=duration;
frames.add(new AnimFrame(image, totalDuration));//totalDuration is END TIME of this image
}
public synchronized void start()
{
animTime=0;
index=0;
}
public synchronized void update(long elapsedTime)
{
if(frames.size()>1)
{
animTime+=elapsedTime;
if(animTime>=totalDuration)
{
animTime=animTime%totalDuration;
index=0;
}
while(animTime>getFrame(index).endTime)
index++;
}
}
public synchronized Image getImage()
{
if(frames.size()==0)
return null;
return getFrame(index).image;
}
private AnimFrame getFrame(int i)
{
return (AnimFrame)frames.get(i);
}
private class AnimFrame
{
Image image;
long endTime;
public AnimFrame(Image image, long endTime)
{
this.image=image;
this.endTime=endTime;
}
}
}
Sprite:
import java.awt.Image;
public class Sprite
{
private Animation anim[]=new Animation[8];
// position (pixels)
private float x;
private float y;
// velocity (pixels per millisecond)
private float dx;
private float dy;
//direction, dependent variable 0-7
private int dir;
public Sprite(Animation[] anim, float dx, float dy)
{
this.anim=anim;
this.dx=dx;
this.dy=dy;
updateDir();
}
public void update(long elapsedTime)
{
x+=dx*elapsedTime;
y+=dy*elapsedTime;
anim[dir].update(elapsedTime);
}
public float getx(){return x;}
public float gety(){return y;}
public int getdir(){return dir;}
public void setx(float x){this.x=x;}
public void sety(float y){this.y=y;}
public int getw(){return anim[dir].getImage().getWidth(null);}
public int geth(){return anim[dir].getImage().getHeight(null);}
public float getdx(){return dx;}
public float getdy(){return dy;}
public void setdx(float dx){this.dx=dx;updateDir();}
public void setdy(float dy){this.dy=dy;updateDir();}
private void updateDir(){this.dir=direction();}
private int direction()
{
if(dx==0)
{
if(dy<=0)
return 2;//up
return 6;//down
}
else if(dy==0)
{
if(dx>=0)//= will never be reached
return 0;//east
return 4;//west
}
if(dx>0)
{
if(dy>0)
return 7;//southeast
return 1;//northeast
}
else if(dx<0)
{
if(dy>0)
return 5;//southwest
return 3;//northwest
}
return 1;
}
public Image getImage(){return anim[dir].getImage();}
}
spriteTest:
import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.applet.*;
import java.net.*;
import java.awt.geom.AffineTransform;
public class spriteTest extends Applet implements Runnable
{
private Graphics dbg;
private Image dbImage;
private boolean imagesLoaded;
private int loadedImages;
private final int FONT_SIZE=12;
private int w;
private int h;
//initialize environment variables
private static final long FADE_TIME=1000;
private static final int NUM_SPRITES=3;
private Image bgImage;
private Sprite sprites[];
private String dbug="No errors.";
Thread th;
public void init()
{
imagesLoaded=false;
loadImages();
setBackground(Color.blue);
//setForeground(Color.white);
setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE));
w=this.getSize().width;
h=this.getSize().height;
}
public void start()
{
th=new Thread(this);
th.start();
}
public void stop()
{
}
public void paint(Graphics g)
{
if(g instanceof Graphics2D)//backwards compatibility
{
Graphics2D g2=(Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
//draw images
if(imagesLoaded)
{
g.drawImage(bgImage,0,0,null);
for(int i=0;i<NUM_SPRITES;i++)
{
g.drawImage(sprites[i].getImage(),Math.round(sprites[i].getx()),Math.round(sprites[i].gety()),null);
}
}
else
{
g.drawString("Loading Image "+loadedImages+" of 88",5,FONT_SIZE);
}
g.drawString(dbug,30,400);
}
public void drawImage(Graphics g,Image image,int x,int y,String caption)
{
g.drawImage(image,x,y,this);
g.drawString(caption,x+5,y+FONT_SIZE+image.getHeight(null));
}
public void destroy()
{
}
public void run()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
long startTime=System.currentTimeMillis();
long currTime=startTime;
while(imagesLoaded)
{
long elapsedTime=System.currentTimeMillis()-currTime;
currTime+=elapsedTime;
dbug="("+sprites[0].getx()+","+sprites[0].gety()+")::("+sprites[0].getdx()+","+sprites[0].getdy()+")";
for(int i=0;i<NUM_SPRITES;i++)
{
if(sprites[i].getx()<0)
sprites[i].setdx(Math.abs(sprites[i].getdx()));
else if(sprites[i].getx()+sprites[i].getw()>=w)
sprites[i].setdx(-Math.abs(sprites[i].getdx()));
if(sprites[i].gety()<0)
sprites[i].setdy(Math.abs(sprites[i].getdy()));
else if(sprites[i].gety()+sprites[i].geth()>=h)
sprites[i].setdy(-Math.abs(sprites[i].getdy()));
sprites[i].update(elapsedTime);
}
repaint();
try{Thread.sleep(20);}
catch (InterruptedException e){dbug="ERORR!";}
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
private void loadImages()//loads images
{
// load images
bgImage = loadImage("Images/background.jpg");
Image walking[][]=new Image[8][12];//8*12
String nesw[]={"e","ne","n","nw","w","sw","s","se"};
for(int i=0;i<8;i++)
for(int j=0;j<12;j++)
{
String jj=(j>9)?"00"+j:"000"+j;
walking[i][j]=loadImage("Images/walking "+nesw[i]+""+jj+".png");
loadedImages++;
//System.out.println(loadedImages);
}
sprites=new Sprite[NUM_SPRITES];
// create animations
for(int i=0;i<NUM_SPRITES;i++)
{
Animation anim[]=new Animation[8];
for(int j=0;j<8;j++)
{
anim[j] = new Animation();
for(int k=0;k<12;k++)
anim[j].addFrame(walking[j][k], 100);
}
sprites[i]=new Sprite(anim,.1f,.1f);
sprites[i].setx((float)Math.random()*(w-sprites[i].getw()));
sprites[i].sety((float)Math.random()*(h-sprites[i].geth()));
}
imagesLoaded=true;
}
private Image loadImage(String fileName){return getImage(getCodeBase(),fileName);}
public void update(Graphics g)
{
if(dbImage==null)//initialize buffer
{
dbImage=createImage(this.getSize().width,this.getSize().height);
dbg=dbImage.getGraphics();
}
dbg.setColor(getBackground());//clear scrn in background
dbg.fillRect(0,0,this.getSize().width,this.getSize().height);
dbg.setColor(getForeground());//draw elements in foreground
paint(dbg);
g.drawImage(dbImage,0,0,this);//draw img on scrn
}
//functions I don't know yet
public String getAppletInfo()
{
return "Title: \nAuthor: \nA simple applet example description. ";
}
public String[][] getParameterInfo()
{
// provide parameter information about the applet
String paramInfo[][] = {
{"firstParameter", "1-10", "description of first parameter"},
{"status", "boolean", "description of second parameter"},
{"images", "url", "description of third parameter"}
};
return paramInfo;
}
}
The BlueJ-generated html test page, run in localhost:
<html>
<!-- This file automatically generated by BlueJ Java Development -->
<!-- Environment. It is regenerated automatically each time the -->
<!-- applet is run. Any manual changes made to file will be lost -->
<!-- when the applet is next run inside BlueJ. Save into a -->
<!-- directory outside of the package directory if you want to -->
<!-- preserve this file. -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>spriteTest Applet</title>
</head>
<body>
<h1>spriteTest Applet</h1>
<hr>
<applet code="spriteTest.class"
width=500
height=500
codebase="."
archive="file:/usr/bin/bluejlib/bluejcore.jar,file:/usr/bin/bluejlib/junit.jar,file:/var/www/JAVA/foundation/"
alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason."
>
Your browser is ignoring the <APPLET> tag!
</applet>
<hr>
</body>
</html>
While I am new to Java applets, I am pretty good with plain Java (command line), so the classes should be fine except for spriteTest--But I welcome any corrections. Thank you for your time.