From 76cff072beebf833362f00482e0b4d11507ae967 Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Sat, 16 Mar 2002 03:15:06 +0000 Subject: [PATCH] Split Sprite into Sprite and ImageSprite. Added LabelSprite. Cleaned up directional constant usage. Added ability to render sprites in two distinct layers. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1132 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/cast/CharacterManager.java | 8 +- .../com/threerings/cast/CharacterSprite.java | 8 +- .../threerings/cast/builder/SpritePanel.java | 20 +- .../bundle/BundledComponentRepository.java | 12 +- .../com/threerings/cast/util/TileUtil.java | 8 +- .../threerings/media/sprite/ImageSprite.java | 270 ++++++++++++++ .../threerings/media/sprite/LabelSprite.java | 59 ++++ .../com/threerings/media/sprite/Sprite.java | 333 +++++------------- .../media/sprite/SpriteManager.java | 33 +- .../threerings/miso/client/IsoSceneView.java | 4 +- .../com/threerings/miso/client/TilePath.java | 7 +- .../threerings/miso/client/util/IsoUtil.java | 32 +- 12 files changed, 500 insertions(+), 294 deletions(-) create mode 100644 src/java/com/threerings/media/sprite/ImageSprite.java create mode 100644 src/java/com/threerings/media/sprite/LabelSprite.java diff --git a/src/java/com/threerings/cast/CharacterManager.java b/src/java/com/threerings/cast/CharacterManager.java index 649946b3a..f0f68c65c 100644 --- a/src/java/com/threerings/cast/CharacterManager.java +++ b/src/java/com/threerings/cast/CharacterManager.java @@ -1,5 +1,5 @@ // -// $Id: CharacterManager.java,v 1.15 2002/03/08 07:50:32 mdb Exp $ +// $Id: CharacterManager.java,v 1.16 2002/03/16 03:15:04 shaper Exp $ package com.threerings.cast; @@ -10,7 +10,8 @@ import java.util.HashMap; import com.samskivert.util.Tuple; import com.threerings.media.sprite.MultiFrameImage; -import com.threerings.media.sprite.Sprite; + +import com.threerings.util.DirectionCodes; import com.threerings.cast.Log; import com.threerings.cast.util.TileUtil; @@ -21,6 +22,7 @@ import com.threerings.cast.util.TileUtil; * compositing and caching of composited character animations. */ public class CharacterManager + implements DirectionCodes { /** * Constructs the character manager. @@ -176,7 +178,7 @@ public class CharacterManager CharacterDescriptor descrip, String action) throws NoSuchComponentException { - MultiFrameImage[] frames = new MultiFrameImage[Sprite.DIRECTION_COUNT]; + MultiFrameImage[] frames = new MultiFrameImage[DIRECTION_COUNT]; int[] cids = descrip.getComponentIds(); int ccount = cids.length; diff --git a/src/java/com/threerings/cast/CharacterSprite.java b/src/java/com/threerings/cast/CharacterSprite.java index 8a6b4dda0..1336cd9e7 100644 --- a/src/java/com/threerings/cast/CharacterSprite.java +++ b/src/java/com/threerings/cast/CharacterSprite.java @@ -1,18 +1,18 @@ // -// $Id: CharacterSprite.java,v 1.24 2002/03/15 01:10:25 mdb Exp $ +// $Id: CharacterSprite.java,v 1.25 2002/03/16 03:15:04 shaper Exp $ package com.threerings.cast; import com.threerings.media.sprite.MultiFrameImage; import com.threerings.media.sprite.Path; -import com.threerings.media.sprite.Sprite; +import com.threerings.media.sprite.ImageSprite; /** * A character sprite is a sprite that animates itself while walking * about in a scene. */ -public class CharacterSprite - extends Sprite implements StandardActions +public class CharacterSprite extends ImageSprite + implements StandardActions { /** * Initializes this character sprite with the specified character diff --git a/src/java/com/threerings/cast/builder/SpritePanel.java b/src/java/com/threerings/cast/builder/SpritePanel.java index d04f12c5f..e7e24edb6 100644 --- a/src/java/com/threerings/cast/builder/SpritePanel.java +++ b/src/java/com/threerings/cast/builder/SpritePanel.java @@ -1,5 +1,5 @@ // -// $Id: SpritePanel.java,v 1.11 2002/03/08 07:50:32 mdb Exp $ +// $Id: SpritePanel.java,v 1.12 2002/03/16 03:15:04 shaper Exp $ package com.threerings.cast.builder; @@ -9,11 +9,14 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; +import java.util.List; + import com.threerings.media.animation.AnimatedPanel; import com.threerings.media.animation.AnimationManager; -import com.threerings.media.sprite.Sprite; import com.threerings.media.sprite.SpriteManager; +import com.threerings.util.DirectionCodes; + import com.threerings.cast.Log; import com.threerings.cast.CharacterDescriptor; import com.threerings.cast.CharacterManager; @@ -24,9 +27,8 @@ import com.threerings.cast.StandardActions; * The sprite panel displays a character sprite centered in the panel * suitable for user perusal. */ -public class SpritePanel - extends AnimatedPanel - implements BuilderModelListener +public class SpritePanel extends AnimatedPanel + implements DirectionCodes, BuilderModelListener { /** * Constructs the sprite panel. @@ -47,10 +49,8 @@ public class SpritePanel } // documentation inherited - protected void render (Graphics g) + protected void render (Graphics2D gfx, List invalidRects) { - Graphics2D gfx = (Graphics2D)g; - // clear the background gfx.setColor(Color.lightGray); Dimension d = getSize(); @@ -63,7 +63,7 @@ public class SpritePanel if (_sprite != null) { // render the sprite - _sprite.paint((Graphics2D)g); + _sprite.paint(gfx); } } @@ -100,7 +100,7 @@ public class SpritePanel protected void setSprite (CharacterSprite sprite) { sprite.setActionSequence(StandardActions.STANDING); - sprite.setOrientation(Sprite.WEST); + sprite.setOrientation(WEST); _sprite = sprite; centerSprite(); repaint(); diff --git a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java index f07d2cc77..ba959134b 100644 --- a/src/java/com/threerings/cast/bundle/BundledComponentRepository.java +++ b/src/java/com/threerings/cast/bundle/BundledComponentRepository.java @@ -1,5 +1,5 @@ // -// $Id: BundledComponentRepository.java,v 1.8 2002/03/08 09:35:14 mdb Exp $ +// $Id: BundledComponentRepository.java,v 1.9 2002/03/16 03:15:04 shaper Exp $ package com.threerings.cast.bundle; @@ -27,12 +27,13 @@ import com.threerings.resource.ResourceManager; import com.threerings.media.ImageManager; import com.threerings.media.sprite.MultiFrameImage; -import com.threerings.media.sprite.Sprite; import com.threerings.media.tile.ImageProvider; import com.threerings.media.tile.TileSet; import com.threerings.media.tile.NoSuchTileException; +import com.threerings.util.DirectionCodes; + import com.threerings.cast.CharacterComponent; import com.threerings.cast.ComponentClass; import com.threerings.cast.ComponentRepository; @@ -47,7 +48,7 @@ import com.threerings.cast.NoSuchComponentException; * @see ResourceManager */ public class BundledComponentRepository - implements ComponentRepository + implements DirectionCodes, ComponentRepository { /** * Constructs a repository which will obtain its resource set from the @@ -271,8 +272,7 @@ public class BundledComponentRepository fset.setImageProvider(this); // and create the necessary multiframe image instances - MultiFrameImage[] frames = - new MultiFrameImage[Sprite.DIRECTION_COUNT]; + MultiFrameImage[] frames = new MultiFrameImage[DIRECTION_COUNT]; for (int i = 0; i < frames.length; i++) { frames[i] = new TileSetFrameImage(fset, i); } @@ -310,7 +310,7 @@ public class BundledComponentRepository // documentation inherited public int getFrameCount () { - return _set.getTileCount() / Sprite.DIRECTION_COUNT; + return _set.getTileCount() / DIRECTION_COUNT; } // documentation inherited diff --git a/src/java/com/threerings/cast/util/TileUtil.java b/src/java/com/threerings/cast/util/TileUtil.java index 87e06d05d..6fe5d6eab 100644 --- a/src/java/com/threerings/cast/util/TileUtil.java +++ b/src/java/com/threerings/cast/util/TileUtil.java @@ -1,5 +1,5 @@ // -// $Id: TileUtil.java,v 1.11 2002/03/10 22:31:21 mdb Exp $ +// $Id: TileUtil.java,v 1.12 2002/03/16 03:15:05 shaper Exp $ package com.threerings.cast.util; @@ -8,9 +8,10 @@ import java.awt.Image; import java.awt.image.BufferedImage; import com.threerings.media.sprite.MultiFrameImage; -import com.threerings.media.sprite.Sprite; import com.threerings.media.util.ImageUtil; +import com.threerings.util.DirectionCodes; + import com.threerings.cast.Log; import com.threerings.cast.Colorization; @@ -18,6 +19,7 @@ import com.threerings.cast.Colorization; * Miscellaneous tile-related utility functions. */ public class TileUtil + implements DirectionCodes { /** * Renders each of the given src component frames into @@ -33,7 +35,7 @@ public class TileUtil MultiFrameImage[] dest, MultiFrameImage[] src, Colorization[] zations) { - for (int orient = 0; orient < Sprite.DIRECTION_COUNT; orient++) { + for (int orient = 0; orient < DIRECTION_COUNT; orient++) { MultiFrameImage sframes = src[orient]; MultiFrameImage dframes = dest[orient]; diff --git a/src/java/com/threerings/media/sprite/ImageSprite.java b/src/java/com/threerings/media/sprite/ImageSprite.java new file mode 100644 index 000000000..b89eda789 --- /dev/null +++ b/src/java/com/threerings/media/sprite/ImageSprite.java @@ -0,0 +1,270 @@ +// +// $Id: ImageSprite.java,v 1.1 2002/03/16 03:15:05 shaper Exp $ + +package com.threerings.media.sprite; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.threerings.media.Log; + +/** + * Extends the sprite class to support rendering the sprite with one or + * more frames of image animation. Overrides various methods to provide + * correspondingly desirable functionality, e.g., {@link #hitTest} only + * reports a hit if the specified point is within a non-transparent pixel + * for the sprite's current image frame. + */ +public class ImageSprite extends Sprite +{ + /** Default frame rate. */ + public static final int DEFAULT_FRAME_RATE = 15; + + /** Animation mode indicating no animation. */ + public static final int NO_ANIMATION = 0; + + /** Animation mode indicating movement cued animation. */ + public static final int MOVEMENT_CUED = 1; + + /** Animation mode indicating time based animation. */ + public static final int TIME_BASED = 2; + + /** + * Constructs an image sprite without any associated frames and with a + * default initial location of (0, 0). The sprite should + * be populated with a set of frames used to display it via a + * subsequent call to {@link #setFrames}, and its location updated + * with {@link #setLocation}. + */ + public ImageSprite () + { + this(0, 0, null); + } + + /** + * Constructs an image sprite without any associated frames. The + * sprite should be populated with a set of frames used to display it + * via a subsequent call to {@link #setFrames}. + * + * @param x the sprite x-position in pixels. + * @param y the sprite y-position in pixels. + */ + public ImageSprite (int x, int y) + { + this(x, y, null); + } + + /** + * Constructs an image sprite. + * + * @param x the sprite x-position in pixels. + * @param y the sprite y-position in pixels. + * @param frames the multi-frame image used to display the sprite. + */ + public ImageSprite (int x, int y, MultiFrameImage frames) + { + super(x, y); + + // initialize frame animation member data + _frames = frames; + _frameIdx = 0; + _animMode = NO_ANIMATION; + _frameDelay = 1000L/DEFAULT_FRAME_RATE; + } + + // documentation inherited + protected void init (SpriteManager spritemgr) + { + super.init(spritemgr); + + setFrames(_frames); + } + + /** + * Returns true if the sprite's bounds contain the specified point, + * and if there is a non-transparent pixel in the sprite's image at + * the specified point, false if not. + */ + public boolean hitTest (int x, int y) + { + // first check to see that we're in the sprite's bounds and that + // we've got a frame image (if we've got no image, there's nothing + // to be hit) + if (!super.hitTest(x, y) || _frame == null) { + return false; + } + + if (_frame instanceof BufferedImage) { + BufferedImage bimage = (BufferedImage)_frame; + int argb = bimage.getRGB(x - _bounds.x, y - _bounds.y); + int alpha = argb >> 24; + // Log.info("Checking [x=" + x + ", y=" + y + + // ", bounds=" + _bounds + ", " + alpha); + + // it's only a hit if the pixel is non-transparent + return (argb >> 24) != 0; + + } else { + Log.warning("Can't check for transparent pixel " + + "[image=" + _frame + "]."); + return true; + } + } + + /** + * Sets the animation mode for this sprite. The available modes are: + * + * + * + * @param mode the desired animation mode. + */ + public void setAnimationMode (int mode) + { + _animMode = mode; + } + + /** + * Sets the number of frames per second desired for the sprite + * animation. This is only used when the animation mode is + * TIME_BASED. + * + * @param fps the desired frames per second. + */ + public void setFrameRate (int fps) + { + _frameDelay = 1000L/fps; + } + + /** + * Set the image array used to render the sprite. + * + * @param frames the sprite images. + */ + public void setFrames (MultiFrameImage frames) + { + if (frames == null) { + // Log.warning("Someone set up us the null frames! " + + // "[sprite=" + this + "]."); + return; + } + + // start with our old bounds + Rectangle dirty = new Rectangle(_bounds); + + _frames = frames; + _frameIdx %= _frames.getFrameCount(); + _frame = _frames.getFrame(_frameIdx); + + // determine our drawing offsets and rendered rectangle size + if (_frame == null) { + _bounds.width = 0; + _bounds.height = 0; + + } else { + _bounds.width = _frame.getWidth(null); + _bounds.height = _frame.getHeight(null); + } + + // add our new bounds + dirty.add(_bounds); + + updateRenderOffset(); + updateRenderOrigin(); + invalidate(dirty); + } + + // documentation inherited + public void paint (Graphics2D gfx) + { + if (_frame != null) { + gfx.drawImage(_frame, _bounds.x, _bounds.y, null); + } else { + super.paint(gfx); + } + } + + // documentation inherited + public void tick (long timestamp) + { + // if we have no frames, we're hosulated (to use a Greenwell term) + if (_frames == null) { + return; + } + + int fcount = _frames.getFrameCount(); + boolean moved = false; + + // move the sprite along toward its destination, if any + if (_path != null) { + moved = _path.updatePosition(this, timestamp); + } + + // increment the display image if performing image animation + int nfidx = _frameIdx; + switch (_animMode) { + case NO_ANIMATION: + // nothing doing + break; + + case TIME_BASED: + nfidx = (int)((timestamp/_frameDelay) % fcount); + break; + + case MOVEMENT_CUED: + // update the frame if the sprite moved + if (moved) { + nfidx = (_frameIdx + 1) % fcount; + } + break; + } + + // only update the sprite if our frame index changed + if (nfidx != _frameIdx) { + _frameIdx = nfidx; + _frame = _frames.getFrame(_frameIdx); + // dirty our rectangle since we've altered our display image + invalidate(); + } + } + + // documentation inherited + protected void invalidate (Rectangle r) + { + if (_frame != null) { + super.invalidate(r); + } + } + + // documentation inherited + protected void toString (StringBuffer buf) + { + super.toString(buf); + buf.append(", fidx=").append(_frameIdx); + } + + /** The images used to render the sprite. */ + protected MultiFrameImage _frames; + + /** The current frame being rendered. */ + protected Image _frame; + + /** The current frame index to render. */ + protected int _frameIdx; + + /** What type of animation is desired for this sprite. */ + protected int _animMode; + + /** For how many milliseconds to display an animation frame. */ + protected long _frameDelay; +} diff --git a/src/java/com/threerings/media/sprite/LabelSprite.java b/src/java/com/threerings/media/sprite/LabelSprite.java new file mode 100644 index 000000000..f61e80156 --- /dev/null +++ b/src/java/com/threerings/media/sprite/LabelSprite.java @@ -0,0 +1,59 @@ +// +// $Id: LabelSprite.java,v 1.1 2002/03/16 03:15:05 shaper Exp $ + +package com.threerings.media.sprite; + +import java.awt.Dimension; +import java.awt.Graphics2D; + +import com.samskivert.swing.Label; + +import com.threerings.media.Log; + +/** + * A sprite that uses a label to render itself. Assumes that the label + * has been previously laid out (see {@link Label#layout}). The label + * should not be altered after the sprite is created. + */ +public class LabelSprite extends Sprite +{ + /** + * Constructs a label sprite that renders itself with the specified + * label. + */ + public LabelSprite (Label label) + { + this(0, 0, label); + } + + /** + * Constructs a label sprite with the given initial position that + * renders itself with the specified label. + */ + public LabelSprite (int x, int y, Label label) + { + super(x, y); + + _label = label; + } + + // documentation inherited + protected void init (SpriteManager spritemgr) + { + super.init(spritemgr); + + // size the bounds to fit our label + Dimension size = _label.getSize(); + _bounds.width = size.width; + _bounds.height = size.height; + } + + // documentation inherited + public void paint (Graphics2D gfx) + { + _label.render(gfx, _bounds.x, _bounds.y); + } + + /** The label associated with this sprite. */ + protected Label _label; +} diff --git a/src/java/com/threerings/media/sprite/Sprite.java b/src/java/com/threerings/media/sprite/Sprite.java index 0872870b1..b283d1919 100644 --- a/src/java/com/threerings/media/sprite/Sprite.java +++ b/src/java/com/threerings/media/sprite/Sprite.java @@ -1,70 +1,70 @@ // -// $Id: Sprite.java,v 1.38 2002/03/04 22:47:06 mdb Exp $ +// $Id: Sprite.java,v 1.39 2002/03/16 03:15:05 shaper Exp $ package com.threerings.media.sprite; -import java.awt.*; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; import java.awt.image.BufferedImage; + import java.util.ArrayList; import java.util.Iterator; -import com.threerings.media.Log; import com.threerings.util.DirectionCodes; +import com.threerings.media.Log; + /** * The sprite class represents a single moveable object in an animated - * view. A sprite has a position within the view, and a set of images - * used to render it (perhaps multiple frames for animation). + * view. A sprite has a position and orientation within the view, and can + * be moved along a path. */ -public class Sprite implements DirectionCodes +public abstract class Sprite + implements DirectionCodes { - /** Default frame rate. */ - public static final int DEFAULT_FRAME_RATE = 15; - - /** Animation mode indicating no animation. */ - public static final int NO_ANIMATION = 0; - - /** Animation mode indicating movement cued animation. */ - public static final int MOVEMENT_CUED = 1; - - /** Animation mode indicating time based animation. */ - public static final int TIME_BASED = 2; - /** - * Constructs a sprite without any associated frames and with a - * default initial location of (0, 0). The sprite should - * be populated with a set of frames used to display it via a - * subsequent call to {@link #setFrames}, and its location can be - * updated with {@link #setLocation}. + * Constructs a sprite with a default initial location of (0, + * 0). */ public Sprite () { - init(0, 0, null); + this(0, 0); } /** - * Constructs a sprite without any associated frames. The sprite - * should be populated with a set of frames used to display it via a - * subsequent call to {@link #setFrames}. + * Constructs a sprite initially positioned at the specified location. * * @param x the sprite x-position in pixels. * @param y the sprite y-position in pixels. */ public Sprite (int x, int y) { - init(x, y, null); + _x = x; + _y = y; } /** - * Constructs a sprite. + * Called by the sprite manager to initialize the sprite when a sprite + * is added to said manager for management. * - * @param x the sprite x-position in pixels. - * @param y the sprite y-position in pixels. - * @param frames the multi-frame image used to display the sprite. + * @param spritemgr the sprite manager. */ - public Sprite (int x, int y, MultiFrameImage frames) + protected void init (SpriteManager spritemgr) { - init(x, y, frames); + _spritemgr = spritemgr; + + updateRenderOrigin(); + } + + /** + * Called by the sprite manager after the sprite is removed from + * service. Derived classes may override this method but should be + * sure to call super.shutdown(). + */ + protected void shutdown () + { + _spritemgr = null; } /** @@ -107,6 +107,50 @@ public class Sprite implements DirectionCodes return _bounds; } + /** + * Sprites have an orientation in one of the eight cardinal + * directions: NORTH, NORTHEAST, etc. + * Derived classes can choose to override this member function and + * select a different set of images based on their orientation, or + * they can ignore the orientation information. + * + * @see DirectionCodes + */ + public void setOrientation (int orient) + { + _orient = orient; + } + + /** + * Returns the sprite's orientation as one of the eight cardinal + * directions: NORTH, NORTHEAST, etc. + * + * @see DirectionCodes + */ + public int getOrientation () + { + return _orient; + } + + /** + * Returns the render order of this sprite. + */ + public int getRenderOrder () + { + return _renderOrder; + } + + /** + * Sets the render order associated with this animation. Sprites can + * be rendered in two layers; those with negative render order and + * those with positive render order. Someday sprites will be rendered + * in each layer according to render order. + */ + public void setRenderOrder (int value) + { + _renderOrder = value; + } + /** * Moves the sprite to the specified location. * @@ -123,7 +167,7 @@ public class Sprite implements DirectionCodes _y = y; // we need to update our draw position which is based on the - // size of our current frame + // size of our current bounds updateRenderOrigin(); if (dirty.intersects(_bounds)) { @@ -140,57 +184,6 @@ public class Sprite implements DirectionCodes invalidate(dirty); } - /** - * Sprites have an orientation in one of the eight cardinal - * directions: NORTH, NORTHEAST, etc. Sprite - * derived classes can choose to override this member function and - * select a different set of images based on their orientation, or - * they can ignore the orientation information. - */ - public void setOrientation (int orient) - { - _orient = orient; - } - - /** - * Returns the sprite's orientation as one of the eight cardinal - * directions: NORTH, NORTHEAST, etc. - */ - public int getOrientation () - { - return _orient; - } - - /** - * Initialize the sprite object with its variegated parameters. - */ - protected void init (int x, int y, MultiFrameImage frames) - { - _x = x; - _y = y; - - updateRenderOrigin(); - - // initialize frame animation member data - _frameIdx = 0; - _animMode = NO_ANIMATION; - _frameDelay = 1000L/DEFAULT_FRAME_RATE; - - setFrames(frames); - invalidate(); - } - - /** - * Called by the sprite manager when a sprite is added to said manager - * for management. - * - * @param mgr the sprite manager. - */ - protected void setSpriteManager (SpriteManager mgr) - { - _spritemgr = mgr; - } - /** * Paint the sprite to the specified graphics context. * @@ -198,11 +191,7 @@ public class Sprite implements DirectionCodes */ public void paint (Graphics2D gfx) { - if (_frame != null) { - gfx.drawImage(_frame, _bounds.x, _bounds.y, null); - } else { - gfx.draw(_bounds); - } + gfx.draw(_bounds); } /** @@ -228,31 +217,11 @@ public class Sprite implements DirectionCodes /** * Returns true if the sprite's bounds contain the specified point, - * and if there is a non-transparent pixel in the sprite's image at - * the specified point, false if not. + * false if not. */ public boolean hitTest (int x, int y) { - // first check to see that we're in the sprite's bounds and that - // we've got a frame image (if we've got no image, there's nothing - // to be hit) - if (!_bounds.contains(x, y) || _frame == null) { - return false; - } - - if (_frame instanceof BufferedImage) { - BufferedImage bimage = (BufferedImage)_frame; - int argb = bimage.getRGB(x - _bounds.x, y - _bounds.y); - int alpha = argb >> 24; - // Log.info("Checking [x=" + x + ", y=" + y + ", bounds=" + _bounds + ", " + alpha); - // it's only a hit if the pixel is non-transparent - return (argb >> 24) != 0; - - } else { - Log.warning("Can't check for transparent pixel " + - "[image=" + _frame + "]."); - return true; - } + return _bounds.contains(x, y); } /** @@ -273,74 +242,6 @@ public class Sprite implements DirectionCodes return shape.intersects(_bounds); } - /** - * Sets the animation mode for this sprite. The available modes are: - * - * - * - * @param mode the desired animation mode. - */ - public void setAnimationMode (int mode) - { - _animMode = mode; - } - - /** - * Sets the number of frames per second desired for the sprite - * animation. This is only used when the animation mode is - * TIME_BASED. - * - * @param fps the desired frames per second. - */ - public void setFrameRate (int fps) - { - _frameDelay = 1000L/fps; - } - - /** - * Set the image array used to render the sprite. - * - * @param frames the sprite images. - */ - public void setFrames (MultiFrameImage frames) - { - if (frames == null) { - // Log.warning("Someone set up us the null frames! " + - // "[sprite=" + this + "]."); - return; - } - - // start with our old bounds - Rectangle dirty = new Rectangle(_bounds); - - _frames = frames; - _frameIdx %= _frames.getFrameCount(); - _frame = _frames.getFrame(_frameIdx); - - // determine our drawing offsets and rendered rectangle size - if (_frame == null) { - _bounds.width = 0; - _bounds.height = 0; - - } else { - _bounds.width = _frame.getWidth(null); - _bounds.height = _frame.getHeight(null); - } - - // add our new bounds - dirty.add(_bounds); - - updateRenderOffset(); - updateRenderOrigin(); - invalidate(dirty); - } - /** * Returns true if this sprite is currently following a path, false if * it is not. @@ -396,7 +297,6 @@ public class Sprite implements DirectionCodes _path = null; // inform observers that we've finished our path notifyObservers(new PathCompletedEvent(this, oldpath)); - } /** @@ -416,10 +316,6 @@ public class Sprite implements DirectionCodes */ protected void invalidate (Rectangle r) { - if (_frame == null) { - return; - } - if (_spritemgr != null) { _spritemgr.addDirtyRect((r != null) ? r : new Rectangle(_bounds)); @@ -439,44 +335,9 @@ public class Sprite implements DirectionCodes */ public void tick (long timestamp) { - // if we have no frames, we're hosulated (to use a Greenwell term) - if (_frames == null) { - return; - } - - int fcount = _frames.getFrameCount(); - boolean moved = false; - - // move the sprite along toward its destination, if any + // if we've a path, move the sprite along toward its destination if (_path != null) { - moved = _path.updatePosition(this, timestamp); - } - - // increment the display image if performing image animation - int nfidx = _frameIdx; - switch (_animMode) { - case NO_ANIMATION: - // nothing doing - break; - - case TIME_BASED: - nfidx = (int)((timestamp/_frameDelay) % fcount); - break; - - case MOVEMENT_CUED: - // update the frame if the sprite moved - if (moved) { - nfidx = (_frameIdx + 1) % fcount; - } - break; - } - - // only update the sprite if our frame index changed - if (nfidx != _frameIdx) { - _frameIdx = nfidx; - _frame = _frames.getFrame(_frameIdx); - // dirty our rectangle since we've altered our display image - invalidate(); + _path.updatePosition(this, timestamp); } } @@ -544,8 +405,7 @@ public class Sprite implements DirectionCodes */ public String toString () { - StringBuffer buf = new StringBuffer(); - buf.append("["); + StringBuffer buf = new StringBuffer("["); toString(buf); return buf.append("]").toString(); } @@ -559,21 +419,8 @@ public class Sprite implements DirectionCodes { buf.append("x=").append(_x); buf.append(", y=").append(_y); - buf.append(", fidx=").append(_frameIdx); } - /** The images used to render the sprite. */ - protected MultiFrameImage _frames; - - /** The current frame being rendered. */ - protected Image _frame; - - /** The current frame index to render. */ - protected int _frameIdx; - - /** The orientation of this sprite. */ - protected int _orient = NONE; - /** The location of the sprite in pixel coordinates. */ protected int _x, _y; @@ -583,15 +430,15 @@ public class Sprite implements DirectionCodes /** Our rendered bounds in pixel coordinates. */ protected Rectangle _bounds = new Rectangle(); - /** What type of animation is desired for this sprite. */ - protected int _animMode; - - /** For how many milliseconds to display an animation frame. */ - protected long _frameDelay; + /** The orientation of this sprite. */ + protected int _orient = NONE; /** When moving, the path the sprite is traversing. */ protected Path _path; + /** The render order of this sprite. */ + protected int _renderOrder; + /** The sprite observers observing this sprite. */ protected ArrayList _observers; diff --git a/src/java/com/threerings/media/sprite/SpriteManager.java b/src/java/com/threerings/media/sprite/SpriteManager.java index 2048d7515..fd75d1401 100644 --- a/src/java/com/threerings/media/sprite/SpriteManager.java +++ b/src/java/com/threerings/media/sprite/SpriteManager.java @@ -1,5 +1,5 @@ // -// $Id: SpriteManager.java,v 1.26 2002/02/28 23:25:15 mdb Exp $ +// $Id: SpriteManager.java,v 1.27 2002/03/16 03:15:05 shaper Exp $ package com.threerings.media.sprite; @@ -25,6 +25,15 @@ import com.threerings.media.Log; */ public class SpriteManager { + /** Constant for the front layer of sprites. */ + public static final int FRONT = 0; + + /** Constant for the back layer of sprites. */ + public static final int BACK = 1; + + /** Constant for all layers of sprites. */ + public static final int ALL = 2; + /** * Construct and initialize the SpriteManager object. */ @@ -129,8 +138,8 @@ public class SpriteManager */ public void addSprite (Sprite sprite) { - // let the sprite know about us - sprite.setSpriteManager(this); + // initialize the sprite + sprite.init(this); // add the sprite to our list _sprites.add(sprite); // and invalidate the sprite's original position @@ -150,17 +159,21 @@ public class SpriteManager // remove the sprite from our list _sprites.remove(sprite); // clear out our manager reference - sprite.setSpriteManager(null); + sprite.shutdown(); } /** - * Render the sprites residing within the given shape to the given - * graphics context. + * Render the sprites residing within the given shape and layer to the + * given graphics context. * * @param gfx the graphics context. * @param bounds the bounding shape. + * @param layer the layer to render; one of {@link #FRONT}, {@link + * #BACK}, or {@link #ALL}. The front layer contains all sprites with + * a positive render order; the back layer contains all sprites with a + * negative render order; all, both. */ - public void renderSprites (Graphics2D gfx, Shape bounds) + public void renderSprites (Graphics2D gfx, Shape bounds, int layer) { // TODO: optimize to store sprites based on quadrants they're // in (or somesuch), and sorted, so that we can more quickly @@ -169,7 +182,11 @@ public class SpriteManager int size = _sprites.size(); for (int ii = 0; ii < size; ii++) { Sprite sprite = (Sprite)_sprites.get(ii); - if (sprite.intersects(bounds)) { + int order = sprite.getRenderOrder(); + if (((layer == ALL) || + (layer == FRONT && order >= 0) || + (layer == BACK && order < 0)) && + sprite.intersects(bounds)) { sprite.paint(gfx); } } diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index 865ec9440..0a49a53c5 100644 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ b/src/java/com/threerings/miso/client/IsoSceneView.java @@ -1,5 +1,5 @@ // -// $Id: IsoSceneView.java,v 1.101 2002/02/19 19:57:46 mdb Exp $ +// $Id: IsoSceneView.java,v 1.102 2002/03/16 03:15:05 shaper Exp $ package com.threerings.miso.scene; @@ -188,7 +188,7 @@ public class IsoSceneView implements SceneView // drawDirtyRegions(gfx); // render any animations - _animmgr.renderAnimations(gfx); + _animmgr.renderAnimations(gfx, AnimationManager.ALL); // clear out the dirty tiles and rectangles clearDirtyRegions(); diff --git a/src/java/com/threerings/miso/client/TilePath.java b/src/java/com/threerings/miso/client/TilePath.java index 6714f8994..c18df8d19 100644 --- a/src/java/com/threerings/miso/client/TilePath.java +++ b/src/java/com/threerings/miso/client/TilePath.java @@ -1,5 +1,5 @@ // -// $Id: TilePath.java,v 1.3 2001/12/17 03:33:18 mdb Exp $ +// $Id: TilePath.java,v 1.4 2002/03/16 03:15:05 shaper Exp $ package com.threerings.miso.scene; @@ -8,6 +8,8 @@ import java.util.List; import com.threerings.media.sprite.*; +import com.threerings.util.DirectionCodes; + import com.threerings.miso.Log; import com.threerings.miso.scene.util.IsoUtil; @@ -18,6 +20,7 @@ import com.threerings.miso.scene.util.IsoUtil; * tile coordinates are updated as the path is traversed. */ public class TilePath extends LineSegmentPath + implements DirectionCodes { /** * Constructs a tile path. @@ -108,7 +111,7 @@ public class TilePath extends LineSegmentPath // add the starting path node int stx = sprite.getTileX(), sty = sprite.getTileY(); int sx = sprite.getX(), sy = sprite.getY(); - addNode(stx, sty, sx, sy, Sprite.NORTH); + addNode(stx, sty, sx, sy, NORTH); // TODO: make more visually appealing path segments from start // to second tile, and penultimate to ultimate tile. diff --git a/src/java/com/threerings/miso/client/util/IsoUtil.java b/src/java/com/threerings/miso/client/util/IsoUtil.java index cc505278f..931896740 100644 --- a/src/java/com/threerings/miso/client/util/IsoUtil.java +++ b/src/java/com/threerings/miso/client/util/IsoUtil.java @@ -1,9 +1,11 @@ // -// $Id: IsoUtil.java,v 1.21 2002/02/19 04:02:50 mdb Exp $ +// $Id: IsoUtil.java,v 1.22 2002/03/16 03:15:06 shaper Exp $ package com.threerings.miso.scene.util; -import java.awt.*; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; import com.samskivert.swing.SmartPolygon; @@ -11,14 +13,18 @@ import com.threerings.media.sprite.Sprite; import com.threerings.media.tile.ObjectTile; import com.threerings.media.util.MathUtil; +import com.threerings.util.DirectionCodes; + import com.threerings.miso.Log; -import com.threerings.miso.scene.*; +import com.threerings.miso.scene.IsoSceneViewModel; +import com.threerings.miso.scene.MisoCharacterSprite; /** * The IsoUtil class is a holding place for miscellaneous * isometric-display-related utility routines. */ public class IsoUtil + implements DirectionCodes { /** * Sets the given character sprite's tile and fine coordinate @@ -190,7 +196,7 @@ public class IsoUtil // compare tile coordinates to determine direction int dir = getIsoDirection(tax, tay, tbx, tby); - if (dir != Sprite.NONE) return dir; + if (dir != DirectionCodes.NONE) return dir; // destination point is in the same tile as the // origination point, so consider fine coordinates @@ -206,7 +212,7 @@ public class IsoUtil dir = getIsoDirection(fax, fay, fbx, fby); // arbitrarily return southwest if fine coords were also equivalent - return (dir == -1) ? Sprite.SOUTHWEST : dir; + return (dir == -1) ? SOUTHWEST : dir; } /** @@ -222,28 +228,28 @@ public class IsoUtil * @param by the y-position of point B. * * @return the direction specified as one of the Sprite - * class's direction constants, or Sprite.NONE - * if point B is equivalent to point A. + * class's direction constants, or DirectionCodes.NONE if + * point B is equivalent to point A. */ public static int getIsoDirection (int ax, int ay, int bx, int by) { if (bx > ax) { if (by == ay) { - return Sprite.SOUTH; + return SOUTH; } - return (by < ay) ? Sprite.SOUTHEAST : Sprite.SOUTHWEST; + return (by < ay) ? SOUTHEAST : SOUTHWEST; } else if (bx == ax) { if (by == ay) { - return Sprite.NONE; + return DirectionCodes.NONE; } - return (by < ay) ? Sprite.EAST : Sprite.WEST; + return (by < ay) ? EAST : WEST; } else { // bx < ax if (by == ay) { - return Sprite.NORTH; + return NORTH; } - return (by < ay) ? Sprite.NORTHEAST : Sprite.NORTHWEST; + return (by < ay) ? NORTHEAST : NORTHWEST; } }