Behold, Nenya, Ring of Water and repository for our media and animation related
goodies, both Java 2D and LWJGL/JME 3D. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@1 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -0,0 +1,437 @@
|
||||
//
|
||||
// $Id: AStarPathUtil.java 3413 2005-03-18 01:13:09Z mdb $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.*;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
|
||||
import com.threerings.media.util.MathUtil;
|
||||
|
||||
/**
|
||||
* The <code>AStarPathUtil</code> class provides a facility for
|
||||
* finding a reasonable path between two points in a scene using the
|
||||
* A* search algorithm.
|
||||
*
|
||||
* <p> See the path-finding article on
|
||||
* <a href="http://www.gamasutra.com/features/19990212/sm_01.htm">
|
||||
* Gamasutra</a> for more detailed information.
|
||||
*/
|
||||
public class AStarPathUtil
|
||||
{
|
||||
/**
|
||||
* Provides traversibility information when computing paths.
|
||||
*/
|
||||
public static interface TraversalPred
|
||||
{
|
||||
/**
|
||||
* Requests to know if the specified traverser (which was provided
|
||||
* in the call to {@link #getPath}) can traverse the specified
|
||||
* tile coordinate.
|
||||
*/
|
||||
public boolean canTraverse (Object traverser, int x, int y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers all the possible steps the piece in question can take.
|
||||
*/
|
||||
public static class Stepper
|
||||
{
|
||||
public void init (Info info, Node n)
|
||||
{
|
||||
_info = info;
|
||||
_node = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should call {@link #considerStep} in turn on all possible steps
|
||||
* from the specified coordinates. No checking must be done as to
|
||||
* whether the step is legal, that will be handled later. Just
|
||||
* enumerate all possible steps.
|
||||
*/
|
||||
public void considerSteps (int x, int y)
|
||||
{
|
||||
considerStep(x - 1, y - 1, DIAGONAL_COST);
|
||||
considerStep(x, y - 1, ADJACENT_COST);
|
||||
considerStep(x + 1, y - 1, DIAGONAL_COST);
|
||||
considerStep(x - 1, y, ADJACENT_COST);
|
||||
considerStep(x + 1, y, ADJACENT_COST);
|
||||
considerStep(x - 1, y + 1, DIAGONAL_COST);
|
||||
considerStep(x, y + 1, ADJACENT_COST);
|
||||
considerStep(x + 1, y + 1, DIAGONAL_COST);
|
||||
}
|
||||
|
||||
protected void considerStep (int x, int y, int cost)
|
||||
{
|
||||
AStarPathUtil.considerStep(_info, _node, x, y, cost);
|
||||
}
|
||||
|
||||
protected Info _info;
|
||||
protected Node _node;
|
||||
}
|
||||
|
||||
/** The standard cost to move between nodes. */
|
||||
public static final int ADJACENT_COST = 10;
|
||||
|
||||
/** The cost to move diagonally. */
|
||||
public static final int DIAGONAL_COST = (int)Math.sqrt(
|
||||
(ADJACENT_COST * ADJACENT_COST) * 2);
|
||||
|
||||
/**
|
||||
* Return a list of <code>Point</code> objects representing a path
|
||||
* from coordinates <code>(ax, by)</code> to <code>(bx, by)</code>,
|
||||
* inclusive, determined by performing an A* search in the given
|
||||
* scene's base tile layer. Assumes the starting and destination nodes
|
||||
* are traversable by the specified traverser.
|
||||
*
|
||||
* @param tpred lets us know what tiles are traversible.
|
||||
* @param stepper enumerates the possible steps.
|
||||
* @param trav the traverser to follow the path.
|
||||
* @param longest the longest allowable path in tile traversals.
|
||||
* @param ax the starting x-position in tile coordinates.
|
||||
* @param ay the starting y-position in tile coordinates.
|
||||
* @param bx the ending x-position in tile coordinates.
|
||||
* @param by the ending y-position in tile coordinates.
|
||||
* @param partial if true, a partial path will be returned that gets
|
||||
* us as close as we can to the goal in the event that a complete path
|
||||
* cannot be located.
|
||||
*
|
||||
* @return the list of points in the path.
|
||||
*/
|
||||
public static List getPath (TraversalPred tpred, Stepper stepper,
|
||||
Object trav, int longest, int ax, int ay,
|
||||
int bx, int by, boolean partial)
|
||||
{
|
||||
Info info = new Info(tpred, trav, longest, bx, by);
|
||||
|
||||
// set up the starting node
|
||||
Node s = info.getNode(ax, ay);
|
||||
s.g = 0;
|
||||
s.h = getDistanceEstimate(ax, ay, bx, by);
|
||||
s.f = s.g + s.h;
|
||||
|
||||
// push starting node on the open list
|
||||
info.open.add(s);
|
||||
_considered = 1;
|
||||
|
||||
// track the best path
|
||||
float bestdist = Float.MAX_VALUE;
|
||||
Node bestpath = null;
|
||||
|
||||
// while there are more nodes on the open list
|
||||
while (info.open.size() > 0) {
|
||||
|
||||
// pop the best node so far from open
|
||||
Node n = (Node)info.open.first();
|
||||
info.open.remove(n);
|
||||
|
||||
// if node is a goal node
|
||||
if (n.x == bx && n.y == by) {
|
||||
// construct and return the acceptable path
|
||||
return getNodePath(n);
|
||||
} else if (partial) {
|
||||
float pathdist = MathUtil.distance(n.x, n.y, bx, by);
|
||||
if (pathdist < bestdist) {
|
||||
bestdist = pathdist;
|
||||
bestpath = n;
|
||||
}
|
||||
}
|
||||
|
||||
// consider each successor of the node
|
||||
stepper.init(info, n);
|
||||
stepper.considerSteps(n.x, n.y);
|
||||
|
||||
// push the node on the closed list
|
||||
info.closed.add(n);
|
||||
}
|
||||
|
||||
// return the best path we could find if we were asked to do so
|
||||
if (bestpath != null) {
|
||||
return getNodePath(bestpath);
|
||||
}
|
||||
|
||||
// no path found
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a path with the default stepper which assumes the piece can
|
||||
* move one in any of the eight cardinal directions.
|
||||
*/
|
||||
public static List getPath (TraversalPred tpred, Object trav, int longest,
|
||||
int ax, int ay, int bx, int by, boolean partial)
|
||||
{
|
||||
return getPath(
|
||||
tpred, new Stepper(), trav, longest, ax, ay, bx, by, partial);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of nodes considered in computing the most recent
|
||||
* path.
|
||||
*/
|
||||
public static int getConsidered ()
|
||||
{
|
||||
return _considered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider the step <code>(n.x, n.y)</code> to <code>(x, y)</code>
|
||||
* for possible inclusion in the path.
|
||||
*
|
||||
* @param info the info object.
|
||||
* @param n the originating node for the step.
|
||||
* @param x the x-coordinate for the destination step.
|
||||
* @param y the y-coordinate for the destination step.
|
||||
*/
|
||||
protected static void considerStep (
|
||||
Info info, Node n, int x, int y, int cost)
|
||||
{
|
||||
// skip node if it's outside the map bounds or otherwise impassable
|
||||
if (!info.isStepValid(n.x, n.y, x, y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the new cost for this node
|
||||
int newg = n.g + cost;
|
||||
|
||||
// make sure the cost is reasonable
|
||||
if (newg > info.maxcost) {
|
||||
// Log.info("Rejected costly step.");
|
||||
return;
|
||||
}
|
||||
|
||||
// retrieve the node corresponding to this location
|
||||
Node np = info.getNode(x, y);
|
||||
|
||||
// skip if it's already in the open or closed list or if its
|
||||
// actual cost is less than the just-calculated cost
|
||||
if ((info.open.contains(np) || info.closed.contains(np)) &&
|
||||
np.g <= newg) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the node from the open list since we're about to
|
||||
// modify its score which determines its placement in the list
|
||||
info.open.remove(np);
|
||||
|
||||
// update the node's information
|
||||
np.parent = n;
|
||||
np.g = newg;
|
||||
np.h = getDistanceEstimate(np.x, np.y, info.destx, info.desty);
|
||||
np.f = np.g + np.h;
|
||||
|
||||
// remove it from the closed list if it's present
|
||||
info.closed.remove(np);
|
||||
|
||||
// add it to the open list for further consideration
|
||||
info.open.add(np);
|
||||
_considered++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of <code>Point</code> objects detailing the path
|
||||
* from the first node (the given node's ultimate parent) to the
|
||||
* ending node (the given node itself.)
|
||||
*
|
||||
* @param n the ending node in the path.
|
||||
*
|
||||
* @return the list detailing the path.
|
||||
*/
|
||||
protected static List getNodePath (Node n)
|
||||
{
|
||||
Node cur = n;
|
||||
ArrayList path = new ArrayList();
|
||||
|
||||
while (cur != null) {
|
||||
// add to the head of the list since we're traversing from
|
||||
// the end to the beginning
|
||||
path.add(0, new Point(cur.x, cur.y));
|
||||
|
||||
// advance to the next node in the path
|
||||
cur = cur.parent;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a heuristic estimate of the cost to get from <code>(ax,
|
||||
* ay)</code> to <code>(bx, by)</code>.
|
||||
*/
|
||||
protected static int getDistanceEstimate (int ax, int ay, int bx, int by)
|
||||
{
|
||||
// we're doing all of our cost calculations based on geometric
|
||||
// distance times ten
|
||||
int xsq = bx - ax;
|
||||
int ysq = by - ay;
|
||||
return (int) (ADJACENT_COST * Math.sqrt(xsq * xsq + ysq * ysq));
|
||||
}
|
||||
|
||||
/**
|
||||
* A holding class to contain the wealth of information referenced
|
||||
* while performing an A* search for a path through a tile array.
|
||||
*/
|
||||
protected static class Info
|
||||
{
|
||||
/** Knows whether or not tiles are traversable. */
|
||||
public TraversalPred tpred;
|
||||
|
||||
/** The tile array dimensions. */
|
||||
public int tilewid, tilehei;
|
||||
|
||||
/** The traverser moving along the path. */
|
||||
public Object trav;
|
||||
|
||||
/** The set of open nodes being searched. */
|
||||
public SortedSet open;
|
||||
|
||||
/** The set of closed nodes being searched. */
|
||||
public ArrayList closed;
|
||||
|
||||
/** The destination coordinates in the tile array. */
|
||||
public int destx, desty;
|
||||
|
||||
/** The maximum cost of any path that we'll consider. */
|
||||
public int maxcost;
|
||||
|
||||
public Info (TraversalPred tpred, Object trav,
|
||||
int longest, int destx, int desty)
|
||||
{
|
||||
// save off references
|
||||
this.tpred = tpred;
|
||||
this.trav = trav;
|
||||
this.destx = destx;
|
||||
this.desty = desty;
|
||||
|
||||
// compute our maximum path cost
|
||||
this.maxcost = longest * ADJACENT_COST;
|
||||
|
||||
// construct the open and closed lists
|
||||
open = new TreeSet();
|
||||
closed = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether moving from the given source to destination
|
||||
* coordinates is a valid move.
|
||||
*/
|
||||
protected boolean isStepValid (int sx, int sy, int dx, int dy)
|
||||
{
|
||||
// not traversable if the destination itself fails test
|
||||
if (!isTraversable(dx, dy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the step is diagonal, make sure the corners don't impede
|
||||
// our progress
|
||||
if ((Math.abs(dx - sx) == 1) && (Math.abs(dy - sy) == 1)) {
|
||||
return isTraversable(dx, sy) && isTraversable(sx, dy);
|
||||
}
|
||||
|
||||
// non-diagonals are always traversable
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given coordinate is valid and traversable.
|
||||
*/
|
||||
protected boolean isTraversable (int x, int y)
|
||||
{
|
||||
return tpred.canTraverse(trav, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the node for the specified point.
|
||||
*/
|
||||
public Node getNode (int x, int y)
|
||||
{
|
||||
// note: this _could_ break for unusual values of x and y.
|
||||
// perhaps use a IntTuple as a key? Bleah.
|
||||
int key = (x << 16) | (y & 0xffff);
|
||||
Node node = (Node) _nodes.get(key);
|
||||
if (node == null) {
|
||||
node = new Node(x, y);
|
||||
_nodes.put(key, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/** The nodes being considered in the path. */
|
||||
protected HashIntMap _nodes = new HashIntMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that represents a single traversable node in the tile array
|
||||
* along with its current A*-specific search information.
|
||||
*/
|
||||
protected static class Node implements Comparable
|
||||
{
|
||||
/** The node coordinates. */
|
||||
public int x, y;
|
||||
|
||||
/** The actual cheapest cost of arriving here from the start. */
|
||||
public int g;
|
||||
|
||||
/** The heuristic estimate of the cost to the goal from here. */
|
||||
public int h;
|
||||
|
||||
/** The score assigned to this node. */
|
||||
public int f;
|
||||
|
||||
/** The node from which we reached this node. */
|
||||
public Node parent;
|
||||
|
||||
/** The node's monotonically-increasing unique identifier. */
|
||||
public int id;
|
||||
|
||||
public Node (int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
id = _nextid++;
|
||||
}
|
||||
|
||||
public int compareTo (Object o)
|
||||
{
|
||||
int bf = ((Node)o).f;
|
||||
|
||||
// since the set contract is fulfilled using the equality results
|
||||
// returned here, and we'd like to allow multiple nodes with
|
||||
// equivalent scores in our set, we explicitly define object
|
||||
// equivalence as the result of object.equals(), else we use the
|
||||
// unique node id since it will return a consistent ordering for
|
||||
// the objects.
|
||||
if (f == bf) {
|
||||
return (this == o) ? 0 : (id - ((Node)o).id);
|
||||
}
|
||||
|
||||
return f - bf;
|
||||
}
|
||||
|
||||
/** The next unique node id. */
|
||||
protected static int _nextid = 0;
|
||||
}
|
||||
|
||||
/** The number of nodes considered in computing our path. */
|
||||
protected static int _considered = 0;
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
//
|
||||
// $Id: ArcPath.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.util.DirectionUtil;
|
||||
|
||||
/**
|
||||
* The line path is used to cause a pathable to go from point A to point B
|
||||
* along the arc of an ellipse in a certain number of milliseconds.
|
||||
*/
|
||||
public class ArcPath extends TimedPath
|
||||
{
|
||||
/** An orientation constant indicating that the normal (eight)
|
||||
* directions should be used to orient the pathable being made to
|
||||
* follow this path. */
|
||||
public static final int NORMAL = 0;
|
||||
|
||||
/** An orientation constant indicating that the fine (sixteen)
|
||||
* directions should be used to orient the pathable being made to
|
||||
* follow this path. */
|
||||
public static final int FINE = 1;
|
||||
|
||||
/** An orientation indicating that the pathable should not be oriented
|
||||
* as it moves along the path.
|
||||
*/
|
||||
public static final int NONE = 2;
|
||||
|
||||
/**
|
||||
* Creates an arc path that will animate a pathable from the specified
|
||||
* starting position along an ellipse defined by the supplied
|
||||
* parameters. The pathable will travel the specified number of
|
||||
* radians along the arc of that ellipse. A positive number of radians
|
||||
* indicates counter-clockwise travel along the circle, a negative
|
||||
* number, clockwise rotation.
|
||||
*
|
||||
* @param start the starting point for the pathable.
|
||||
* @param xradius the length of the x radius.
|
||||
* @param yradius the length of the y radius.
|
||||
* @param sangle the starting angle.
|
||||
* @param delta the angle through which the pathable should be moved.
|
||||
* @param duration the number of milliseconds during which to effect
|
||||
* the animation.
|
||||
* @param orient an orientation code indicating how the pathable
|
||||
* should be oriented when following the path, either {@link #NORMAL},
|
||||
* or {@link #FINE}.
|
||||
*/
|
||||
public ArcPath (Point start, double xradius, double yradius,
|
||||
double sangle, double delta, long duration,
|
||||
int orient)
|
||||
{
|
||||
super(duration);
|
||||
_xradius = xradius;
|
||||
_yradius = yradius;
|
||||
_sangle = sangle;
|
||||
_delta = delta;
|
||||
_orient = orient;
|
||||
|
||||
// compute the center of the ellipse
|
||||
_center = new Point(
|
||||
(int)(start.x - Math.round(Math.cos(sangle) * xradius)),
|
||||
(int)(start.y - Math.round(Math.sin(sangle) * yradius)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the path, translated by the specified amounts.
|
||||
*/
|
||||
public Path getTranslatedInstance (int x, int y)
|
||||
{
|
||||
int startx =
|
||||
(int)(_center.x + Math.round(Math.cos(_sangle) * _xradius));
|
||||
int starty =
|
||||
(int)(_center.y + Math.round(Math.sin(_sangle) * _yradius));
|
||||
|
||||
return new ArcPath(new Point (startx + x, starty + y),
|
||||
_xradius, _yradius, _sangle, _delta, _duration, _orient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset that is applied to the pathable whenever it is
|
||||
* oriented. This offset is in clockwise units whose granularity is
|
||||
* specified by the {@link #NORMAL} or {@link #FINE} setting supplied
|
||||
* to the path at construct time. The intent here is to allow arc
|
||||
* paths to be applied that don't orient the pathable in the direction
|
||||
* they are traveling but instead in some fixed offset from that
|
||||
* direction.
|
||||
*/
|
||||
public void setOrientOffset (int offset)
|
||||
{
|
||||
_orientOffset = offset;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean tick (Pathable pable, long timestamp)
|
||||
{
|
||||
double angle;
|
||||
boolean modified = false;
|
||||
|
||||
// if we've blown past our arrival time...
|
||||
if (timestamp >= _startStamp + _duration) {
|
||||
// ...force the angle to the destination angle
|
||||
angle = _sangle + _delta;
|
||||
|
||||
} else {
|
||||
// otherwise, compute the angle at which we should place the
|
||||
// pathable based on the elapsed time
|
||||
long elapsed = timestamp - _startStamp;
|
||||
angle = _sangle + _delta * elapsed / _duration;
|
||||
}
|
||||
|
||||
// determine where we should be along the path
|
||||
computePosition(_center, _xradius, _yradius, angle, _tpos);
|
||||
|
||||
// Skip this if we are not reorienting as we follow the path.
|
||||
if (_orient != NONE) {
|
||||
// compute the pathable's new orientation
|
||||
double theta = angle + ((_delta > 0) ? Math.PI/2 : -Math.PI/2);
|
||||
int orient;
|
||||
switch (_orient) {
|
||||
default:
|
||||
case NORMAL:
|
||||
orient = DirectionUtil.getDirection(theta);
|
||||
// adjust it appropriately
|
||||
orient = DirectionUtil.rotateCW(orient, 2*_orientOffset);
|
||||
break;
|
||||
|
||||
case FINE:
|
||||
orient = DirectionUtil.getFineDirection(theta);
|
||||
// adjust it appropriately
|
||||
orient = DirectionUtil.rotateCW(orient, _orientOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
// update the pathable's orientation if it changed
|
||||
if (pable.getOrientation() != orient) {
|
||||
pable.setOrientation(orient);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// update the pathable's location if it moved
|
||||
if (pable.getX() != _tpos.x || pable.getY() != _tpos.y) {
|
||||
pable.setLocation(_tpos.x, _tpos.y);
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// if we completed our path, let the sprite know
|
||||
if (angle == _sangle + _delta) {
|
||||
pable.pathCompleted(timestamp);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
int x = (int)(_center.x - _xradius), y = (int)(_center.y - _yradius);
|
||||
int width = (int)(2*_xradius), height = (int)(2*_yradius);
|
||||
int sangle = (int)(Math.round(180 * _sangle / Math.PI)),
|
||||
delta = (int)(Math.round(180 * _delta / Math.PI));
|
||||
|
||||
gfx.setColor(Color.blue);
|
||||
gfx.drawRect(x, y, width-1, height-1);
|
||||
|
||||
gfx.setColor(Color.yellow);
|
||||
gfx.drawArc(x, y, width-1, height-1, 0, 360);
|
||||
|
||||
gfx.setColor(Color.red);
|
||||
gfx.drawArc(x, y, width-1, height-1, 360-sangle, -delta);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", center=").append(StringUtil.toString(_center));
|
||||
buf.append(", sangle=").append(_sangle);
|
||||
buf.append(", delta=").append(_delta);
|
||||
buf.append(", radii=").append(_xradius).append("/").append(_yradius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the position of an entity along the path defined by the
|
||||
* supplied parameters assuming that it must finish the path in the
|
||||
* specified duration (in millis) and has been traveling the path for
|
||||
* the specified number of elapsed milliseconds.
|
||||
*/
|
||||
public static void computePosition (
|
||||
Point center, double xradius, double yradius, double angle, Point pos)
|
||||
{
|
||||
pos.x = (int)Math.round(center.x + xradius * Math.cos(angle));
|
||||
pos.y = (int)Math.round(center.y + yradius * Math.sin(angle));
|
||||
}
|
||||
|
||||
/** The center of our ellipse. */
|
||||
protected Point _center;
|
||||
|
||||
/** Our ellipse radii. */
|
||||
protected double _xradius, _yradius;
|
||||
|
||||
/** Our starting and delta angles. */
|
||||
protected double _sangle, _delta;
|
||||
|
||||
/** The method to be used to orient the pathable. */
|
||||
protected int _orient;
|
||||
|
||||
/** An orientation offset used when orienting our pathable. */
|
||||
protected int _orientOffset = 0;
|
||||
|
||||
/** A temporary point used when computing our position along the
|
||||
* path. */
|
||||
protected Point _tpos = new Point();
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// $Id: BackgroundTiler.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Used to tile a background image into regions of various sizes. The
|
||||
* source image is divided into nine quadrants (of mostly equal size)
|
||||
* which are tiled accordingly to fill whatever size background image is
|
||||
* desired.
|
||||
*/
|
||||
public class BackgroundTiler
|
||||
{
|
||||
/**
|
||||
* Creates a background tiler with the specified source image.
|
||||
*/
|
||||
public BackgroundTiler (BufferedImage src)
|
||||
{
|
||||
// make sure we were given the goods
|
||||
if (src == null) {
|
||||
Log.info("Backgrounder given null source image. Coping.");
|
||||
return;
|
||||
}
|
||||
|
||||
// compute some values
|
||||
int width = src.getWidth(null);
|
||||
int height = src.getHeight(null);
|
||||
|
||||
_w3 = width/3;
|
||||
_cw3 = width-2*_w3;
|
||||
_h3 = height/3;
|
||||
_ch3 = height-2*_h3;
|
||||
|
||||
// make sure the image suits our minimum useful dimensions
|
||||
if (_w3 <= 0 || _cw3 <= 0 || _h3 <= 0 || _ch3 <= 0) {
|
||||
Log.warning("Backgrounder given source image of insufficient " +
|
||||
"size for tiling " +
|
||||
"[width=" + width + ", height=" + height + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// create our sub-divided images
|
||||
_tiles = new BufferedImage[9];
|
||||
int[] sy = { 0, _h3, _h3+_ch3 };
|
||||
int[] thei = { _h3, _ch3, _h3 };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
_tiles[3*i] = src.getSubimage(0, sy[i], _w3, thei[i]);
|
||||
_tiles[3*i+1] = src.getSubimage(_w3, sy[i], _cw3, thei[i]);
|
||||
_tiles[3*i+2] =
|
||||
src.getSubimage(width-_w3, sy[i], _w3, thei[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "natural" width of the image being used to tile the
|
||||
* background.
|
||||
*/
|
||||
public int getNaturalWidth ()
|
||||
{
|
||||
return _w3*2+_cw3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "natural" height of the image being used to tile the
|
||||
* background.
|
||||
*/
|
||||
public int getNaturalHeight ()
|
||||
{
|
||||
return _h3*2+_ch3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the requested region with the background defined by our
|
||||
* source image.
|
||||
*/
|
||||
public void paint (Graphics g, int x, int y, int width, int height)
|
||||
{
|
||||
// bail out now if we were passed a bogus source image at
|
||||
// construct time
|
||||
if (_tiles == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rwid = width-2*_w3, rhei = height-2*_h3;
|
||||
|
||||
g.drawImage(_tiles[0], x, y, _w3, _h3, null);
|
||||
g.drawImage(_tiles[1], x + _w3, y, rwid, _h3, null);
|
||||
g.drawImage(_tiles[2], x + _w3 + rwid, y, _w3, _h3, null);
|
||||
|
||||
y += _h3;
|
||||
g.drawImage(_tiles[3], x, y, _w3, rhei, null);
|
||||
g.drawImage(_tiles[4], x + _w3, y, rwid, rhei, null);
|
||||
g.drawImage(_tiles[5], x + _w3 + rwid, y, _w3, rhei, null);
|
||||
|
||||
y += rhei;
|
||||
g.drawImage(_tiles[6], x, y, _w3, _h3, null);
|
||||
g.drawImage(_tiles[7], x + _w3, y, rwid, _h3, null);
|
||||
g.drawImage(_tiles[8], x + _w3 + rwid, y, _w3, _h3, null);
|
||||
}
|
||||
|
||||
/** Our nine sub-divided images. */
|
||||
protected BufferedImage[] _tiles;
|
||||
|
||||
/** One third of width/height of our source image. */
|
||||
protected int _w3, _h3;
|
||||
|
||||
/** The size of the center chunk of our subdivided images. */
|
||||
protected int _cw3, _ch3;
|
||||
}
|
||||
|
||||
|
||||
// Below is an alternate implementation that uses only the source image
|
||||
// without chopping it up. It ends up running very slightly slower, that
|
||||
// may be because the documentation for the version of drawImage used below
|
||||
// states that scaled instances will not be cached, that the scaling will
|
||||
// happen each time on the fly. On the other hand, maybe that's a good thing.
|
||||
// I like it better because it doesn't have to have 9 separate images and
|
||||
// because it does the render in a loop, which is good fun.
|
||||
|
||||
//public class BackgroundTiler
|
||||
//{
|
||||
// /**
|
||||
// * Creates a background tiler with the specified source image.
|
||||
// */
|
||||
// public BackgroundTiler (BufferedImage src)
|
||||
// {
|
||||
// // make sure we were given the goods
|
||||
// if (src == null) {
|
||||
// Log.info("Backgrounder given null source image. Coping.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// _src = src;
|
||||
//
|
||||
// // compute some values
|
||||
// int width = src.getWidth(null);
|
||||
// int height = src.getHeight(null);
|
||||
//
|
||||
// _w3 = width/3;
|
||||
// _cw3 = width-2*_w3;
|
||||
// _h3 = height/3;
|
||||
// _ch3 = height-2*_h3;
|
||||
//
|
||||
// _sx = new int[] { 0, _w3, width - _w3, width };
|
||||
// _sy = new int[] { 0, _h3, height - _h3, height };
|
||||
// _dx = new int[4];
|
||||
// _dy = new int[4];
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Fills the requested region with the background defined by our
|
||||
// * source image.
|
||||
// */
|
||||
// public void paint (Graphics g, int x, int y, int width, int height)
|
||||
// {
|
||||
// _dx[0] = x;
|
||||
// _dx[1] = x + _w3;
|
||||
// _dx[2] = x + width - _w3;
|
||||
// _dx[3] = x + width;
|
||||
//
|
||||
// _dy[0] = y;
|
||||
// _dy[1] = y + _h3;
|
||||
// _dy[2] = y + height - _h3;
|
||||
// _dy[3] = y + height;
|
||||
//
|
||||
// for (int jj=0; jj < 3; jj++) {
|
||||
// for (int ii=0; ii < 3; ii++) {
|
||||
// g.drawImage(_src, _dx[ii], _dy[jj], _dx[ii + 1], _dy[jj + 1],
|
||||
// _sx[ii], _sy[jj], _sx[ii + 1], _sy[jj + 1], null);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /** Our source image. */
|
||||
// protected BufferedImage _src;
|
||||
//
|
||||
// /** Coordinates. */
|
||||
// protected int[] _sx, _sy, _dx, _dy;
|
||||
//
|
||||
// /** One third of width/height of our source image. */
|
||||
// protected int _w3, _h3;
|
||||
//
|
||||
// /** The size of the center chunk of our subdivided images. */
|
||||
// protected int _cw3, _ch3;
|
||||
//}
|
||||
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// $Id: BobblePath.java 4188 2006-06-13 18:03:48Z mdb $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Bobble a Pathable.
|
||||
*/
|
||||
public class BobblePath implements Path
|
||||
{
|
||||
/**
|
||||
* Construct a bobble path that updates as often as possible.
|
||||
*
|
||||
* @param dx the variance in the x direction.
|
||||
* @param dy the variance in the y direction.
|
||||
* @param duration the duration to bobble, or -1 to bobble until
|
||||
* stop() is called.
|
||||
*/
|
||||
public BobblePath (int dx, int dy, long duration)
|
||||
{
|
||||
this(dx, dy, duration, 1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a bobble path.
|
||||
*
|
||||
* @param dx the variance in the x direction.
|
||||
* @param dy the variance in the y direction.
|
||||
* @param duration the duration to bobble, or -1 to bobble until
|
||||
* stop() is called.
|
||||
* @param updateFreq how often to update the Pathable's location.
|
||||
*/
|
||||
public BobblePath (int dx, int dy, long duration, long updateFreq)
|
||||
{
|
||||
_updateFreq = updateFreq;
|
||||
_duration = duration;
|
||||
setVariance(dx, dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the variance of bobblin' in each direction.
|
||||
*/
|
||||
public void setVariance (int dx, int dy)
|
||||
{
|
||||
if ((dx < 0) || (dy < 0) || ((dx == 0) && (dy == 0))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Variance values must be positive, " +
|
||||
"and at least one must be non-zero.");
|
||||
} else {
|
||||
_dx = dx;
|
||||
_dy = dy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new update frequency.
|
||||
*/
|
||||
public void setUpdateFrequency (long freq)
|
||||
{
|
||||
_updateFreq = freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have the Pathable stop bobbling asap.
|
||||
*/
|
||||
public void stop ()
|
||||
{
|
||||
// it will stop on the next tick..
|
||||
_stopTime = 0L;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void init (Pathable pable, long tickstamp)
|
||||
{
|
||||
_sx = pable.getX();
|
||||
_sy = pable.getY();
|
||||
// change the duration to a real stop time
|
||||
if (_duration == -1L) {
|
||||
_stopTime = Long.MAX_VALUE;
|
||||
} else {
|
||||
_stopTime = tickstamp + _duration;
|
||||
}
|
||||
_nextMove = tickstamp;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public boolean tick (Pathable pable, long tickStamp)
|
||||
{
|
||||
// see if we need to stop
|
||||
if (_stopTime <= tickStamp) {
|
||||
boolean updated = updatePositionTo(pable, _sx, _sy);
|
||||
pable.pathCompleted(tickStamp);
|
||||
return updated;
|
||||
}
|
||||
|
||||
// see if it's time to move..
|
||||
if (_nextMove > tickStamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// when bobbling, it's bad form to bobble into the same position
|
||||
int newx, newy;
|
||||
do {
|
||||
newx = _sx + RandomUtil.getInt(_dx * 2 + 1) - _dx;
|
||||
newy = _sy + RandomUtil.getInt(_dy * 2 + 1) - _dy;
|
||||
} while (! updatePositionTo(pable, newx, newy));
|
||||
|
||||
// and update the next time to move
|
||||
_nextMove = tickStamp + _updateFreq;
|
||||
return true;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_stopTime += timeDelta;
|
||||
_nextMove += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// for debugging, show the bobble bounds
|
||||
gfx.setColor(Color.RED);
|
||||
gfx.drawRect(_sx - _dx, _sy - _dy, _dx * 2, _dy * 2);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void wasRemoved (Pathable pable)
|
||||
{
|
||||
// reset the pathable to its initial location
|
||||
pable.setLocation(_sx, _sy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the position of the pathable or return false
|
||||
* if it's already there.
|
||||
*/
|
||||
protected boolean updatePositionTo (Pathable pable, int x, int y)
|
||||
{
|
||||
if ((pable.getX() == x) && (pable.getY() == y)) {
|
||||
return false;
|
||||
} else {
|
||||
pable.setLocation(x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** The initial position of the pathable. */
|
||||
protected int _sx, _sy;
|
||||
|
||||
/** The variance we will bobble around that initial position. */
|
||||
protected int _dx, _dy;
|
||||
|
||||
/** How long we'll bobble. */
|
||||
protected long _duration;
|
||||
|
||||
/** How often we update the locations. */
|
||||
protected long _updateFreq;
|
||||
|
||||
/** The time at which we'll stop pathin'. */
|
||||
protected long _stopTime;
|
||||
|
||||
/** The time at which we'll next update the position of the pathable. */
|
||||
protected long _nextMove = 0L;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
/**
|
||||
* A convenience path that waits a specified amount of time.
|
||||
*/
|
||||
public class DelayPath extends TimedPath
|
||||
{
|
||||
/**
|
||||
* Cause the current path to remain unchanged for the duration.
|
||||
*/
|
||||
public DelayPath (long duration)
|
||||
{
|
||||
this(null, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the sprite to the supplied location then wait for the duration.
|
||||
*/
|
||||
public DelayPath (int x, int y, long duration)
|
||||
{
|
||||
this(new Point(x, y), duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to the sprite to the supplied location then wait for the duration.
|
||||
*/
|
||||
public DelayPath (Point source, long duration)
|
||||
{
|
||||
super(duration);
|
||||
_source = source;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void init (Pathable pable, long timestamp)
|
||||
{
|
||||
super.init(pable, timestamp);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean tick (Pathable pable, long tickstamp)
|
||||
{
|
||||
if (tickstamp >= _startStamp + _duration) {
|
||||
if (_source != null) {
|
||||
pable.setLocation(_source.x, _source.y);
|
||||
}
|
||||
pable.pathCompleted(tickstamp);
|
||||
return (_source != null);
|
||||
}
|
||||
|
||||
// If necessary, move the sprite to the supplied location
|
||||
if (_source != null && (pable.getX() != _source.x ||
|
||||
pable.getY() != _source.y)) {
|
||||
pable.setLocation(_source.x, _source.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Source point. */
|
||||
protected Point _source;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// $Id: DelegatingPathable.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Delegates all calls to a delegate pathable. One would derive from this
|
||||
* class and override just the methods in which that one desired to
|
||||
* intervene.
|
||||
*/
|
||||
public class DelegatingPathable implements Pathable
|
||||
{
|
||||
public DelegatingPathable (Pathable delegate)
|
||||
{
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getX ()
|
||||
{
|
||||
return _delegate.getX();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getY ()
|
||||
{
|
||||
return _delegate.getY();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public Rectangle getBounds ()
|
||||
{
|
||||
return _delegate.getBounds();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void setLocation (int x, int y)
|
||||
{
|
||||
_delegate.setLocation(x, y);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void setOrientation (int orient)
|
||||
{
|
||||
_delegate.setOrientation(orient);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getOrientation ()
|
||||
{
|
||||
return _delegate.getOrientation();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void pathBeginning ()
|
||||
{
|
||||
_delegate.pathBeginning();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void pathCompleted (long timestamp)
|
||||
{
|
||||
_delegate.pathCompleted(timestamp);
|
||||
}
|
||||
|
||||
protected Pathable _delegate;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// $Id: FrameSequencer.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
/**
|
||||
* Used to control animation timing when displaying a {@link
|
||||
* MultiFrameImage}. This interface allows for constant framerates, or
|
||||
* more sophisticated animation timing.
|
||||
*/
|
||||
public interface FrameSequencer
|
||||
{
|
||||
/**
|
||||
* Called prior to the execution of an animation sequence (not
|
||||
* necessarily immediately, so time stamps should be obtained in the
|
||||
* first call to tick).
|
||||
*
|
||||
* @param source the multie-frame image that is providing the
|
||||
* animation frames.
|
||||
*/
|
||||
public void init (MultiFrameImage source);
|
||||
|
||||
/**
|
||||
* Called every display frame, the frame sequencer should return the
|
||||
* index of the animation frame that should be displayed during this
|
||||
* tick. If the sequencer returns -1, it is taken as an indication
|
||||
* that the animation is finished and should be stopped.
|
||||
*/
|
||||
public int tick (long tickStamp);
|
||||
|
||||
/**
|
||||
* Called if the display is paused for some length of time and then
|
||||
* unpaused. Sequencers should adjust any time stamps they are
|
||||
* maintaining internally by the delta so that time maintains the
|
||||
* illusion of flowing smoothly forward.
|
||||
*/
|
||||
public void fastForward (long timeDelta);
|
||||
|
||||
/**
|
||||
* A frame sequencer that delivers a constant frame rate in either one
|
||||
* shot or looping mode.
|
||||
*/
|
||||
public static class ConstantRate implements FrameSequencer
|
||||
{
|
||||
/**
|
||||
* Creates a constant rate frame sequencer with the desired target
|
||||
* frames per second.
|
||||
*
|
||||
* @param framesPerSecond the target frames per second.
|
||||
* @param loop if false, the sequencer will report the end of
|
||||
* the animation after progressing through all of the frames once,
|
||||
* otherwise it will loop indefinitely.
|
||||
*/
|
||||
public ConstantRate (double framesPerSecond, boolean loop)
|
||||
{
|
||||
_millisPerFrame = (long)(1000d / framesPerSecond);
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void init (MultiFrameImage source)
|
||||
{
|
||||
_frameCount = source.getFrameCount();
|
||||
_startStamp = 0l;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int tick (long tickStamp)
|
||||
{
|
||||
// obtain our starting timestamp if we don't already have one
|
||||
if (_startStamp == 0) {
|
||||
_startStamp = tickStamp;
|
||||
}
|
||||
|
||||
// compute our current frame index
|
||||
int frameIdx = (int)((tickStamp - _startStamp) / _millisPerFrame);
|
||||
|
||||
// if we're not looping and we've exhausted our frames, we
|
||||
// return -1 to indicate that the animation should stop
|
||||
return (_loop || frameIdx < _frameCount) ? (frameIdx % _frameCount)
|
||||
: -1;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_startStamp += timeDelta;
|
||||
}
|
||||
|
||||
protected long _millisPerFrame;
|
||||
protected boolean _loop;
|
||||
protected int _frameCount;
|
||||
protected long _startStamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// $Id: LinePath.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* The line path is used to cause a pathable to go from point A to point B
|
||||
* in a certain number of milliseconds.
|
||||
*/
|
||||
public class LinePath extends TimedPath
|
||||
{
|
||||
/**
|
||||
* Constructs a line path between the two specified points that will
|
||||
* be followed in the specified number of milliseconds.
|
||||
*/
|
||||
public LinePath (int x1, int y1, int x2, int y2, long duration)
|
||||
{
|
||||
this(new Point(x1, y1), new Point(x2, y2), duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a line path between the two specified points that will
|
||||
* be followed in the specified number of milliseconds.
|
||||
*/
|
||||
public LinePath (Point source, Point dest, long duration)
|
||||
{
|
||||
super(duration);
|
||||
_source = source;
|
||||
_dest = dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a line path that moves a pathable from
|
||||
* whatever its location is at init time to the dest point over
|
||||
* the specified number of milliseconds.
|
||||
*/
|
||||
public LinePath (Point dest, long duration)
|
||||
{
|
||||
this(null, dest, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the path, translated by the specified amounts.
|
||||
*/
|
||||
public Path getTranslatedInstance (int x, int y)
|
||||
{
|
||||
if (_source == null) {
|
||||
return new LinePath(null, new Point(_dest.x + x, _dest.y + y),
|
||||
_duration);
|
||||
} else {
|
||||
return new LinePath(_source.x + x, _source.y + y, _dest.x + x,
|
||||
_dest.y + y, _duration);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void init (Pathable pable, long timestamp)
|
||||
{
|
||||
super.init(pable, timestamp);
|
||||
|
||||
// fill in the source if necessary.
|
||||
if (_source == null) {
|
||||
_source = new Point(pable.getX(), pable.getY());
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean tick (Pathable pable, long timestamp)
|
||||
{
|
||||
// if we've blown past our arrival time, we need to get our bootay
|
||||
// to the prearranged spot and get the hell out
|
||||
if (timestamp >= _startStamp + _duration) {
|
||||
pable.setLocation(_dest.x, _dest.y);
|
||||
pable.pathCompleted(timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// determine where we should be along the path
|
||||
long elapsed = timestamp - _startStamp;
|
||||
computePosition(_source, _dest, elapsed, _duration, _tpos);
|
||||
|
||||
// only update the pathable's location if it actually moved
|
||||
if (pable.getX() != _tpos.x || pable.getY() != _tpos.y) {
|
||||
pable.setLocation(_tpos.x, _tpos.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
gfx.setColor(Color.red);
|
||||
gfx.drawLine(_source.x, _source.y, _dest.x, _dest.y);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", src=").append(StringUtil.toString(_source));
|
||||
buf.append(", dest=").append(StringUtil.toString(_dest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the position of an entity along the path defined by the
|
||||
* supplied start and end points assuming that it must finish the path
|
||||
* in the specified duration (in millis) and has been traveling the
|
||||
* path for the specified number of elapsed milliseconds.
|
||||
*/
|
||||
public static void computePosition (Point start, Point end, long elapsed,
|
||||
long duration, Point pos)
|
||||
{
|
||||
float pct = (float)elapsed / duration;
|
||||
int travx = (int)((end.x - start.x) * pct);
|
||||
int travy = (int)((end.y - start.y) * pct);
|
||||
pos.setLocation(start.x + travx, start.y + travy);
|
||||
}
|
||||
|
||||
/** Our source and destination points. */
|
||||
protected Point _source, _dest;
|
||||
|
||||
/** A temporary point used when computing our position along the
|
||||
* path. */
|
||||
protected Point _tpos = new Point();
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
//
|
||||
// $Id: LineSegmentPath.java 3880 2006-02-22 18:29:05Z mjohnson $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.util.DirectionCodes;
|
||||
import com.threerings.util.DirectionUtil;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
import com.threerings.media.util.MathUtil;
|
||||
|
||||
/**
|
||||
* The line segment path is used to cause a pathable to follow a path that
|
||||
* is made up of a sequence of line segments. There must be at least two
|
||||
* nodes in any worthwhile path. The direction of the first node in the
|
||||
* path is meaningless since the pathable begins at that node and will
|
||||
* therefore never be heading towards it.
|
||||
*/
|
||||
public class LineSegmentPath
|
||||
implements DirectionCodes, Path
|
||||
{
|
||||
/**
|
||||
* Constructs an empty line segment path.
|
||||
*/
|
||||
public LineSegmentPath ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a line segment path that consists of a single segment
|
||||
* connecting the point <code>(x1, y1)</code> with <code>(x2,
|
||||
* y2)</code>. The orientation for the first node is set arbitrarily
|
||||
* and the second node is oriented based on the vector between the two
|
||||
* nodes (in top-down coordinates).
|
||||
*/
|
||||
public LineSegmentPath (int x1, int y1, int x2, int y2)
|
||||
{
|
||||
addNode(x1, y1, NORTH);
|
||||
Point p1 = new Point(x1, y1), p2 = new Point(x2, y2);
|
||||
int dir = DirectionUtil.getDirection(p1, p2);
|
||||
addNode(x2, y2, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a line segment path between the two nodes with the
|
||||
* specified direction.
|
||||
*/
|
||||
public LineSegmentPath (Point p1, Point p2, int dir)
|
||||
{
|
||||
addNode(p1.x, p1.y, NORTH);
|
||||
addNode(p2.x, p2.y, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a line segment path with the specified list of points.
|
||||
* An arbitrary direction will be assigned to the starting node.
|
||||
*/
|
||||
public LineSegmentPath (List points)
|
||||
{
|
||||
createPath(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the orientation the sprite will face at the end of the
|
||||
* path.
|
||||
*/
|
||||
public int getFinalOrientation ()
|
||||
{
|
||||
return (_nodes.size() == 0) ? NORTH :
|
||||
((PathNode)_nodes.get(_nodes.size()-1)).dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the path with the specified destination point and
|
||||
* facing direction.
|
||||
*
|
||||
* @param x the x-position.
|
||||
* @param y the y-position.
|
||||
* @param dir the facing direction.
|
||||
*/
|
||||
public void addNode (int x, int y, int dir)
|
||||
{
|
||||
_nodes.add(new PathNode(x, y, dir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the requested node index in the path, or null if no such
|
||||
* index exists.
|
||||
*
|
||||
* @param idx the node index.
|
||||
*
|
||||
* @return the path node.
|
||||
*/
|
||||
public PathNode getNode (int idx)
|
||||
{
|
||||
return (PathNode)_nodes.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of nodes in the path.
|
||||
*/
|
||||
public int size ()
|
||||
{
|
||||
return _nodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the velocity of this pathable in pixels per millisecond. The
|
||||
* velocity is measured as pixels traversed along the path that the
|
||||
* pathable is traveling rather than in the x or y directions
|
||||
* individually. Note that the pathable velocity should not be
|
||||
* changed while a path is being traversed; doing so may result in the
|
||||
* pathable position changing unexpectedly.
|
||||
*
|
||||
* @param velocity the pathable velocity in pixels per millisecond.
|
||||
*/
|
||||
public void setVelocity (float velocity)
|
||||
{
|
||||
_vel = velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the velocity at which the pathable will need to travel
|
||||
* along this path such that it will arrive at the destination in
|
||||
* approximately the specified number of milliseconds. Efforts are
|
||||
* taken to get the pathable there as close to the desired time as
|
||||
* possible, but framerate variation may prevent it from arriving
|
||||
* exactly on time.
|
||||
*/
|
||||
public void setDuration (long millis)
|
||||
{
|
||||
// if we have only zero or one nodes, we don't have enough
|
||||
// information to compute our velocity
|
||||
int ncount = _nodes.size();
|
||||
if (ncount < 2) {
|
||||
Log.warning("Requested to set duration of bogus path " +
|
||||
"[path=" + this + ", duration=" + millis + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the total distance along our path
|
||||
float distance = 0;
|
||||
PathNode start = (PathNode)_nodes.get(0);
|
||||
for (int ii = 1; ii < ncount; ii++) {
|
||||
PathNode end = (PathNode)_nodes.get(ii);
|
||||
distance += MathUtil.distance(
|
||||
start.loc.x, start.loc.y, end.loc.x, end.loc.y);
|
||||
start = end;
|
||||
}
|
||||
|
||||
// set the velocity accordingly
|
||||
setVelocity(distance/millis);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void init (Pathable pable, long timestamp)
|
||||
{
|
||||
// give the pathable a chance to perform any starting antics
|
||||
pable.pathBeginning();
|
||||
|
||||
// if we have only one node then let the pathable know that we're
|
||||
// done straight away
|
||||
if (size() < 2) {
|
||||
// move the pathable to the location specified by the first
|
||||
// node (assuming we have a first node)
|
||||
if (size() == 1) {
|
||||
PathNode node = (PathNode)_nodes.get(0);
|
||||
pable.setLocation(node.loc.x, node.loc.y);
|
||||
}
|
||||
// and let the pathable know that we're done
|
||||
pable.pathCompleted(timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
// and an enumeration of the path nodes
|
||||
_niter = _nodes.iterator();
|
||||
|
||||
// pretend like we were previously heading to our starting position
|
||||
_dest = getNextNode();
|
||||
|
||||
// begin traversing the path
|
||||
headToNextNode(pable, timestamp, timestamp);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean tick (Pathable pable, long timestamp)
|
||||
{
|
||||
// figure out how far along this segment we should be
|
||||
long msecs = timestamp - _nodestamp;
|
||||
float travpix = msecs * _vel;
|
||||
float pctdone = travpix / _seglength;
|
||||
|
||||
// if we've moved beyond the end of the path, we need to adjust
|
||||
// the timestamp to determine how much time we used getting to the
|
||||
// end of this node, then move to the next one
|
||||
if (pctdone >= 1.0) {
|
||||
long used = (long)(_seglength / _vel);
|
||||
return headToNextNode(pable, _nodestamp + used, timestamp);
|
||||
}
|
||||
|
||||
// otherwise we position the pathable along the path
|
||||
int ox = pable.getX();
|
||||
int oy = pable.getY();
|
||||
int nx = _src.loc.x + (int)((_dest.loc.x - _src.loc.x) * pctdone);
|
||||
int ny = _src.loc.y + (int)((_dest.loc.y - _src.loc.y) * pctdone);
|
||||
|
||||
// Log.info("Moving pathable [msecs=" + msecs + ", pctdone=" + pctdone +
|
||||
// ", travpix=" + travpix + ", seglength=" + _seglength +
|
||||
// ", dx=" + (nx-ox) + ", dy=" + (ny-oy) + "].");
|
||||
|
||||
// only update the pathable's location if it actually moved
|
||||
if (ox != nx || oy != ny) {
|
||||
pable.setLocation(nx, ny);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_nodestamp += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void wasRemoved (Pathable pable)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the pathable moving along the path at the end of the previous
|
||||
* path node, face it appropriately for the next node, and start it on
|
||||
* its way. Returns whether the pathable position moved.
|
||||
*/
|
||||
protected boolean headToNextNode (
|
||||
Pathable pable, long startstamp, long now)
|
||||
{
|
||||
if (_niter == null) {
|
||||
throw new IllegalStateException(
|
||||
"headToNextNode() called before init()");
|
||||
}
|
||||
|
||||
// check to see if we've completed our path
|
||||
if (!_niter.hasNext()) {
|
||||
// move the pathable to the location of our last destination
|
||||
pable.setLocation(_dest.loc.x, _dest.loc.y);
|
||||
pable.pathCompleted(now);
|
||||
return true;
|
||||
}
|
||||
|
||||
// our previous destination is now our source
|
||||
_src = _dest;
|
||||
|
||||
// pop the next node off the path
|
||||
_dest = getNextNode();
|
||||
|
||||
// adjust the pathable's orientation
|
||||
if (_dest.dir != NONE) {
|
||||
pable.setOrientation(_dest.dir);
|
||||
}
|
||||
|
||||
// make a note of when we started traversing this node
|
||||
_nodestamp = startstamp;
|
||||
|
||||
// figure out the distance from source to destination
|
||||
_seglength = MathUtil.distance(
|
||||
_src.loc.x, _src.loc.y, _dest.loc.x, _dest.loc.y);
|
||||
|
||||
// if we're already there (the segment length is zero), we skip to
|
||||
// the next segment
|
||||
if (_seglength == 0) {
|
||||
return headToNextNode(pable, startstamp, now);
|
||||
}
|
||||
|
||||
// now update the pathable's position based on our progress thus far
|
||||
return tick(pable, now);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
gfx.setColor(Color.red);
|
||||
Point prev = null;
|
||||
int size = size();
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
PathNode n = (PathNode)getNode(ii);
|
||||
if (prev != null) {
|
||||
gfx.drawLine(prev.x, prev.y, n.loc.x, n.loc.y);
|
||||
}
|
||||
prev = n.loc;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String toString ()
|
||||
{
|
||||
return StringUtil.toString(_nodes.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the path with the path nodes that lead the pathable from
|
||||
* its starting position to the given destination coordinates
|
||||
* following the given list of screen coordinates.
|
||||
*/
|
||||
protected void createPath (List points)
|
||||
{
|
||||
Point last = null;
|
||||
int size = points.size();
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
Point p = (Point)points.get(ii);
|
||||
|
||||
int dir = (ii == 0) ? NORTH : DirectionUtil.getDirection(last, p);
|
||||
addNode(p.x, p.y, dir);
|
||||
last = p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next node in the path.
|
||||
*/
|
||||
protected PathNode getNextNode ()
|
||||
{
|
||||
return (PathNode)_niter.next();
|
||||
}
|
||||
|
||||
/** The nodes that make up the path. */
|
||||
protected ArrayList _nodes = new ArrayList();
|
||||
|
||||
/** We use this when moving along this path. */
|
||||
protected Iterator _niter;
|
||||
|
||||
/** When moving, the pathable's source path node. */
|
||||
protected PathNode _src;
|
||||
|
||||
/** When moving, the pathable's destination path node. */
|
||||
protected PathNode _dest;
|
||||
|
||||
/** The time at which we started traversing the current node. */
|
||||
protected long _nodestamp;
|
||||
|
||||
/** The length in pixels of the current path segment. */
|
||||
protected float _seglength;
|
||||
|
||||
/** The path velocity in pixels per millisecond. */
|
||||
protected float _vel = DEFAULT_VELOCITY;
|
||||
|
||||
/** When moving, the pathable position including fractional pixels. */
|
||||
protected float _movex, _movey;
|
||||
|
||||
/** When moving, the distance to move on each axis per tick. */
|
||||
protected float _incx, _incy;
|
||||
|
||||
/** The distance to move on the straight path line per tick. */
|
||||
protected float _fracx, _fracy;
|
||||
|
||||
/** Default pathable velocity. */
|
||||
protected static final float DEFAULT_VELOCITY = 200f/1000f;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// $Id: LinearTimeFunction.java 4191 2006-06-13 22:42:20Z ray $
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
/**
|
||||
* Varies a value linearly with time.
|
||||
*/
|
||||
public class LinearTimeFunction extends TimeFunction
|
||||
{
|
||||
public LinearTimeFunction (int start, int end, int duration)
|
||||
{
|
||||
super(start, end, duration);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected int computeValue (int dt)
|
||||
{
|
||||
int dv = (_end - _start);
|
||||
return (dt * dv / _duration) + _start;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// $Id: MathUtil.java 3580 2005-05-27 23:04:42Z tedv $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
/**
|
||||
* Provides miscellaneous useful utility routines for mathematical
|
||||
* calculations.
|
||||
*/
|
||||
public class MathUtil
|
||||
{
|
||||
/**
|
||||
* Bounds the supplied value within the specified range.
|
||||
*
|
||||
* @return low if value < low, high if value > high and value
|
||||
* otherwise.
|
||||
*/
|
||||
public static int bound (int low, int value, int high)
|
||||
{
|
||||
return Math.min(high, Math.max(low, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the squared distance between the given points.
|
||||
*/
|
||||
public static int distanceSq (int x0, int y0, int x1, int y1)
|
||||
{
|
||||
return ((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the distance between the given points.
|
||||
*/
|
||||
public static float distance (int x0, int y0, int x1, int y1)
|
||||
{
|
||||
return (float)Math.sqrt(((x1 - x0) * (x1 - x0)) +
|
||||
((y1 - y0) * (y1 - y0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the distance between the given points.
|
||||
*/
|
||||
public static float distance (Point source, Point dest)
|
||||
{
|
||||
return MathUtil.distance(source.x, source.y, dest.x, dest.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the given line.
|
||||
*/
|
||||
public static String lineToString (int x0, int y0, int x1, int y1)
|
||||
{
|
||||
return "(" + x0 + ", " + y0 + ") -> (" + x1 + ", " + y1 + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the given line.
|
||||
*/
|
||||
public static String lineToString (Point p1, Point p2)
|
||||
{
|
||||
return lineToString(p1.x, p1.y, p2.x, p2.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the approximate circumference of the ellipse defined by the
|
||||
* specified minor and major axes. The formula used (due to Ramanujan,
|
||||
* via a paper of his entitled "Modular Equations and Approximations
|
||||
* to Pi"), is <code>Pi(3a + 3b - sqrt[(a+3b)(b+3a)])</code>.
|
||||
*/
|
||||
public static double ellipseCircum (double a, double b)
|
||||
{
|
||||
return Math.PI * (3*a + 3*b - Math.sqrt((a + 3*b) * (b + 3*a)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns positive 1 if the sign of the argument is positive, or -1
|
||||
* if the sign of the argument is negative.
|
||||
*/
|
||||
public static int sign (int value)
|
||||
{
|
||||
return (value < 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the floored division <code>dividend/divisor</code> which
|
||||
* is useful when dividing potentially negative numbers into bins. For
|
||||
* positive numbers, it is the same as normal division, for negative
|
||||
* numbers it returns <code>(dividend - divisor + 1) / divisor</code>.
|
||||
*
|
||||
* <p> For example, the following numbers floorDiv 10 are:
|
||||
* <pre>
|
||||
* -15 -10 -8 -2 0 2 8 10 15
|
||||
* -2 -1 -1 -1 0 0 0 1 1
|
||||
* </pre>
|
||||
*/
|
||||
public static int floorDiv (int dividend, int divisor)
|
||||
{
|
||||
return ((dividend >= 0) ? dividend : (dividend - divisor + 1))/divisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the standard deviation of the supplied values.
|
||||
*
|
||||
* @return an array of three values: the mean, variance and standard
|
||||
* deviation, in that order.
|
||||
*/
|
||||
public static float[] stddev (int[] values, int start, int length)
|
||||
{
|
||||
// first we need the mean
|
||||
float mean = 0f;
|
||||
for (int ii = start, end = start + length; ii < end; ii++) {
|
||||
mean += values[ii];
|
||||
}
|
||||
mean /= length;
|
||||
|
||||
// next we compute the variance
|
||||
float variance = 0f;
|
||||
for (int ii = start, end = start + length; ii < end; ii++) {
|
||||
float value = values[ii] - mean;
|
||||
variance += value * value;
|
||||
}
|
||||
variance /= (length - 1);
|
||||
|
||||
// the standard deviation is the square root of the variance
|
||||
return new float[] { mean, variance, (float)Math.sqrt(variance) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes (N choose K), the number of ways to select K different
|
||||
* elements from a set of size N.
|
||||
*/
|
||||
public static int choose (int n, int k)
|
||||
{
|
||||
// Base case: One way to select or not select the whole set
|
||||
if (k <= 0 || k >= n) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Recurse using pascal's triangle
|
||||
return (choose(n-1, k-1) + choose(n-1, k));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// $Id: ModeUtil.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.DisplayMode;
|
||||
import java.awt.GraphicsDevice;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Display mode related utilities.
|
||||
*/
|
||||
public class ModeUtil
|
||||
{
|
||||
/**
|
||||
* Gets a display mode that matches the specified parameters. The
|
||||
* screen resolution must match the specified resolution exactly, the
|
||||
* specified desired depth will be used if it is available, and if
|
||||
* not, the highest depth greater than or equal to the specified
|
||||
* minimum depth is used. The highest refresh rate available for the
|
||||
* desired mode is also used.
|
||||
*/
|
||||
public static DisplayMode getDisplayMode (
|
||||
GraphicsDevice gd, int width, int height,
|
||||
int desiredDepth, int minimumDepth)
|
||||
{
|
||||
DisplayMode[] modes = gd.getDisplayModes();
|
||||
final int ddepth = desiredDepth;
|
||||
|
||||
// we sort modes in order of desirability
|
||||
Comparator mcomp = new Comparator () {
|
||||
public int compare (Object o1, Object o2) {
|
||||
DisplayMode m1 = (DisplayMode)o1;
|
||||
DisplayMode m2 = (DisplayMode)o2;
|
||||
int bd1 = m1.getBitDepth(), bd2 = m2.getBitDepth();
|
||||
int rr1 = m1.getRefreshRate(), rr2 = m2.getRefreshRate();
|
||||
|
||||
// prefer the desired depth
|
||||
if (bd1 == ddepth && bd2 != ddepth) {
|
||||
return -1;
|
||||
} else if (bd2 == ddepth && bd1 != ddepth) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// otherwise prefer higher depths
|
||||
if (bd1 != bd2) {
|
||||
return bd2 - bd1;
|
||||
}
|
||||
|
||||
// for same bitrates, prefer higher refresh rates
|
||||
return rr2 - rr1;
|
||||
}
|
||||
};
|
||||
|
||||
// but we only add modes that meet our minimum requirements
|
||||
TreeSet mset = new TreeSet(mcomp);
|
||||
for (int i = 0; i < modes.length; i++) {
|
||||
if (modes[i].getWidth() == width &&
|
||||
modes[i].getHeight() == height &&
|
||||
modes[i].getBitDepth() >= minimumDepth &&
|
||||
modes[i].getRefreshRate() <= 75) {
|
||||
mset.add(modes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return (mset.size() > 0) ? (DisplayMode)mset.first() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the supplied display mode.
|
||||
*/
|
||||
public static String toString (DisplayMode mode)
|
||||
{
|
||||
return "[width=" + mode.getWidth() +
|
||||
", height=" + mode.getHeight() +
|
||||
", depth=" + mode.getBitDepth() +
|
||||
", refresh=" + mode.getRefreshRate() + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// $Id: MultiFrameImage.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
/**
|
||||
* The multi-frame image interface provides encapsulated access to a set
|
||||
* of images that are used to create a multi-frame animation.
|
||||
*/
|
||||
public interface MultiFrameImage
|
||||
{
|
||||
/**
|
||||
* Returns the number of frames in this multi-frame image.
|
||||
*/
|
||||
public int getFrameCount ();
|
||||
|
||||
/**
|
||||
* Returns the width of the specified frame image.
|
||||
*/
|
||||
public int getWidth (int index);
|
||||
|
||||
/**
|
||||
* Returns the height of the specified frame image.
|
||||
*/
|
||||
public int getHeight (int index);
|
||||
|
||||
/**
|
||||
* Renders the specified frame into the specified graphics object at
|
||||
* the specified coordinates.
|
||||
*/
|
||||
public void paintFrame (Graphics2D g, int index, int x, int y);
|
||||
|
||||
/**
|
||||
* Returns true if the specified frame contains a non-transparent
|
||||
* pixel at the specified coordinates.
|
||||
*/
|
||||
public boolean hitTest (int index, int x, int y);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id: MultiFrameImageImpl.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* A basic implementation of the {@link MultiFrameImage} interface
|
||||
* intended to facilitate the creation of MFIs whose display frames
|
||||
* consist of multiple image objects.
|
||||
*/
|
||||
public class MultiFrameImageImpl implements MultiFrameImage
|
||||
{
|
||||
/**
|
||||
* Constructs a multiple frame image object.
|
||||
*/
|
||||
public MultiFrameImageImpl (Mirage[] mirages)
|
||||
{
|
||||
_mirages = mirages;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getFrameCount ()
|
||||
{
|
||||
return _mirages.length;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getWidth (int index)
|
||||
{
|
||||
return _mirages[index].getWidth();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getHeight (int index)
|
||||
{
|
||||
return _mirages[index].getHeight();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void paintFrame (Graphics2D g, int index, int x, int y)
|
||||
{
|
||||
_mirages[index].paint(g, x, y);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean hitTest (int index, int x, int y)
|
||||
{
|
||||
return _mirages[index].hitTest(x, y);
|
||||
}
|
||||
|
||||
/** The frame images. */
|
||||
protected Mirage[] _mirages;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// $Id: Path.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
/**
|
||||
* A path is used to cause a {@link Pathable} to follow a particular path
|
||||
* along the screen. The {@link Pathable} is responsible for calling
|
||||
* {@link #tick} on the path with reasonable frequency (generally as a
|
||||
* part of the frame tick. The path is responsible for updating the
|
||||
* position of the {@link Pathable} based on the time that has elapsed
|
||||
* since the {@link Pathable} started down the path.
|
||||
*
|
||||
* <p> The path should call the appropriate callbacks on the {@link
|
||||
* Pathable} when appropriate (e.g. {@link Pathable#pathBeginning}, {@link
|
||||
* Pathable#pathCompleted}).
|
||||
*/
|
||||
public interface Path
|
||||
{
|
||||
/**
|
||||
* Called once to let the path prepare itself for the process of
|
||||
* animating the supplied pathable. Path users should also call {@link
|
||||
* #tick} after {@link #init} with the same initialization timestamp.
|
||||
*/
|
||||
public void init (Pathable pable, long tickStamp);
|
||||
|
||||
/**
|
||||
* Called to request that this path update the position of the
|
||||
* specified pathable based on the supplied timestamp information. A
|
||||
* path should record its initial timestamp and determine the progress
|
||||
* of the pathable along the path based on the time elapsed since the
|
||||
* pathable began down the path.
|
||||
*
|
||||
* @param pable the pathable whose position should be updated.
|
||||
* @param tickStamp the timestamp associated with this frame.
|
||||
*
|
||||
* @return true if the pathable's position was updated, false if the
|
||||
* path determined that the pathable should not move at this time.
|
||||
*/
|
||||
public boolean tick (Pathable pable, long tickStamp);
|
||||
|
||||
/**
|
||||
* This is called if the pathable is paused for some length of time
|
||||
* and then unpaused. Paths should adjust any time stamps they are
|
||||
* maintaining internally by the delta so that time maintains the
|
||||
* illusion of flowing smoothly forward.
|
||||
*/
|
||||
public void fastForward (long timeDelta);
|
||||
|
||||
/**
|
||||
* Paint this path on the screen (used for debugging purposes only).
|
||||
*/
|
||||
public void paint (Graphics2D gfx);
|
||||
|
||||
/**
|
||||
* When a path is removed from a pathable, whether that is because the
|
||||
* path was completed or because it was replaced by another path, this
|
||||
* method will be called to let the path know that it is no longer
|
||||
* associated with this pathable.
|
||||
*/
|
||||
public void wasRemoved (Pathable pable);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// $Id: PathNode.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
/**
|
||||
* A path node is a single destination point in a {@link Path}.
|
||||
*/
|
||||
public class PathNode
|
||||
{
|
||||
/** The node coordinates in screen pixels. */
|
||||
public Point loc;
|
||||
|
||||
/** The direction to face while heading toward the node. */
|
||||
public int dir;
|
||||
|
||||
/**
|
||||
* Construct a path node object.
|
||||
*
|
||||
* @param x the node x-position.
|
||||
* @param y the node y-position.
|
||||
* @param dir the facing direction.
|
||||
*/
|
||||
public PathNode (int x, int y, int dir)
|
||||
{
|
||||
loc = new Point(x, y);
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this path node.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("[");
|
||||
toString(buf);
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be overridden by derived classes (which should be sure
|
||||
* to call <code>super.toString()</code>) to append the derived class
|
||||
* specific path node information to the string buffer.
|
||||
*/
|
||||
public void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("x=").append(loc.x);
|
||||
buf.append(", y=").append(loc.y);
|
||||
buf.append(", dir=").append(dir);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// $Id: PathSequence.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Used to create a path that is a sequence of several other paths.
|
||||
*/
|
||||
public class PathSequence
|
||||
implements Path
|
||||
{
|
||||
/**
|
||||
* Conveniently construct a path sequence with the two specified
|
||||
* paths.
|
||||
*/
|
||||
public PathSequence (Path first, Path second)
|
||||
{
|
||||
this(new ArrayList());
|
||||
_paths.add(first);
|
||||
_paths.add(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a path sequence with the list of paths.
|
||||
* Note: Paths may be added to the end of the list while
|
||||
* the pathable is still traversing earlier paths!
|
||||
*/
|
||||
public PathSequence (List paths)
|
||||
{
|
||||
_paths = paths;
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void init (Pathable pable, long tickStamp)
|
||||
{
|
||||
_pable = pable;
|
||||
_pableRep = new DelegatingPathable(_pable) {
|
||||
public void pathCompleted (long timeStamp) {
|
||||
long initStamp;
|
||||
// if we just finished a timed path, we can figure out how
|
||||
// long ago it really finished and init the next path at
|
||||
// that time in the past.
|
||||
if (_curPath instanceof TimedPath) {
|
||||
initStamp = _lastInit + ((TimedPath) _curPath)._duration;
|
||||
} else {
|
||||
// we don't know
|
||||
initStamp = timeStamp;
|
||||
}
|
||||
initNextPath(initStamp, timeStamp);
|
||||
}
|
||||
};
|
||||
initNextPath(tickStamp, tickStamp);
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public boolean tick (Pathable pable, long tickStamp)
|
||||
{
|
||||
if (pable != _pable) {
|
||||
Log.warning("PathSequence ticked with different path than " +
|
||||
"it was inited with.");
|
||||
}
|
||||
return _curPath.tick(_pableRep, tickStamp);
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_lastInit += timeDelta;
|
||||
_curPath.fastForward(timeDelta);
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// for now..
|
||||
_curPath.paint(gfx);
|
||||
}
|
||||
|
||||
// documentation inherited from interface Path
|
||||
public void wasRemoved (Pathable pable)
|
||||
{
|
||||
if (_curPath != null) {
|
||||
_curPath.wasRemoved(_pableRep);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize and start the next path in the sequence.
|
||||
*/
|
||||
protected void initNextPath (long initStamp, long tickStamp)
|
||||
{
|
||||
if (_paths.size() == 0) {
|
||||
_pable.pathCompleted(tickStamp);
|
||||
|
||||
} else {
|
||||
_curPath = (Path) _paths.remove(0);
|
||||
_lastInit = initStamp;
|
||||
|
||||
_curPath.init(_pableRep, initStamp);
|
||||
_curPath.tick(_pableRep, tickStamp);
|
||||
}
|
||||
}
|
||||
|
||||
/** The list of paths. */
|
||||
protected List _paths;
|
||||
|
||||
/** The timestamp at which we last inited a path. */
|
||||
protected long _lastInit;
|
||||
|
||||
/** The current path we're pathing. */
|
||||
protected Path _curPath;
|
||||
|
||||
/** The pathable we're duping bigtime. */
|
||||
protected Pathable _pable;
|
||||
|
||||
/** A fake pathable that we pass to the subpaths. */
|
||||
protected Pathable _pableRep;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// $Id: Pathable.java 3310 2005-01-24 23:08:21Z mdb $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.util.DirectionCodes;
|
||||
|
||||
/**
|
||||
* Used in conjunction with a {@link Path}.
|
||||
*/
|
||||
public interface Pathable
|
||||
{
|
||||
/**
|
||||
* Returns the pathable's current x coordinate.
|
||||
*/
|
||||
public int getX ();
|
||||
|
||||
/**
|
||||
* Returns the pathable's current y coordinate.
|
||||
*/
|
||||
public int getY ();
|
||||
|
||||
/**
|
||||
* Returns the rectangle that bounds the pathable.
|
||||
*/
|
||||
public Rectangle getBounds ();
|
||||
|
||||
/**
|
||||
* Updates the pathable's current coordinates.
|
||||
*/
|
||||
public void setLocation (int x, int y);
|
||||
|
||||
/**
|
||||
* Will be called by a path when it moves the pathable in the
|
||||
* specified direction. Pathables that wish to face in the direction
|
||||
* they are moving can take advantage of this callback.
|
||||
*
|
||||
* @see DirectionCodes
|
||||
*/
|
||||
public void setOrientation (int orient);
|
||||
|
||||
/**
|
||||
* Should return the orientation of the pathable, or {@link
|
||||
* DirectionCodes#NONE} if the pathable does not support orientation.
|
||||
*/
|
||||
public int getOrientation ();
|
||||
|
||||
/**
|
||||
* Called by a path when this pathable is made to start along a path.
|
||||
*/
|
||||
public void pathBeginning ();
|
||||
|
||||
/**
|
||||
* Called by a path when this pathable finishes moving along its path.
|
||||
*/
|
||||
public void pathCompleted (long timestamp);
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// $Id: PerformanceMonitor.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
import com.threerings.media.timer.MediaTimer;
|
||||
import com.threerings.media.timer.SystemMediaTimer;
|
||||
|
||||
/**
|
||||
* Provides a simple mechanism for monitoring the number of times an
|
||||
* action takes place within a certain time period.
|
||||
*
|
||||
* <p> The action being tracked should be registered with a suitable name
|
||||
* via {@link #register}, and {@link #tick} should be called each time the
|
||||
* action is performed.
|
||||
*
|
||||
* <p> Whenever {@link #tick} is called and the checkpoint time interval
|
||||
* has elapsed since the last checkpoint (if any), the observer will be
|
||||
* notified to that effect by a call to {@link
|
||||
* PerformanceObserver#checkpoint}.
|
||||
*
|
||||
* <p> Note that this is <em>not</em> intended to be used as an
|
||||
* industrial-strength profiling or performance monitoring tool. The
|
||||
* checkpoint time interval granularity is in milliseconds, not
|
||||
* microseconds, and the observer's <code>checkpoint()</code> method will
|
||||
* never be called until/unless a subsequent call to {@link #tick} is made
|
||||
* after the requested number of milliseconds have passed since the last
|
||||
* checkpoint.
|
||||
*/
|
||||
public class PerformanceMonitor
|
||||
{
|
||||
/**
|
||||
* Register a new action with an observer, the action name, and
|
||||
* the milliseconds to wait between checkpointing the action's
|
||||
* performance.
|
||||
*
|
||||
* @param obs the action observer.
|
||||
* @param name the action name.
|
||||
* @param delta the milliseconds between checkpoints.
|
||||
*/
|
||||
public static void register (PerformanceObserver obs, String name,
|
||||
long delta)
|
||||
{
|
||||
// get the observer's action hashtable
|
||||
HashMap actions = (HashMap)_observers.get(obs);
|
||||
if (actions == null) {
|
||||
// create it if it didn't exist
|
||||
_observers.put(obs, actions = new HashMap());
|
||||
}
|
||||
|
||||
// add the action to the set we're tracking
|
||||
actions.put(name, new PerformanceAction(obs, name, delta));
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-register the named action associated with the given observer.
|
||||
*
|
||||
* @param obs the action observer.
|
||||
* @param name the action name.
|
||||
*/
|
||||
public static void unregister (PerformanceObserver obs, String name)
|
||||
{
|
||||
// get the observer's action hashtable
|
||||
HashMap actions = (HashMap)_observers.get(obs);
|
||||
if (actions == null) {
|
||||
Log.warning("Attempt to unregister by unknown observer " +
|
||||
"[observer=" + obs + ", name=" + name + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt to remove the specified action
|
||||
PerformanceAction action = (PerformanceAction)actions.remove(name);
|
||||
if (action == null) {
|
||||
Log.warning("Attempt to unregister unknown action " +
|
||||
"[observer=" + obs + ", name=" + name + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// if the observer has no actions left, remove the observer's action
|
||||
// hash in its entirety
|
||||
if (actions.size() == 0) {
|
||||
_observers.remove(obs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tick the named action associated with the given observer.
|
||||
*
|
||||
* @param obs the action observer.
|
||||
* @param name the action name.
|
||||
*/
|
||||
public static void tick (PerformanceObserver obs, String name)
|
||||
{
|
||||
// get the observer's action hashtable
|
||||
HashMap actions = (HashMap)_observers.get(obs);
|
||||
if (actions == null) {
|
||||
Log.warning("Attempt to tick by unknown observer " +
|
||||
"[observer=" + obs + ", name=" + name + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// get the specified action
|
||||
PerformanceAction action = (PerformanceAction)actions.get(name);
|
||||
if (action == null) {
|
||||
Log.warning("Attempt to tick unknown value " +
|
||||
"[observer=" + obs + ", name=" + name + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// tick the action
|
||||
action.tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to configure the performance monitor with a particular {@link
|
||||
* MediaTimer} implementation. By default it uses a pure-Java
|
||||
* implementation which isn't extremely accurate across platforms.
|
||||
*/
|
||||
public static void setMediaTimer (MediaTimer timer)
|
||||
{
|
||||
_timer = timer;
|
||||
}
|
||||
|
||||
/** Used by the performance actions. */
|
||||
protected synchronized static long getTimeStamp ()
|
||||
{
|
||||
return _timer.getElapsedMillis();
|
||||
}
|
||||
|
||||
/** The observers monitoring some set of actions. */
|
||||
protected static HashMap _observers = new HashMap();
|
||||
|
||||
/** Used to obtain high resolution time stamps. */
|
||||
protected static MediaTimer _timer = new SystemMediaTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents the individual actions being tracked by the
|
||||
* <code>PerformanceMonitor</code> class.
|
||||
*/
|
||||
class PerformanceAction
|
||||
{
|
||||
public PerformanceAction (PerformanceObserver obs, String name, long delta)
|
||||
{
|
||||
_obs = obs;
|
||||
_name = name;
|
||||
_delta = delta;
|
||||
_lastDelta = PerformanceMonitor.getTimeStamp();
|
||||
}
|
||||
|
||||
public void tick ()
|
||||
{
|
||||
_numTicks++;
|
||||
|
||||
long now = PerformanceMonitor.getTimeStamp();
|
||||
long passed = now - _lastDelta;
|
||||
if (passed >= _delta) {
|
||||
// update the last checkpoint time
|
||||
_lastDelta = now + (passed - _delta);
|
||||
|
||||
// notify our observer of the checkpoint
|
||||
_obs.checkpoint(_name, _numTicks);
|
||||
|
||||
// reset the tick count
|
||||
_numTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("[obs=").append(_obs);
|
||||
buf.append(", name=").append(_name);
|
||||
buf.append(", delta=").append(_delta);
|
||||
buf.append(", lastDelta=").append(_lastDelta);
|
||||
buf.append(", numTicks=").append(_numTicks);
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/** The performance observer. */
|
||||
protected PerformanceObserver _obs;
|
||||
|
||||
/** The action name. */
|
||||
protected String _name;
|
||||
|
||||
/** The number of milliseconds between each checkpoint. */
|
||||
protected long _delta;
|
||||
|
||||
/** The time the last time a checkpoint was made. */
|
||||
protected long _lastDelta;
|
||||
|
||||
/** The number of ticks since the last checkpoint. */
|
||||
protected int _numTicks;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// $Id: PerformanceObserver.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
/**
|
||||
* This interface should be implemented by classes that wish to register
|
||||
* actions to be monitored by the {@link PerformanceMonitor} class.
|
||||
*/
|
||||
public interface PerformanceObserver
|
||||
{
|
||||
/**
|
||||
* This method is called by the {@link PerformanceMonitor} class
|
||||
* whenever an action's requested time interval between checkpoints
|
||||
* has expired.
|
||||
*
|
||||
* @param name the action name.
|
||||
* @param ticks the ticks since the last checkpoint.
|
||||
*/
|
||||
public void checkpoint (String name, int ticks);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id: SingleFrameImageImpl.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* The single frame image class is a basic implementation of the {@link
|
||||
* MultiFrameImage} interface intended to facilitate the creation of MFIs
|
||||
* whose display frames consist of only a single image.
|
||||
*/
|
||||
public class SingleFrameImageImpl implements MultiFrameImage
|
||||
{
|
||||
/**
|
||||
* Constructs a single frame image object.
|
||||
*/
|
||||
public SingleFrameImageImpl (Mirage mirage)
|
||||
{
|
||||
_mirage = mirage;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getFrameCount ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getWidth (int index)
|
||||
{
|
||||
return _mirage.getWidth();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getHeight (int index)
|
||||
{
|
||||
return _mirage.getHeight();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void paintFrame (Graphics2D g, int index, int x, int y)
|
||||
{
|
||||
_mirage.paint(g, x, y);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean hitTest (int index, int x, int y)
|
||||
{
|
||||
return _mirage.hitTest(x, y);
|
||||
}
|
||||
|
||||
/** The frame image. */
|
||||
protected Mirage _mirage;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id: SingleTileImageImpl.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import com.threerings.media.tile.Tile;
|
||||
|
||||
/**
|
||||
* The single frame image class is a basic implementation of the {@link
|
||||
* MultiFrameImage} interface intended to facilitate the creation of MFIs
|
||||
* whose display frames consist of only a single tile image.
|
||||
*/
|
||||
public class SingleTileImageImpl implements MultiFrameImage
|
||||
{
|
||||
/**
|
||||
* Constructs a single frame image object.
|
||||
*/
|
||||
public SingleTileImageImpl (Tile tile)
|
||||
{
|
||||
_tile = tile;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getFrameCount ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getWidth (int index)
|
||||
{
|
||||
return _tile.getWidth();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getHeight (int index)
|
||||
{
|
||||
return _tile.getHeight();
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void paintFrame (Graphics2D g, int index, int x, int y)
|
||||
{
|
||||
_tile.paint(g, x, y);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean hitTest (int index, int x, int y)
|
||||
{
|
||||
return _tile.hitTest(x, y);
|
||||
}
|
||||
|
||||
/** The frame image. */
|
||||
protected Tile _tile;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
|
||||
/**
|
||||
* Bobble a Pathable smoothly.
|
||||
*/
|
||||
public class SmoothBobblePath extends BobblePath
|
||||
{
|
||||
public SmoothBobblePath (int dx, int dy, long duration)
|
||||
{
|
||||
this(dx, dy, duration, 1L);
|
||||
}
|
||||
|
||||
public SmoothBobblePath (int dx, int dy, long duration, long updateFreq)
|
||||
{
|
||||
super(dx, dy, duration, updateFreq);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void init (Pathable pable, long tickstamp)
|
||||
{
|
||||
super.init(pable, tickstamp);
|
||||
|
||||
_newx = _sx;
|
||||
_newy = _sy;
|
||||
_oldx = _sx;
|
||||
_oldy = _sy;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean tick (Pathable pable, long tickStamp)
|
||||
{
|
||||
// see if we need to stop
|
||||
if (_stopTime <= tickStamp) {
|
||||
boolean updated = updatePositionTo(pable, _sy, _sy);
|
||||
pable.pathCompleted(tickStamp);
|
||||
return updated;
|
||||
}
|
||||
|
||||
// see if it's time to update the position
|
||||
if (_nextMove < tickStamp) {
|
||||
_oldx = _newx;
|
||||
_oldy = _newy;
|
||||
do {
|
||||
_newx = _sx + RandomUtil.getInt(_dx * 2 + 1) - _dx;
|
||||
_newy = _sy + RandomUtil.getInt(_dy * 2 + 1) - _dy;
|
||||
} while (_newx == _oldx && _newy == _oldy);
|
||||
|
||||
_nextMove = tickStamp + _updateFreq;
|
||||
}
|
||||
|
||||
float movePerc = (float)(_nextMove - tickStamp) / (float)_updateFreq;
|
||||
int x = _oldx + (int)((_newx - _oldx) * movePerc);
|
||||
int y = _oldy + (int)((_newy - _oldy) * movePerc);
|
||||
// update the position
|
||||
return updatePositionTo(pable, x, y);
|
||||
}
|
||||
|
||||
/** The previous position. */
|
||||
protected int _oldx, _oldy;
|
||||
|
||||
/** The next position. */
|
||||
protected int _newx, _newy;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// $Id: TiledArea.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
* A component that can be inserted into a user interface to fill a
|
||||
* particular area using a {@link BackgroundTiler}.
|
||||
*/
|
||||
public class TiledArea extends JComponent
|
||||
{
|
||||
public TiledArea (BufferedImage imgsrc)
|
||||
{
|
||||
this(new BackgroundTiler(imgsrc));
|
||||
}
|
||||
|
||||
public TiledArea (BackgroundTiler tiler)
|
||||
{
|
||||
_tiler = tiler;
|
||||
setOpaque(true);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
_tiler.paint(g, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Dimension getPreferredSize ()
|
||||
{
|
||||
return new Dimension(_tiler.getNaturalWidth(),
|
||||
_tiler.getNaturalHeight());
|
||||
}
|
||||
|
||||
protected BackgroundTiler _tiler;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// $Id: TimeFunction.java 4191 2006-06-13 22:42:20Z ray $
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
/**
|
||||
* Used to vary a value over time where time is provided at discrete
|
||||
* increments (on the frame tick) and the value is computed appropriately.
|
||||
*/
|
||||
public abstract class TimeFunction
|
||||
{
|
||||
/**
|
||||
* Every time function varies a value from some starting value to some
|
||||
* ending value over some duration. The way in which it varies
|
||||
* (linearly, for example) is up to the derived class.
|
||||
*
|
||||
* <p><em>Note:</em> it is assumed that we will operate with
|
||||
* relatively short durations such that integer arithmetic may be used
|
||||
* rather than long arithmetic.
|
||||
*/
|
||||
public TimeFunction (int start, int end, int duration)
|
||||
{
|
||||
_start = start;
|
||||
_end = end;
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this function with a starting time. This method need not
|
||||
* be called, and instead the first vall to {@link #getValue} will be
|
||||
* used to obtain a starting time stamp.
|
||||
*/
|
||||
public void init (long tickStamp)
|
||||
{
|
||||
_startStamp = tickStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to fast forward our time stamps if we are ever paused and
|
||||
* need to resume where we left off.
|
||||
*/
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_startStamp += timeDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value given the supplied time stamp. The value
|
||||
* will be bounded to the originally supplied starting and ending
|
||||
* values at times 0 (and below) and {@link #_duration} (and above)
|
||||
* respectively.
|
||||
*/
|
||||
public int getValue (long tickStamp)
|
||||
{
|
||||
if (_startStamp == 0L) {
|
||||
_startStamp = tickStamp;
|
||||
}
|
||||
|
||||
int dt = (int)(tickStamp - _startStamp);
|
||||
if (dt <= 0) {
|
||||
return _start;
|
||||
} else if (dt >= _duration) {
|
||||
return _end;
|
||||
} else {
|
||||
return computeValue(dt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be implemented by our derived class to compute our value
|
||||
* given the specified elapsed time (in millis).
|
||||
*/
|
||||
protected abstract int computeValue (int dt);
|
||||
|
||||
/** Our starting and ending values. */
|
||||
protected int _start, _end;
|
||||
|
||||
/** The number of milliseconds over which we vary our value. */
|
||||
protected int _duration;
|
||||
|
||||
/** The timestamp at which we began varying our value. */
|
||||
protected long _startStamp;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// $Id: TimedPath.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* A base class for path implementations that endeavor to move their
|
||||
* pathables along a path in a specified number of milliseconds.
|
||||
*/
|
||||
public abstract class TimedPath implements Path
|
||||
{
|
||||
/**
|
||||
* Configures the timed path with the duration in which it must
|
||||
* traverse its path.
|
||||
*/
|
||||
public TimedPath (long duration)
|
||||
{
|
||||
// sanity check some things
|
||||
if (duration <= 0) {
|
||||
Log.warning("Requested path with illegal duration (<=0) " +
|
||||
"[duration=" + duration + "]");
|
||||
Thread.dumpStack();
|
||||
duration = 1; // assume something short but non-zero
|
||||
}
|
||||
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void init (Pathable pable, long timestamp)
|
||||
{
|
||||
// give the pable a chance to perform any starting antics
|
||||
pable.pathBeginning();
|
||||
|
||||
// make a note of when we started
|
||||
_startStamp = timestamp;
|
||||
|
||||
// we'll be ticked immediately following init() which will update
|
||||
// our position to the start of our path
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_startStamp += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void wasRemoved (Pathable pable)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this instance.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder("[");
|
||||
toString(buf);
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An extensible method for generating a string representation of this
|
||||
* instance.
|
||||
*/
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("duration=").append(_duration).append("ms");
|
||||
}
|
||||
|
||||
/** The duration that we're to spend following the path. */
|
||||
protected long _duration;
|
||||
|
||||
/** The time at which we started along the path. */
|
||||
protected long _startStamp;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// $Id: TrailingAverage.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.util;
|
||||
|
||||
/**
|
||||
* Used to compute a trailing average of a value.
|
||||
*/
|
||||
public class TrailingAverage
|
||||
{
|
||||
/**
|
||||
* Creates a trailing average instance with the default number of
|
||||
* values used to compute the average (10).
|
||||
*/
|
||||
public TrailingAverage ()
|
||||
{
|
||||
this(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a trailing average instance with the specified number of
|
||||
* values used to compute the average.
|
||||
*/
|
||||
public TrailingAverage (int history)
|
||||
{
|
||||
_history = new int[history];
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a new value.
|
||||
*/
|
||||
public void record (int value)
|
||||
{
|
||||
_history[_index++%_history.length] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current averaged value.
|
||||
*/
|
||||
public int value ()
|
||||
{
|
||||
int end = Math.min(_history.length, _index);
|
||||
int value = 0;
|
||||
for (int ii = 0; ii < end; ii++) {
|
||||
value += _history[ii];
|
||||
}
|
||||
return (end > 0) ? (value/end) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current trailing average value as a string.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return Integer.toString(value());
|
||||
}
|
||||
|
||||
/** The history of values. */
|
||||
protected int[] _history;
|
||||
|
||||
/** The index where we will next record a value. */
|
||||
protected int _index;
|
||||
}
|
||||
Reference in New Issue
Block a user