Hey guys, I have already spent too many hours (actually nights…) in this problem and could not found a solution for it. I really need your help. It seems to be very simple but I could not solve it
When I have 5 sprites on screen the animation is very smooth but when I got 60 sprites for example the animation got too fast. See it:
http://luisoft.o-f.com/tmp/5aliens.jnlp
and
http://luisoft.o-f.com/tmp/60aliens.jnlp
I could not figured out what is happining
Here is the source code that I have made (I have put all in a single class to let you analize it better). The code is based on Brackeen’s book.
http://luisoft.o-f.com/tmp/Problem.java
or
http://luisoft.o-f.com/tmp/60aliens.jar
I really need your help. Thanks
package game;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Problem extends Canvas {
private BufferStrategy strategy;
private ArrayList sprites = new ArrayList();
private HashMap animations = new HashMap();
public Problem() throws Exception {
JFrame frame = new JFrame("Space Shooter");
JPanel panel = (JPanel) frame.getContentPane();
panel.setPreferredSize(new Dimension(800, 600));
panel.setLayout(null);
this.setBounds(0, 0, 800, 600);
panel.add(this);
this.setIgnoreRepaint(true);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.createBufferStrategy(2);
this.strategy = this.getBufferStrategy();
this.initSprites();
this.gameLoop();
}
private void initSprites() throws Exception {
URL url = this.getClass().getClassLoader().getResource("gfx/enemy.png");
if (url == null) {
System.out.println("error");
System.exit(0);
}
BufferedImage image = ImageIO.read(url);
Image[] tmp = this.cropImage(image, 32, 32);
Image[] animationImage = new Image[tmp.length];
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();
Animation animation = new Animation();
for (int i = 0; i < tmp.length; i++) {
animationImage[i] = gc.createCompatibleImage(32, 32,
Transparency.BITMASK);
animationImage[i].getGraphics().drawImage(tmp[i], 0, 0, null);
animation.addFrame(animationImage[i], 250);
}
animation.start();
this.animations.put("gfx/enemy.png", animation);
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 1; i++) {
Sprite alien = new Sprite((Animation) this.animations
.get("gfx/enemy.png"), 100 + (i * 50), 50 + (j * 30));
this.sprites.add(alien);
}
}
}
private void update(long elapsedTime) {
for (int i = 0; i < this.sprites.size(); i++) {
Sprite sprite = (Sprite) sprites.get(i);
sprite.update(elapsedTime);
}
}
private void draw(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, 800, 600);
for (int i = 0; i < this.sprites.size(); i++) {
Sprite sprite = (Sprite) sprites.get(i);
sprite.draw(g);
}
}
private void gameLoop() {
long startTime = System.currentTimeMillis();
long currTime = startTime;
while (true) {
long elapsedTime = System.currentTimeMillis() - currTime;
currTime += elapsedTime;
update(elapsedTime);
Graphics g = this.strategy.getDrawGraphics();
draw((Graphics2D) g);
g.dispose();
this.strategy.show();
Toolkit.getDefaultToolkit().sync();
}
}
class Sprite {
protected Animation animation;
protected double x;
protected double y;
public Sprite(Animation pAnimation, int pX, int pY) {
this.animation = pAnimation;
this.x = pX;
this.y = pY;
}
public void update(long pDelta) {
this.animation.update(pDelta);
}
public void draw(Graphics g) {
this.animation.draw(g, (int) x, (int) y);
}
}
class Animation {
/** Array for holding the frames of the animation. */
private ArrayList frames = new ArrayList();
/** Indicates current frame. */
private int currFrameIndex;
/** Current animation time. */
private long animTime;
/** Total time of the animation. */
private long totalDuration;
private long lastFrameChange;
/**
* Adds an image to the animation with the specified duration (time to
* display the image).
*
* @param pImage
* Image of the frame.
* @param pDuration
* Amount of time to display the frame.
*/
public synchronized void addFrame(Image pImage, long pDuration) {
this.totalDuration += pDuration;
this.frames.add(new Frame(pImage, this.totalDuration, pDuration));
}
/**
* Starts this animation over from the beginning.
*/
public synchronized void start() {
this.animTime = 0;
this.currFrameIndex = 0;
}
/**
* Updates this animation's current image (frame), if neccesary.
*
* @param pElapsedTime
* Elapsed time since last update.
*/
public synchronized void update(long pElapsedTime) {
// We need only to update if the animation has more than 1 frame.
if (this.frames.size() > 1) {
this.animTime += pElapsedTime;
if (this.animTime >= this.totalDuration) {
this.animTime = this.animTime % this.totalDuration;
this.currFrameIndex = 0;
}
while (this.animTime > this.getFrame(this.currFrameIndex).endTime) {
this.currFrameIndex++;
}
}
}
private Frame getFrame(int index) {
return (Frame) frames.get(index);
}
public void draw(Graphics g, int pX, int pY) {
g.drawImage(((Frame) frames.get(currFrameIndex)).image, pX, pY, null);
}
}
/**
* Represents a frame of an animation.
*/
class Frame {
private Image image;
private long endTime;
private long duration;
public Frame(Image pImage, long pEndTime, long pDuration) {
this.image = pImage;
this.endTime = pEndTime;
this.duration = pDuration;
}
}
/**
* Breaks an image in tiles (subimages).
*
* @param pImage
* Image to be cropped.
* @param pCropWidth
* Tile width.
* @param pCropHeight
* Tile Height.
* @return Array of Image.
*/
private Image[] cropImage(Image pImage, int pCropWidth, int pCropHeight) {
int i = 0;
int j = 0;
Vector imgs = new Vector();
boolean finished = false;
while (!finished) {
if ((i + pCropWidth) > pImage.getWidth(null)) {
i = 0;
j += pCropHeight;
}
if ((j + pCropHeight) <= pImage.getHeight(null)) {
Image image1;
CropImageFilter cropimagefilter = new CropImageFilter(i, j,
pCropWidth, pCropHeight);
FilteredImageSource filteredimagesource = new FilteredImageSource(
pImage.getSource(), cropimagefilter);
image1 = Toolkit.getDefaultToolkit().createImage(
filteredimagesource);
imgs.add(image1);
i += pCropWidth;
} else {
pImage.flush();
finished = true;
}
}
Image[] tmp = new Image[imgs.size()];
for (int e = 0; e < tmp.length; e++) {
tmp[e] = (Image) imgs.get(e);
}
return tmp;
}
public static void main(String[] args) throws Exception {
new Problem();
}
}