From 4f92224a8fa1c6920c1228b0645b0f64764fd9ae Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Wed, 5 Sep 2001 00:40:33 +0000 Subject: [PATCH] Minor comment re-formatting. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@327 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/media/sprite/Sprite.java | 112 ++++++++++++-- .../media/sprite/SpriteManager.java | 137 +++++++++++++++++- .../media/sprite/SpriteObserver.java | 42 ++++++ .../com/threerings/media/util/PathNode.java | 7 +- 4 files changed, 279 insertions(+), 19 deletions(-) create mode 100644 src/java/com/threerings/media/sprite/SpriteObserver.java diff --git a/src/java/com/threerings/media/sprite/Sprite.java b/src/java/com/threerings/media/sprite/Sprite.java index a37db608b..230ce1fb4 100644 --- a/src/java/com/threerings/media/sprite/Sprite.java +++ b/src/java/com/threerings/media/sprite/Sprite.java @@ -1,18 +1,19 @@ // -// $Id: Sprite.java,v 1.16 2001/08/22 02:14:57 mdb Exp $ +// $Id: Sprite.java,v 1.17 2001/09/05 00:40:33 shaper Exp $ package com.threerings.media.sprite; import java.awt.*; +import java.util.ArrayList; import java.util.Iterator; import com.threerings.media.Log; import com.threerings.media.util.MathUtil; /** - * The Sprite class represents a single moveable object - * within a scene. A sprite has a position within the scene, and a set of - * images used to render it (perhaps multiple frames for animation). + * 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). */ public class Sprite { @@ -31,7 +32,7 @@ public class Sprite /** * Construct a sprite object without any associated frames. The sprite * should be populated with a set of frames used to display it via a - * subsequent call to setFrames(). + * subsequent call to {@link #setFrames}. * * @param x the sprite x-position in pixels. * @param y the sprite y-position in pixels. @@ -57,9 +58,45 @@ public class Sprite return _y; } + /** + * Returns the sprite's width in pixels. + */ + public int getWidth () + { + return _rbounds.width; + } + + /** + * Returns the sprite's height in pixels. + */ + public int getHeight () + { + return _rbounds.height; + } + + /** + * Returns the sprite's rendered bounds in pixels. + */ + public Rectangle getBounds () + { + return _rbounds; + } + + /** + * Return whether the sprite is currently moving (following an + * assigned path.) + */ + public boolean isMoving () + { + return (_dest != null); + } + /** * Moves the sprite to the specified location. The location specified * will be used as the center of the bottom edge of the sprite. + * + * @param x the x-position in pixels. + * @param y the y-position in pixels. */ public void setLocation (int x, int y) { @@ -100,6 +137,8 @@ public class Sprite /** * 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) { @@ -208,7 +247,7 @@ public class Sprite } /** - * Set the sprite's velocity when walking. + * Set the sprite's velocity when following a path. * * @param vx the x-axis velocity. * @param vy the y-axis velocity. @@ -225,7 +264,7 @@ public class Sprite public void stop () { // TODO: make sure we come to a stop on a full coordinate, - // even in the case where we aborted a path walk mid-traversal. + // even in the case where we aborted a path mid-traversal. _dest = null; _path = null; _fullpath = null; @@ -243,8 +282,9 @@ public class Sprite { // make sure following the path is a sensible thing to do if (path == null || path.size() < 2) { - // halt movement if we're walking since, regardless of its - // reasonableness, we've been asked to follow a new path + // halt any previously existing movement since, regardless + // of its reasonableness, we've been asked to follow a new + // path stop(); return; } @@ -268,12 +308,19 @@ public class Sprite */ protected void moveAlongPath () { - // if no more nodes remain, clear out our path and bail if (!_path.hasNext()) { + // inform observers that we've finished our path + notifyObservers(SpriteObserver.FINISHED_PATH, _path); + // clear out our path and bail stop(); return; } + if (_dest != null) { + // inform observers that we've finished a path node + notifyObservers(SpriteObserver.FINISHED_PATH_NODE, _dest); + } + // grab the next node in our path _dest = (PathNode)_path.next(); @@ -387,6 +434,46 @@ public class Sprite _rbounds.y = _y + _ryoff; } + /** + * Add a sprite observer to observe this sprite's events. + * + * @param obs the sprite observer. + */ + public void addSpriteObserver (SpriteObserver obs) + { + // create the observer list if it doesn't yet exist + if (_observers == null) { + _observers = new ArrayList(); + } + + // make sure each observer observes only once + if (_observers.contains(obs)) { + Log.info("Attempt to observe sprite already observing " + + "[sprite=" + this + ", obs=" + obs + "]."); + return; + } + + // add the observer + _observers.add(obs); + } + + /** + * Inform all sprite observers of a sprite event. + * + * @param eventCode the type of sprite event. + * @param arg the argument associated with the event. + */ + protected void notifyObservers (int eventCode, Object arg) + { + if (_observers == null) return; + + int size = _observers.size(); + for (int ii = 0; ii < size; ii++) { + SpriteObserver obs = (SpriteObserver)_observers.get(ii); + obs.spriteChanged(this, eventCode, arg); + } + } + /** * Return a string representation of the sprite. */ @@ -441,9 +528,12 @@ public class Sprite /** When moving, the full path the sprite is traversing. */ protected Path _fullpath; - /** The sprite velocity when walking. */ + /** The sprite velocity when moving. */ protected Point _vel; + /** The sprite observers observing this sprite. */ + protected ArrayList _observers; + /** The sprite manager. */ protected SpriteManager _spritemgr; } diff --git a/src/java/com/threerings/media/sprite/SpriteManager.java b/src/java/com/threerings/media/sprite/SpriteManager.java index 32779365e..9f37c8b8f 100644 --- a/src/java/com/threerings/media/sprite/SpriteManager.java +++ b/src/java/com/threerings/media/sprite/SpriteManager.java @@ -1,11 +1,12 @@ // -// $Id: SpriteManager.java,v 1.10 2001/08/22 02:14:57 mdb Exp $ +// $Id: SpriteManager.java,v 1.11 2001/09/05 00:40:33 shaper Exp $ package com.threerings.media.sprite; import java.awt.*; -import java.util.ArrayList; +import java.util.*; +import com.samskivert.util.Tuple; import com.threerings.media.Log; /** @@ -147,23 +148,151 @@ public class SpriteManager } } + /** + * Called periodically by the tick tasks put on the AWT event + * queue by the {@link AnimationManager}. Handles moving about of + * sprites and reporting of sprite collisions. + */ + public void tick () + { + // tick all sprites + tickSprites(); + + // re-sort the sprite list to account for potential new positions + sortSprites(); + + // notify sprite observers of any collisions + handleCollisions(); + } + /** * Call tick() on all sprite objects to give them a * chance to move themselves about, change their display image, * and so forth. */ - public void tick () + protected void tickSprites () { int size = _sprites.size(); - for (int ii = 0; ii < size; ii++) { + for (int ii = 0; ii < size; ii++) { Sprite sprite = (Sprite)_sprites.get(ii); sprite.tick(); } + } + + /** + * Sort the sprite list in order of ascending x-coordinate. + */ + protected void sortSprites () + { + Object[] sprites = new Sprite[_sprites.size()]; + _sprites.toArray(sprites); + Arrays.sort(sprites, SPRITE_COMP); + _sprites.clear(); + for (int ii = 0; ii < sprites.length; ii++) { + _sprites.add(sprites[ii]); + } } + /** + * Check all sprites for collisions with others and inform any + * sprite observers. + */ + protected void handleCollisions () + { + // gather a list of all sprite collisions + int size = _sprites.size(); + ArrayList collisions = new ArrayList(); + for (int ii = 0; ii < size; ii++) { + Sprite sprite = (Sprite)_sprites.get(ii); + checkCollisions(ii, size, sprite, collisions); + } + + // observers are notified of sprite collisions after all + // collision-detection is performed so that modifications to + // the sprite, e.g. location or velocity, won't impact the + // validity of our checking. + int csize = collisions.size(); + for (int ii = 0; ii < csize; ii++) { + Tuple tup = (Tuple)collisions.get(ii); + Sprite a = (Sprite)tup.left, b = (Sprite)tup.right; + + // inform sprite observers for both sprites of the collision + a.notifyObservers(SpriteObserver.COLLIDED_SPRITE, b); + b.notifyObservers(SpriteObserver.COLLIDED_SPRITE, a); + } + } + + /** + * Check a sprite for collision with any other sprites in the + * sprite list. The sprites involved in a collision are added to + * the collisions list of {@link Tuple} objects. + * + * @param idx the starting sprite index. + * @param size the total number of sprites. + * @param sprite the sprite to check against other sprites for + * collisions. + * @param collisions the list of collisions gathered so far. + */ + protected void checkCollisions (int idx, int size, Sprite sprite, + ArrayList collisions) + { + // TODO: make this handle quickly moving objects that may pass + // through each other. + + // if we're the last sprite we know we've already handled any + // collisions + if (idx == (size - 1)) { + return; + } + + // calculate the x-position of the right edge of the sprite + // we're checking for collisions + Rectangle bounds = sprite.getBounds(); + int edgeX = bounds.x + bounds.width; + + for (int ii = (idx + 1); ii < size; ii++) { + Sprite other = (Sprite)_sprites.get(ii); + Rectangle obounds = other.getBounds(); + +// Log.info("Checking collision [bounds=" + bounds + +// ", obounds=" + obounds + "]."); + + if (obounds.x > edgeX) { + // since sprites are stored in the list sorted by + // ascending x-position, we know this sprite and any + // other sprites farther on in the list can't possibly + // intersect with the sprite we're checking, so we're + // done. + return; + } + + if (obounds.intersects(bounds)) { + collisions.add(new Tuple(sprite, other)); + } + } + } + + /** The comparator used to sort sprites by horizontal position. */ + protected static final Comparator SPRITE_COMP = new SpriteComparator(); + /** The sprite objects we're managing. */ protected ArrayList _sprites; /** The dirty rectangles created by sprites. */ protected DirtyRectList _dirty; + + protected static class SpriteComparator implements Comparator + { + public int compare (Object o1, Object o2) + { + Sprite s1 = (Sprite)o1; + Sprite s2 = (Sprite)o2; + return (s2.getX() - s1.getX()); + } + + public boolean equals (Object obj) + { + return (obj == this); + } + } } diff --git a/src/java/com/threerings/media/sprite/SpriteObserver.java b/src/java/com/threerings/media/sprite/SpriteObserver.java new file mode 100644 index 000000000..4b9db6842 --- /dev/null +++ b/src/java/com/threerings/media/sprite/SpriteObserver.java @@ -0,0 +1,42 @@ +// +// $Id: SpriteObserver.java,v 1.1 2001/09/05 00:40:33 shaper Exp $ + +package com.threerings.media.sprite; + +/** + * An interface to be implemented by classes that would like to + * observe a sprite and be notified of meaningful events as it, and + * any other sprites, move about. + */ +public interface SpriteObserver +{ + /** + * This method is called by the {@link SpriteManager} when + * something interesting is accomplished by or happens to the + * sprite. + * + * @param sprite the involved sprite. + * @param eventCode the type of sprite event. + * @param arg the argument associated with the event. + */ + public void spriteChanged (Sprite sprite, int eventCode, Object arg); + + /** + * Event code noting that the sprite completed a path node. The + * argument to the event is the {@link PathNode} completed. + */ + public static final int FINISHED_PATH_NODE = 0; + + /** + * Event code noting that the sprite completed its entire path. + * The argument to the event is the {@link Path} completed. + */ + public static final int FINISHED_PATH = 1; + + /** + * Event code noting that the sprite collided with another + * sprite. The argument to the event is the {@link Sprite} the + * observed sprite collided with. + */ + public static final int COLLIDED_SPRITE = 2; +} diff --git a/src/java/com/threerings/media/util/PathNode.java b/src/java/com/threerings/media/util/PathNode.java index a121826c0..22800c4cd 100644 --- a/src/java/com/threerings/media/util/PathNode.java +++ b/src/java/com/threerings/media/util/PathNode.java @@ -1,13 +1,12 @@ // -// $Id: PathNode.java,v 1.4 2001/08/14 22:54:45 mdb Exp $ +// $Id: PathNode.java,v 1.5 2001/09/05 00:40:33 shaper Exp $ package com.threerings.media.sprite; import java.awt.Point; /** - * The PathNode is a single destination point in a - * Path. + * A path node is a single destination point in a {@link Path}. */ public class PathNode { @@ -18,7 +17,7 @@ public class PathNode public int dir; /** - * Construct a PathNode object. + * Construct a path node object. * * @param x the node x-position. * @param y the node y-position.