Sprite list

Ive been sending a LinkedList to all my clients which seems pretty ineffective since all kinds of useless data is being sent as well.

Sprite:

public class Sprite implements Serializable {
    public static final int LEFT = 0, RIGHT = 1, UP = 2, DOWN = 3;
    
    private Rectangle collisionRect;
    protected Animation anim;
    protected float posX; // x position in pixels
    protected float posY; // y position in pixels
    protected float dx; // delta x in pixels per millisecond
    protected float dy; // delta y in pixels per millisecond
    protected boolean visible;
    protected int state;
    protected boolean alive;
    
    lots of methods here that make more than 10000 characters

}

Ive been trying to figure out if I should let each client keep track of the animations themselves, and let the server just handle movement. But there is a seperate animation for each direction and I havnt been able to figure out what I could do. What is the best way to go about this?

Your SPrites and Anim must be serializable anyway, that includes to copy the Image buffer too as well as other references. That may be tricky if you intend to send it through a socket… :’(

I made them serializable, the Animation holds an int[] instead of a bufferedImage which is converted back and fourth in the set/get methods. I have it working, its just that im sending way to much useless data over the socket. There are little jitters occasionally even when both client and host are on localhost.

I was trying to think of how I could sum up the state of the sprite list in a string or some primitive array. Like when a sprite is created maybe I could have a SpriteID field, then I could send info like
“sprite:294 x:2 y:8 animation:up animationProgress:873”. Or maybe I could just let the clients keep track of how far along the animation is and just have the host send information about when the animation changes.

My thought behind the sprite ID is that the host/client sprite list may not stay in the same order, so each sprite would have a number associated, which I guess would mean in need a sprite factory class.

Here is my animation class by the way, i thought i posted it in the first one, guess not:

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.io.*;

/**
    The Animation class manages a series of images (frames) and
    the amount of time to display each frame.
*/
public class Animation implements Serializable{

    private ArrayList<AnimFrame> frames;
    private int currFrameIndex;
    private long animTime;
    private long totalDuration;


    /**
        Creates a new, empty Animation.
    */
    public Animation() {
        this(new ArrayList<AnimFrame>(), 0);
    }
    
    public Animation(BufferedImage img) {
        this();
        frames.add(new AnimFrame(img, 1));
    }


    private Animation(ArrayList<AnimFrame> frames, long totalDuration) {
        this.frames = frames;
        this.totalDuration = totalDuration;
        start();
    }

	public void setAnimTime(long time) {
		animTime = time;
	}

	public long getAnimTime() {
		return animTime;
	}
    
    public int getDuration() {
        return (int)totalDuration;
    }

    /**
        Creates a duplicate of this animation. The list of frames
        are shared between the two Animations, but each Animation
        can be animated independently.
    */
    public Object clone() {
        return new Animation(frames, totalDuration);
    }


    /**
        Adds an image to the animation with the specified
        duration (time to display the image).
    */
    public synchronized void addFrame(BufferedImage image,
        long duration)
    {
        totalDuration += duration;
        frames.add(new AnimFrame(image, totalDuration));
    }


    /**
        Starts this animation over from the beginning.
    */
    public synchronized void start() {
        animTime = 0;
        currFrameIndex = 0;
    }


    /**
        Updates this animation's current image (frame), if
        neccesary.
    */
    public synchronized void update(long elapsedTime) {
        if (frames.size() > 1) {
            animTime += elapsedTime;

            if (animTime >= totalDuration) {
                animTime = animTime % totalDuration;
                currFrameIndex = 0;
            }

            while (animTime > getFrame(currFrameIndex).endTime) {
                currFrameIndex++;
            }
        }
    }


    /**
        Gets this Animation's current image. Returns null if this
        animation has no images.
    */
    public synchronized BufferedImage getImage() {
        if (frames.size() == 0) {
            return null;
        }
        else {
            return getFrame(currFrameIndex).getImage();
        }
    }


    private AnimFrame getFrame(int i) {
        return (AnimFrame)frames.get(i);
    }

    public void reset(){
    	animTime = 0;
    	currFrameIndex = 0;
    }

    private class AnimFrame implements Serializable {
    	int[] imageData;
    	int height, width;
        long endTime;

        public AnimFrame(BufferedImage image, long endTime) {
        	width = image.getWidth();
        	height = image.getHeight();
        	imageData = new int[width * height];
        	image.getRGB(0, 0, width, height, imageData, 0, width);
        	
            this.endTime = endTime;
        }
        
        public BufferedImage getImage() {
        	BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        	image.setRGB(0, 0, width, height, imageData, 0, width);
        	return image;
        }
    }
}

Well this seems quite ok for Animations but as you noticed the data int[] (I’ve to apologize for the poor english I can write) it simply disgust me in the way that array are static objects… :stuck_out_tongue: Plus you should know that the Java Core always make Arrays for data storing, e.g. the BufferedInputStream or other Buffers are Arrays. So it is also true that the Java Core manages the Graphics instances as cached/buffered objects so that it can be cleared as soon as possible a.k.a Garbage Collecting. Then why would you have an extra array for the image data? You better use a more dynamic struct’ for data. ArrayList or HashMaps are the best, though I’d not recommend them for image data.
More spefically, if you intend to buffer your images, use an offscreen image that will buffer the whole contents, simply draw onto the graphics obtained offscreen. That’s the fastest and most compatible manner for Rendering. Use Arrays with care because of their static struct unlike the Maps! ;D

[quote=“broumbroum,post:4,topic:30255”]
BufferedImages do not implement Serializable, so i need to not have any field be a BufferedImage in any class I am intending to send over an ObjectOutputStream. This is the easiest way I could figure out.

Yes, but see, if you don’t serialize the image then you don’t get the “sprite” as properly known completely serialized, do you? I can show you my own impl of serialized Sprite I use, it’s still in beta-test:

/** writes Sprite instance to given output
     * @param out OOutputStream to write to*/
    private void writeObject(ObjectOutputStream out) throws IOException {
        int currentPty = Thread.currentThread().getPriority();
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        out.defaultWriteObject();
        if(src instanceof Serializable)
            out.writeObject(src);
        else
            out.writeObject(NO_SOURCE);
        refreshData();
        if(!(data instanceof BufferedImage))
            data = toBuffered();
        if(data instanceof Image) {
            ImageWriter w = getWriter(0);
            w.setOutput(ImageIO.createImageOutputStream(out));
            IIOMetadata meta = w.getDefaultImageMetadata(new ImageTypeSpecifier((RenderedImage)data),w.getDefaultWriteParam());
            if(w.canInsertImage(-1))
                w.writeInsert(-1, new IIOImage((BufferedImage)data, null, meta), w.getDefaultWriteParam());
            else
                w.write(meta, new IIOImage((RenderedImage)data, null, meta), w.getDefaultWriteParam());
        }
        Thread.currentThread().setPriority(currentPty);
    }
    
    /** reads Sprite instanced from given input
     * @param in OInputStream to read from*/
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        int currentPty = Thread.currentThread().getPriority();
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        in.defaultReadObject();
        src = in.readObject();
        refQueue = new ReferenceQueue<PhantomReference>();
        obs = this;
        mt = new MediaTracker(obs);
        rProgList = Collections.synchronizedSet(new HashSet<IIOReadProgressListener>());
        wProgList = Collections.synchronizedSet(new HashSet<IIOWriteProgressListener>());
        rWarnList = Collections.synchronizedSet(new HashSet<IIOReadWarningListener>());
        wWarnList = Collections.synchronizedSet(new HashSet<IIOWriteWarningListener>());
        ImageReader r = getReader(0);
        r.setInput(ImageIO.createImageInputStream(in), true);
        try{
            data = (Image)r.read(r.getMinIndex());
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            packed = false;
            Thread.currentThread().setPriority(currentPty);
        }
    }

You can see that the BufferedImage can be written to an output with ImageWriter. That is a bit tricky if you don’t know how to deal with ImageWriter instances. There’s an non-accelerated ImageIO.write() method, too. But JAI doesn’t seem to support ImageIO.write()… Well this is the way I do it, but what seems more complex is to Rasterize or DataBufferize that I won’t do at all. I’ve seen that Jake2, java port of Quake2, do Rasterize the textures to get them serialized or buffered. But that Jake2 is seemly a port from a C coded game…
Note that I’ve set the Image field to transient while I write them to the stream with ImageWriters. :smiley:

Heh, I just realized this is all pointless anyway. The goal of this post was to find out how to keep everything up to date without having to send any BufferedImages ever. If I could do that I would get rid of my silly int[].

well this was a suggest, anyway I do confirm that this works well for me since I’ve been using that to serialize to disk. Indeed I make my own models of Sprites to have my own format. But regarding networking this is another issue I will looking forward to set it up. I’d say it is a bit struggled to send everything to the client and it’d be necesary to cut off most part of the datas.
I’d send through a socket only the keys to use and no list of Images, by the way. :smiley:

broumbroum, I think you got a little off topic. It would be incredibly inefficient to send images over the network to tell the client which images to draw. For animation and movement, the animation direction could be calculated by the client (and thus pick the correct animation) or it could just be a simple int value sent along with other information to tell the client which animation to play.