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,169 @@
|
||||
//
|
||||
// $Id: Animation.java 3822 2006-01-27 03:28:04Z 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.animation;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.util.ObserverList;
|
||||
|
||||
import com.threerings.media.AbstractMedia;
|
||||
|
||||
/**
|
||||
* The animation class is an abstract class that should be extended to
|
||||
* provide animation functionality. It is generally used in conjunction
|
||||
* with an {@link AnimationManager}.
|
||||
*/
|
||||
public abstract class Animation extends AbstractMedia
|
||||
{
|
||||
/**
|
||||
* Constructs an animation.
|
||||
*
|
||||
* @param bounds the animation rendering bounds.
|
||||
*/
|
||||
public Animation (Rectangle bounds)
|
||||
{
|
||||
super(bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the animation has finished all of its business,
|
||||
* false if not.
|
||||
*/
|
||||
public boolean isFinished ()
|
||||
{
|
||||
return _finished;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this animation has run to completion, it can be reset to prepare
|
||||
* it for another go.
|
||||
*/
|
||||
public void reset ()
|
||||
{
|
||||
_finished = false;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setLocation (int x, int y)
|
||||
{
|
||||
if (_bounds.x == x && _bounds.y == y) {
|
||||
return; // no-op
|
||||
}
|
||||
|
||||
// start with our current bounds
|
||||
Rectangle dirty = new Rectangle(_bounds);
|
||||
|
||||
// move ourselves
|
||||
super.setLocation(x, y);
|
||||
|
||||
// grow the dirty rectangle to incorporate our new bounds and pass
|
||||
// the dirty region to our region manager
|
||||
if (_mgr != null) {
|
||||
// if our new bounds intersect our old bounds, grow a single
|
||||
// dirty rectangle to incorporate them both
|
||||
if (_bounds.intersects(dirty)) {
|
||||
dirty.add(_bounds);
|
||||
} else {
|
||||
// otherwise invalidate our new bounds separately
|
||||
_mgr.getRegionManager().invalidateRegion(_bounds);
|
||||
}
|
||||
_mgr.getRegionManager().addDirtyRegion(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void willStart (long tickStamp)
|
||||
{
|
||||
super.willStart(tickStamp);
|
||||
queueNotification(new AnimStartedOp(this, tickStamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the animation is finished and the animation manager is
|
||||
* about to remove it from service.
|
||||
*/
|
||||
protected void willFinish (long tickStamp)
|
||||
{
|
||||
queueNotification(new AnimCompletedOp(this, tickStamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the animation is finished and the animation manager has
|
||||
* removed it from service.
|
||||
*/
|
||||
protected void didFinish (long tickStamp)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an animation observer to this animation's list of observers.
|
||||
*/
|
||||
public void addAnimationObserver (AnimationObserver obs)
|
||||
{
|
||||
addObserver(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an animation observer from this animation's list of observers.
|
||||
*/
|
||||
public void removeAnimationObserver (AnimationObserver obs)
|
||||
{
|
||||
removeObserver(obs);
|
||||
}
|
||||
|
||||
/** Whether the animation is finished. */
|
||||
protected boolean _finished = false;
|
||||
|
||||
/** Used to dispatch {@link AnimationObserver#animationStarted}. */
|
||||
protected static class AnimStartedOp implements ObserverList.ObserverOp
|
||||
{
|
||||
public AnimStartedOp (Animation anim, long when) {
|
||||
_anim = anim;
|
||||
_when = when;
|
||||
}
|
||||
|
||||
public boolean apply (Object observer) {
|
||||
((AnimationObserver)observer).animationStarted(_anim, _when);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Animation _anim;
|
||||
protected long _when;
|
||||
}
|
||||
|
||||
/** Used to dispatch {@link AnimationObserver#animationCompleted}. */
|
||||
protected static class AnimCompletedOp implements ObserverList.ObserverOp
|
||||
{
|
||||
public AnimCompletedOp (Animation anim, long when) {
|
||||
_anim = anim;
|
||||
_when = when;
|
||||
}
|
||||
|
||||
public boolean apply (Object observer) {
|
||||
((AnimationObserver)observer).animationCompleted(_anim, _when);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Animation _anim;
|
||||
protected long _when;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// $Id: AnimationAdapter.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.animation;
|
||||
|
||||
/**
|
||||
* An adapter class for {@link AnimationObserver}.
|
||||
*/
|
||||
public class AnimationAdapter implements AnimationObserver
|
||||
{
|
||||
// documentation inherited from interface
|
||||
public void animationStarted (Animation anim, long when)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void animationCompleted (Animation anim, long when)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// $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.animation;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* A utility class for positioning animations such that they don't overlap,
|
||||
* as best as possible.
|
||||
*/
|
||||
public class AnimationArranger
|
||||
{
|
||||
/**
|
||||
* Position the specified animation so that it is not overlapping
|
||||
* any still-running animations previously passed to this method.
|
||||
*/
|
||||
public void positionAvoidAnimation (Animation anim, Rectangle viewBounds)
|
||||
{
|
||||
Rectangle abounds = new Rectangle(anim.getBounds());
|
||||
ArrayList avoidables = (ArrayList) _avoidAnims.clone();
|
||||
// if we are able to place it somewhere, do so
|
||||
if (SwingUtil.positionRect(abounds, viewBounds, avoidables)) {
|
||||
anim.setLocation(abounds.x, abounds.y);
|
||||
}
|
||||
|
||||
// add the animation to the list of avoidables
|
||||
_avoidAnims.add(anim);
|
||||
// keep an eye on it so that we can remove it when it's finished
|
||||
anim.addAnimationObserver(_avoidAnimObs);
|
||||
}
|
||||
|
||||
/** The animations that other animations may wish to avoid. */
|
||||
protected ArrayList _avoidAnims = new ArrayList();
|
||||
|
||||
/** Automatically removes avoid animations when they're done. */
|
||||
protected AnimationAdapter _avoidAnimObs = new AnimationAdapter() {
|
||||
public void animationCompleted (Animation anim, long when) {
|
||||
if (!_avoidAnims.remove(anim)) {
|
||||
Log.warning("Couldn't remove avoid animation?! " + anim + ".");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
//
|
||||
// $Id: AnimationFrameSequencer.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.animation;
|
||||
|
||||
import com.samskivert.util.ObserverList;
|
||||
|
||||
import com.threerings.media.util.FrameSequencer;
|
||||
import com.threerings.media.util.MultiFrameImage;
|
||||
|
||||
/**
|
||||
* Used to control animation timing when displaying an animation.
|
||||
*/
|
||||
public interface AnimationFrameSequencer extends FrameSequencer
|
||||
{
|
||||
/**
|
||||
* Called after init to set the animation.
|
||||
*/
|
||||
public void setAnimation (Animation anim);
|
||||
|
||||
/**
|
||||
* A sequencer that can step through a series of frames in any order
|
||||
* and speed and notify (via {@link SequencedAnimationObserver}) when
|
||||
* specific frames are reached.
|
||||
*/
|
||||
public static class MultiFunction implements AnimationFrameSequencer
|
||||
{
|
||||
/**
|
||||
* Creates the simplest multifunction frame sequencer.
|
||||
*
|
||||
* @param sequence the ordering to display the frames.
|
||||
* @param msPerFrame the number of ms to display each frame.
|
||||
* @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 MultiFunction (int[] sequence, long msPerFrame, boolean loop)
|
||||
{
|
||||
_length = sequence.length;
|
||||
_sequence = sequence;
|
||||
setDelay(msPerFrame);
|
||||
_marks = new boolean[_length];
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fully-specified multifunction frame sequencer.
|
||||
*
|
||||
* @param sequence the ordering to display the frames.
|
||||
* @param msPerFrame the number of ms to display each frame.
|
||||
* @param marks if true for a frame, a FrameReachedEvent will
|
||||
* be generated when that frame is reached.
|
||||
* @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 MultiFunction (
|
||||
int[] sequence, long[] msPerFrame, boolean[] marks, boolean loop)
|
||||
{
|
||||
_length = sequence.length;
|
||||
if ((_length != msPerFrame.length) || (_length != marks.length)) {
|
||||
throw new IllegalArgumentException(
|
||||
"All MultiFunction FrameSequencer arrays must be " +
|
||||
"the same length.");
|
||||
}
|
||||
|
||||
_sequence = sequence;
|
||||
_delays = msPerFrame;
|
||||
_marks = marks;
|
||||
_loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay to use.
|
||||
*/
|
||||
public void setDelay (long msPerFrame)
|
||||
{
|
||||
_delays = null;
|
||||
_delay = msPerFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of the sequence we are to use, or 0 means set
|
||||
* it to the length of the sequence array that we were constructed with.
|
||||
*/
|
||||
public void setLength (int len)
|
||||
{
|
||||
_length = (len == 0) ? _sequence.length : len;
|
||||
if (_curIdx >= _length) {
|
||||
_curIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we reset the animation on init? Default is true.
|
||||
*/
|
||||
public void setResetOnInit (boolean resets)
|
||||
{
|
||||
_resets = resets;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void init (MultiFrameImage source)
|
||||
{
|
||||
int framecount = source.getFrameCount();
|
||||
// let's make sure our frames are valid
|
||||
for (int ii=0; ii < _length; ii++) {
|
||||
if (_sequence[ii] >= framecount) {
|
||||
throw new IllegalArgumentException(
|
||||
"MultiFunction FrameSequencer was initialized " +
|
||||
"with a MultiFrameImage with not enough frames " +
|
||||
"to match the sequence it was constructed with.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_resets) {
|
||||
_lastStamp = 0L;
|
||||
_curIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void setAnimation (Animation anim)
|
||||
{
|
||||
_animation = anim;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int tick (long tickStamp)
|
||||
{
|
||||
// obtain our starting timestamp if we don't already have one
|
||||
if (_lastStamp == 0L) {
|
||||
_lastStamp = tickStamp;
|
||||
// we might need to notify on the first frame
|
||||
checkNotify(tickStamp);
|
||||
}
|
||||
|
||||
// we may have rushed through more than one frame since the last
|
||||
// tick, but we want to always notify even if we never displayed
|
||||
long curdelay = getDelay(_curIdx);
|
||||
while (tickStamp >= (_lastStamp + curdelay)) {
|
||||
_lastStamp += curdelay;
|
||||
_curIdx++;
|
||||
if (_curIdx == _length) {
|
||||
if (_loop) {
|
||||
_curIdx = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
checkNotify(tickStamp);
|
||||
|
||||
// get the delay for checking the next frame
|
||||
curdelay = getDelay(_curIdx);
|
||||
}
|
||||
|
||||
// return the right frame
|
||||
return _sequence[_curIdx];
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
// this method should be called "unpause"
|
||||
_lastStamp += timeDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the delay to use for the specified frame.
|
||||
*/
|
||||
protected final long getDelay (int index)
|
||||
{
|
||||
return (_delays == null) ? _delay : _delays[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if we need to notify that we've reached a marked frame.
|
||||
*/
|
||||
protected void checkNotify (long tickStamp)
|
||||
{
|
||||
if (_marks[_curIdx]) {
|
||||
_animation.queueNotification(
|
||||
new FrameReachedOp(_animation, tickStamp,
|
||||
_sequence[_curIdx], _curIdx));
|
||||
}
|
||||
}
|
||||
|
||||
/** The current sequence index. */
|
||||
protected int _curIdx = 0;
|
||||
|
||||
/** The length of our animation sequence. */
|
||||
protected int _length;
|
||||
|
||||
/** Do we reset on init? */
|
||||
protected boolean _resets = true;
|
||||
|
||||
/** The sequence of frames to display. */
|
||||
protected int[] _sequence;
|
||||
|
||||
/** The corresponding delay for each frame, in ms. */
|
||||
protected long[] _delays;
|
||||
|
||||
/** Or a single delay for all frames. */
|
||||
protected long _delay;
|
||||
|
||||
/** Whether to send a FrameReachedEvent on a sequence index. */
|
||||
protected boolean[] _marks;
|
||||
|
||||
/** Does the animation loop? */
|
||||
protected boolean _loop;
|
||||
|
||||
/** The time at which we were last ticked. */
|
||||
protected long _lastStamp;
|
||||
|
||||
/** The animation that we're sequencing for. */
|
||||
protected Animation _animation;
|
||||
|
||||
/** Used to dispatch {@link SequencedAnimationObserver#frameReached}. */
|
||||
protected static class FrameReachedOp implements ObserverList.ObserverOp
|
||||
{
|
||||
public FrameReachedOp (Animation anim, long when,
|
||||
int frameIdx, int frameSeq) {
|
||||
_anim = anim;
|
||||
_when = when;
|
||||
_frameIdx = frameIdx;
|
||||
_frameSeq = frameSeq;
|
||||
}
|
||||
|
||||
public boolean apply (Object observer) {
|
||||
if (observer instanceof SequencedAnimationObserver) {
|
||||
((SequencedAnimationObserver)observer).frameReached(
|
||||
_anim, _when, _frameIdx, _frameSeq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Animation _anim;
|
||||
protected long _when;
|
||||
protected int _frameIdx, _frameSeq;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// $Id: AnimationManager.java 3347 2005-02-14 03:00:58Z 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.animation;
|
||||
|
||||
import com.threerings.media.AbstractMediaManager;
|
||||
import com.threerings.media.MediaPanel;
|
||||
|
||||
/**
|
||||
* Manages a collection of animations, ticking them when the animation
|
||||
* manager itself is ticked and generating events when animations finish
|
||||
* and suchlike.
|
||||
*/
|
||||
public class AnimationManager extends AbstractMediaManager
|
||||
{
|
||||
/**
|
||||
* Construct and initialize the animation manager which readies itself
|
||||
* to manage animations.
|
||||
*/
|
||||
public AnimationManager (MediaPanel panel)
|
||||
{
|
||||
super(panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given {@link Animation} with the animation manager
|
||||
* for ticking and painting.
|
||||
*/
|
||||
public void registerAnimation (Animation anim)
|
||||
{
|
||||
insertMedia(anim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-registers the given {@link Animation} from the animation
|
||||
* manager. The bounds of the animation will automatically be
|
||||
* invalidated so that they are properly rerendered in the absence of
|
||||
* the animation.
|
||||
*/
|
||||
public void unregisterAnimation (Animation anim)
|
||||
{
|
||||
removeMedia(anim);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void tickAllMedia (long tickStamp)
|
||||
{
|
||||
super.tickAllMedia(tickStamp);
|
||||
|
||||
for (int ii = _media.size() - 1; ii >= 0; ii--) {
|
||||
Animation anim = (Animation)_media.get(ii);
|
||||
if (!anim.isFinished()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// as the anim is finished, remove it and notify observers
|
||||
anim.willFinish(tickStamp);
|
||||
unregisterAnimation(anim);
|
||||
anim.didFinish(tickStamp);
|
||||
// Log.info("Removed finished animation " + anim + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// $Id: AnimationObserver.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.animation;
|
||||
|
||||
/**
|
||||
* An interface to be implemented by classes that would like to observe an
|
||||
* {@link Animation} and be notified of interesting events relating to it.
|
||||
*/
|
||||
public interface AnimationObserver
|
||||
{
|
||||
/**
|
||||
* Called the first time this animation is ticked.
|
||||
*/
|
||||
public void animationStarted (Animation anim, long when);
|
||||
|
||||
/**
|
||||
* Called when the observed animation has completed.
|
||||
*/
|
||||
public void animationCompleted (Animation anim, long when);
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
//
|
||||
// $Id: AnimationSequencer.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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* An animation that provides facilities for adding a sequence of
|
||||
* animations that are fired after a fixed time interval has elapsed or
|
||||
* after previous animations in the sequence have completed. Facilities
|
||||
* are also provided for running code upon the completion of animations in
|
||||
* the sequence.
|
||||
*/
|
||||
public class AnimationSequencer extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs an animation sequencer with the expectation that
|
||||
* animations will be added via subsequent calls to {@link
|
||||
* #addAnimation}.
|
||||
*
|
||||
* @param animmgr the animation manager to which to add our animations
|
||||
* when they are ready to start.
|
||||
*/
|
||||
public AnimationSequencer (AnimationManager animmgr)
|
||||
{
|
||||
super(new Rectangle());
|
||||
_animmgr = animmgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied animation to the sequence with the given
|
||||
* parameters. Note that care should be taken if this is called after
|
||||
* the animation sequence has begun firing animations. Do not add new
|
||||
* animations after the final animation in the sequence has been
|
||||
* started or you run the risk of attempting to add an animation to
|
||||
* the sequence after it thinks that it has finished (in which case
|
||||
* this method will fail).
|
||||
*
|
||||
* @param anim the animation to be sequenced, or null if the
|
||||
* completion action should be run immediately when this "animation"
|
||||
* is ready to fired.
|
||||
* @param delta the number of milliseconds following the
|
||||
* <em>start</em> of the previous animation in the queue that this
|
||||
* animation should be started; 0 if it should be started
|
||||
* simultaneously with its predecessor int the queue; -1 if it should
|
||||
* be started when its predecessor has completed.
|
||||
* @param completionAction a runnable to be executed when this
|
||||
* animation completes.
|
||||
*/
|
||||
public void addAnimation (
|
||||
Animation anim, long delta, Runnable completionAction)
|
||||
{
|
||||
// sanity check
|
||||
if (_finished) {
|
||||
throw new IllegalStateException(
|
||||
"Animation added to finished sequencer");
|
||||
}
|
||||
|
||||
// if this guy is triggering on a previous animation, grab that
|
||||
// good fellow here
|
||||
AnimRecord trigger = null;
|
||||
if (delta == -1) {
|
||||
if (_queued.size() > 0) {
|
||||
// if there are queued animations we want the most
|
||||
// recently queued animation
|
||||
trigger = (AnimRecord)_queued.get(_queued.size()-1);
|
||||
} else if (_running.size() > 0) {
|
||||
// otherwise, if there are running animations, we want the
|
||||
// last one in that list
|
||||
trigger = (AnimRecord)_running.get(_running.size()-1);
|
||||
}
|
||||
// otherwise we have no trigger, we'll just start ASAP
|
||||
}
|
||||
|
||||
AnimRecord arec = new AnimRecord(
|
||||
anim, delta, trigger, completionAction);
|
||||
// Log.info("Queued " + arec + ".");
|
||||
_queued.add(arec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out the animations being managed by this sequencer.
|
||||
*/
|
||||
public void clear ()
|
||||
{
|
||||
_queued.clear();
|
||||
_lastStamp = 0;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
if (_lastStamp == 0) {
|
||||
_lastStamp = tickStamp;
|
||||
}
|
||||
|
||||
// add all animations whose time has come
|
||||
while (_queued.size() > 0) {
|
||||
AnimRecord arec = (AnimRecord)_queued.get(0);
|
||||
if (!arec.readyToFire(tickStamp, _lastStamp)) {
|
||||
// if it's not time to add this animation, all subsequent
|
||||
// animations must surely wait as well
|
||||
break;
|
||||
}
|
||||
|
||||
// remove it from queued and put it on the running list
|
||||
_queued.remove(0);
|
||||
_running.add(arec);
|
||||
|
||||
// note that we've advanced to the next animation
|
||||
_lastStamp = tickStamp;
|
||||
|
||||
// fire in the hole!
|
||||
arec.fire(tickStamp);
|
||||
}
|
||||
|
||||
// we're done when both lists are empty
|
||||
// boolean finished = _finished;
|
||||
_finished = ((_queued.size() + _running.size()) == 0);
|
||||
// if (!finished && _finished) {
|
||||
// Log.info("Finishing sequence at " + (tickStamp%10000) + ".");
|
||||
// }
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// don't care
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_lastStamp += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void viewLocationDidChange (int dx, int dy)
|
||||
{
|
||||
super.viewLocationDidChange(dx, dy);
|
||||
|
||||
// track cumulative view location changes so that we can adjust our
|
||||
// animations before we start them
|
||||
_vdx += dx;
|
||||
_vdy += dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the time comes to start an animation. Derived classes
|
||||
* may override this method and pass the animation on to their
|
||||
* animation manager and do whatever else they need to do with
|
||||
* operating animations. The default implementation simply adds them
|
||||
* to the media panel supplied when we were constructed.
|
||||
*
|
||||
* @param anim the animation to be displayed.
|
||||
* @param tickStamp the timestamp at which this animation was fired.
|
||||
*/
|
||||
protected void startAnimation (Animation anim, long tickStamp)
|
||||
{
|
||||
// account for any view scrolling that happened before this animation
|
||||
// was actually added to the view
|
||||
if (_vdx != 0 || _vdy != 0) {
|
||||
anim.viewLocationDidChange(_vdx, _vdy);
|
||||
}
|
||||
|
||||
_animmgr.registerAnimation(anim);
|
||||
}
|
||||
|
||||
protected class AnimRecord extends AnimationAdapter
|
||||
{
|
||||
public AnimRecord (Animation anim, long delta, AnimRecord trigger,
|
||||
Runnable completionAction) {
|
||||
_anim = anim;
|
||||
_delta = delta;
|
||||
_trigger = trigger;
|
||||
_completionAction = completionAction;
|
||||
}
|
||||
|
||||
public boolean readyToFire (long now, long lastStamp)
|
||||
{
|
||||
if (_delta == -1) {
|
||||
// if we have no trigger, that means we should start
|
||||
// immediately, otherwise we wait until our trigger is no
|
||||
// longer running (they are guaranteed not to be still
|
||||
// queued at this point because readyToFire is only called
|
||||
// on an animation after all animations previous in the
|
||||
// queue have been started)
|
||||
return (_trigger == null) ?
|
||||
true : !_running.contains(_trigger);
|
||||
|
||||
} else {
|
||||
return (lastStamp + _delta <= now);
|
||||
}
|
||||
}
|
||||
|
||||
public void fire (long when)
|
||||
{
|
||||
// Log.info("Firing " + this + " at " + (when%10000) + ".");
|
||||
|
||||
// if we have an animation, start it up and await its
|
||||
// completion
|
||||
if (_anim != null) {
|
||||
startAnimation(_anim, when);
|
||||
_anim.addAnimationObserver(this);
|
||||
|
||||
} else {
|
||||
// since there's no animation, we need to fire our
|
||||
// completion routine immediately
|
||||
fireCompletion(when);
|
||||
}
|
||||
}
|
||||
|
||||
public void fireCompletion (long when)
|
||||
{
|
||||
// Log.info("Completing " + this + " at " + (when%10000) + ".");
|
||||
|
||||
// call the completion action, if there is one
|
||||
if (_completionAction != null) {
|
||||
try {
|
||||
_completionAction.run();
|
||||
} catch (Throwable t) {
|
||||
Log.logStackTrace(t);
|
||||
}
|
||||
}
|
||||
|
||||
// make a note that this animation is complete
|
||||
_running.remove(this);
|
||||
|
||||
// kids, don't try this at home; we call tick() immediately so
|
||||
// that any animations triggered on the completion of previous
|
||||
// animations can trigger on the completion of this animation
|
||||
// rather than having to wait until the next tick to do so
|
||||
tick(when);
|
||||
}
|
||||
|
||||
public void animationCompleted (Animation anim, long when)
|
||||
{
|
||||
fireCompletion(when);
|
||||
}
|
||||
|
||||
public String toString ()
|
||||
{
|
||||
return "[anim=" + StringUtil.shortClassName(_anim) +
|
||||
((_anim == null) ? "" : ("/" + _anim.hashCode())) +
|
||||
", action=" + _completionAction +
|
||||
", delta=" + _delta + ", trig=" + (_trigger != null) + "]";
|
||||
}
|
||||
|
||||
protected Animation _anim;
|
||||
protected Runnable _completionAction;
|
||||
protected long _delta;
|
||||
protected AnimRecord _trigger;
|
||||
}
|
||||
|
||||
/** The animation manager in which we run animations. */
|
||||
protected AnimationManager _animmgr;
|
||||
|
||||
/** Animations that have not been fired. */
|
||||
protected ArrayList _queued = new ArrayList();
|
||||
|
||||
/** Animations that are currently running. */
|
||||
protected ArrayList _running = new ArrayList();
|
||||
|
||||
/** The timestamp at which we fired the last animation. */
|
||||
protected long _lastStamp;
|
||||
|
||||
/** Used to track view scrolling while animations are in limbo. */
|
||||
protected int _vdx, _vdy;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// $Id: AnimationWaiter.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.animation;
|
||||
|
||||
/**
|
||||
* An abstract class that simplifies a common animation usage case in
|
||||
* which a number of animations are created and the creator would like to
|
||||
* be able to perform specific actions when each animation has completed
|
||||
* (see {@link #animationDidFinish} and/or when all animations are
|
||||
* finished (see {@link #allAnimationsFinished}.)
|
||||
*/
|
||||
public abstract class AnimationWaiter
|
||||
implements AnimationObserver
|
||||
{
|
||||
/**
|
||||
* Adds an animation to the animation waiter for observation.
|
||||
*/
|
||||
public void addAnimation (Animation anim)
|
||||
{
|
||||
anim.addAnimationObserver(this);
|
||||
_animCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied animations to the animation waiter for
|
||||
* observation.
|
||||
*/
|
||||
public void addAnimations (Animation[] anims)
|
||||
{
|
||||
int acount = anims.length;
|
||||
for (int ii = 0; ii < acount; ii++) {
|
||||
addAnimation(anims[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void animationStarted (Animation anim, long when)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void animationCompleted (Animation anim, long when)
|
||||
{
|
||||
// note that the animation is finished
|
||||
animationDidFinish(anim);
|
||||
_animCount--;
|
||||
|
||||
// let derived classes know when all is done
|
||||
if (_animCount == 0) {
|
||||
allAnimationsFinished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an animation being observed by the waiter has
|
||||
* completed its business. Derived classes may wish to override
|
||||
* this method to engage in their unique antics.
|
||||
*/
|
||||
protected void animationDidFinish (Animation anim)
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when all animations being observed by the waiter have
|
||||
* completed their business. Derived classes may wish to override
|
||||
* this method to engage in their unique antics.
|
||||
*/
|
||||
protected void allAnimationsFinished ()
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
/** The number of animations. */
|
||||
protected int _animCount;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// $Id: BlankAnimation.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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Displays nothing, but does so for a specified amount of time. Useful
|
||||
* when you want to get an animation completed event in some period of
|
||||
* time but don't actually need to display anything.
|
||||
*/
|
||||
public class BlankAnimation extends Animation
|
||||
{
|
||||
public BlankAnimation (long duration)
|
||||
{
|
||||
super(new Rectangle(0, 0, 0, 0));
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
if (_start == 0) {
|
||||
// initialize our starting time
|
||||
_start = timestamp;
|
||||
}
|
||||
|
||||
// check whether we're done
|
||||
_finished = (timestamp - _start >= _duration);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
if (_start > 0) {
|
||||
_start += timeDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
protected long _duration, _start;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// $Id: BlendAnimation.java 4191 2006-06-13 22:42:20Z ray $
|
||||
|
||||
package com.threerings.media.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.media.util.LinearTimeFunction;
|
||||
import com.threerings.media.util.TimeFunction;
|
||||
|
||||
/**
|
||||
* Blends between a series of images using alpha.
|
||||
*/
|
||||
public class BlendAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Blends from the starting image through each successive image in the
|
||||
* specified amount of time (blending between each image takes place
|
||||
* in <code>delay</code> milliseconds).
|
||||
*/
|
||||
public BlendAnimation (int x, int y, Mirage[] images, int delay)
|
||||
{
|
||||
super(new Rectangle(x, y, images[0].getWidth(), images[0].getHeight()));
|
||||
_images = images;
|
||||
int fades = images.length-1;
|
||||
_tfunc = new LinearTimeFunction(0, 100 * fades, delay * fades);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
// check to see if our blend level has changed
|
||||
int level = _tfunc.getValue(timestamp);
|
||||
if (level == _level) {
|
||||
return;
|
||||
}
|
||||
// stop if we reach the end
|
||||
if (level == 100*(_images.length-1)) {
|
||||
_finished = true;
|
||||
}
|
||||
_level = level;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_tfunc.fastForward(timeDelta);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
int index = _level / 100;
|
||||
float alpha = 1f - (_level % 100) / 100f;
|
||||
|
||||
Composite ocomp = gfx.getComposite();
|
||||
gfx.setComposite(AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, alpha));
|
||||
_images[index].paint(gfx, _bounds.x, _bounds.y);
|
||||
if (index < _images.length-1) {
|
||||
gfx.setComposite(AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, 1f-alpha));
|
||||
_images[index+1].paint(gfx, _bounds.x, _bounds.y);
|
||||
}
|
||||
gfx.setComposite(ocomp);
|
||||
}
|
||||
|
||||
/** The images between which we are blending. */
|
||||
protected Mirage[] _images;
|
||||
|
||||
/** The time function we're using to time our blends. */
|
||||
protected TimeFunction _tfunc;
|
||||
|
||||
/** Our current blend level and image index all wrapped into one. */
|
||||
protected int _level;
|
||||
|
||||
/** The alpha composite used to render our current image. */
|
||||
protected AlphaComposite _currentComp;
|
||||
|
||||
/** The alpha composite used to render our "next" image. */
|
||||
protected AlphaComposite _nextComp;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// $Id: BobbleAnimation.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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* An animation that bobbles an image around within a specific horizontal
|
||||
* and vertical pixel range for a given period of time.
|
||||
*/
|
||||
public class BobbleAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs a bobble animation.
|
||||
*
|
||||
* @param image the image to animate.
|
||||
* @param sx the starting x-position.
|
||||
* @param sy the starting y-position.
|
||||
* @param rx the horizontal bobble range.
|
||||
* @param ry the vertical bobble range.
|
||||
* @param duration the time to animate in milliseconds.
|
||||
*/
|
||||
public BobbleAnimation (
|
||||
Mirage image, int sx, int sy, int rx, int ry, int duration)
|
||||
{
|
||||
super(new Rectangle(sx - rx, sy - ry, sx + image.getWidth() + rx,
|
||||
sy + image.getHeight() + ry));
|
||||
|
||||
// save things off
|
||||
_image = image;
|
||||
_sx = sx;
|
||||
_sy = sy;
|
||||
_rx = rx;
|
||||
_ry = ry;
|
||||
|
||||
// calculate animation ending time
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
// grab our ending time on our first tick
|
||||
if (_end == 0L) {
|
||||
_end = tickStamp + _duration;
|
||||
}
|
||||
|
||||
_finished = (tickStamp >= _end);
|
||||
invalidate();
|
||||
|
||||
// calculate the latest position
|
||||
int dx = RandomUtil.getInt(_rx);
|
||||
int dy = RandomUtil.getInt(_ry);
|
||||
_x = (_sx + dx) * ((RandomUtil.getInt(2) == 0) ? -1 : 1);
|
||||
_y = (_sy + dy) * ((RandomUtil.getInt(2) == 0) ? -1 : 1);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_end += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
_image.paint(gfx, _x, _y);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
|
||||
buf.append(", x=").append(_x);
|
||||
buf.append(", y=").append(_y);
|
||||
buf.append(", rx=").append(_rx);
|
||||
buf.append(", ry=").append(_ry);
|
||||
buf.append(", sx=").append(_sx);
|
||||
buf.append(", sy=").append(_sy);
|
||||
}
|
||||
|
||||
/** The current position of the image. */
|
||||
protected int _x, _y;
|
||||
|
||||
/** The horizontal and vertical bobbling range. */
|
||||
protected int _rx, _ry;
|
||||
|
||||
/** The starting position. */
|
||||
protected int _sx, _sy;
|
||||
|
||||
/** The image to animate. */
|
||||
protected Mirage _image;
|
||||
|
||||
/** Animation ending timing information. */
|
||||
protected long _duration, _end;
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
//
|
||||
// $Id: ExplodeAnimation.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.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* An animation that displays an object exploding into chunks, fading out
|
||||
* as they fly apart. The animation ends when all chunks have exited the
|
||||
* animation bounds, or when the given delay time (if any is specified)
|
||||
* has elapsed.
|
||||
*/
|
||||
public class ExplodeAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* A class that describes an explosion's attributes.
|
||||
*/
|
||||
public static class ExplodeInfo
|
||||
{
|
||||
/** The bounds within which to animate. */
|
||||
public Rectangle bounds;
|
||||
|
||||
/** The number of image chunks on each axis. */
|
||||
public int xchunk, ychunk;
|
||||
|
||||
/** The maximum chunk velocity on each axis in pixels per
|
||||
* millisecond. */
|
||||
public float xvel, yvel;
|
||||
|
||||
/** The y-axis chunk acceleration in pixels per millisecond. */
|
||||
public float yacc;
|
||||
|
||||
/** The chunk rotational velocity in rotations per millisecond. */
|
||||
public float rvel;
|
||||
|
||||
/** The animation length in milliseconds, or -1 if the animation
|
||||
* should continue until all pieces are outside the bounds. */
|
||||
public long delay;
|
||||
|
||||
/** Returns a string representation of this instance. */
|
||||
public String toString ()
|
||||
{
|
||||
return StringUtil.fieldsToString(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an explode animation with the chunks represented as
|
||||
* filled rectangles of the specified color.
|
||||
*
|
||||
* @param color the color to render the chunks in.
|
||||
* @param info the explode info object.
|
||||
* @param x the x-position of the object.
|
||||
* @param y the y-position of the object.
|
||||
* @param width the width of the object.
|
||||
* @param height the height of the object.
|
||||
*/
|
||||
public ExplodeAnimation (
|
||||
Color color, ExplodeInfo info, int x, int y, int width, int height)
|
||||
{
|
||||
super(info.bounds);
|
||||
|
||||
_color = color;
|
||||
init(info, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an explode animation with the chunks represented as
|
||||
* portions of the actual image.
|
||||
*
|
||||
* @param image the image to animate.
|
||||
* @param info the explode info object.
|
||||
* @param x the x-position of the object.
|
||||
* @param y the y-position of the object.
|
||||
* @param width the width of the object.
|
||||
* @param height the height of the object.
|
||||
*/
|
||||
public ExplodeAnimation (
|
||||
Mirage image, ExplodeInfo info, int x, int y, int width, int height)
|
||||
{
|
||||
super(info.bounds);
|
||||
|
||||
_image = image;
|
||||
init(info, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the animation with the attributes of the given explode
|
||||
* info object.
|
||||
*/
|
||||
protected void init (ExplodeInfo info, int x, int y, int width, int height)
|
||||
{
|
||||
_info = info;
|
||||
_ox = x;
|
||||
_oy = y;
|
||||
_owid = width;
|
||||
_ohei = height;
|
||||
|
||||
_info.rvel = (float)((2.0f * Math.PI) * _info.rvel);
|
||||
_chunkcount = (_info.xchunk * _info.ychunk);
|
||||
_cxpos = new int[_chunkcount];
|
||||
_cypos = new int[_chunkcount];
|
||||
_sxvel = new float[_chunkcount];
|
||||
_syvel = new float[_chunkcount];
|
||||
|
||||
// determine chunk dimensions
|
||||
_cwid = _owid / _info.xchunk;
|
||||
_chei = _ohei / _info.ychunk;
|
||||
_hcwid = _cwid / 2;
|
||||
_hchei = _chei / 2;
|
||||
|
||||
// initialize all chunks
|
||||
for (int ii = 0; ii < _chunkcount; ii++) {
|
||||
// initialize chunk position
|
||||
int xpos = ii % _info.xchunk;
|
||||
int ypos = ii / _info.xchunk;
|
||||
_cxpos[ii] = _ox + (xpos * _cwid);
|
||||
_cypos[ii] = _oy + (ypos * _chei);
|
||||
|
||||
// initialize chunk velocity
|
||||
_sxvel[ii] = RandomUtil.getFloat(_info.xvel) *
|
||||
((xpos < (_info.xchunk / 2)) ? -1.0f : 1.0f);
|
||||
_syvel[ii] = -(RandomUtil.getFloat(_info.yvel));
|
||||
}
|
||||
|
||||
// initialize the chunk rotation angle
|
||||
_angle = 0.0f;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
if (_start > 0) {
|
||||
_start += timeDelta;
|
||||
_end += timeDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
if (_start == 0) {
|
||||
// initialize our starting time
|
||||
_start = timestamp;
|
||||
if (_info.delay != -1) {
|
||||
_end = _start + _info.delay;
|
||||
}
|
||||
}
|
||||
|
||||
// figure out the distance the chunks have travelled
|
||||
long msecs = timestamp - _start;
|
||||
|
||||
if (_info.delay != -1) {
|
||||
// calculate the alpha level with which to render the chunks
|
||||
float pctdone = msecs / (float)_info.delay;
|
||||
_alpha = Math.max(0.1f, Math.min(1.0f, 1.0f - pctdone));
|
||||
}
|
||||
|
||||
// move all chunks and check whether any remain to be animated
|
||||
int inside = 0;
|
||||
for (int ii = 0; ii < _chunkcount; ii++) {
|
||||
// determine the chunk travel distance
|
||||
int xtrav = (int)(_sxvel[ii] * msecs);
|
||||
int ytrav = (int)
|
||||
((_syvel[ii] * msecs) + (0.5f * _info.yacc * (msecs * msecs)));
|
||||
|
||||
// determine the chunk movement direction
|
||||
int xpos = ii % _info.xchunk;
|
||||
int ypos = ii / _info.xchunk;
|
||||
|
||||
// update the chunk position
|
||||
_cxpos[ii] = _ox + (xpos * _cwid) + xtrav;
|
||||
_cypos[ii] = _oy + (ypos * _chei) + ytrav;
|
||||
|
||||
// note whether this chunk is still within our bounds
|
||||
_wrect.setBounds(_cxpos[ii], _cypos[ii], _cwid, _chei);
|
||||
if (_bounds.intersects(_wrect)) {
|
||||
inside++;
|
||||
}
|
||||
}
|
||||
|
||||
// increment the rotation angle
|
||||
_angle += _info.rvel;
|
||||
|
||||
// note whether we're finished
|
||||
_finished = (inside == 0) || (_info.delay != -1 && timestamp >= _end);
|
||||
|
||||
// dirty ourselves
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
Shape oclip = gfx.getClip();
|
||||
Composite ocomp = null;
|
||||
|
||||
if (_info.delay != -1) {
|
||||
// set the alpha composite to reflect the current fade-out
|
||||
ocomp = gfx.getComposite();
|
||||
gfx.setComposite(
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alpha));
|
||||
}
|
||||
|
||||
for (int ii = 0; ii < _chunkcount; ii++) {
|
||||
// get the chunk position within the image
|
||||
int xpos = ii % _info.xchunk;
|
||||
int ypos = ii / _info.xchunk;
|
||||
|
||||
// calculate image chunk offset
|
||||
int xoff = -(xpos * _cwid);
|
||||
int yoff = -(ypos * _chei);
|
||||
|
||||
// translate the origin to center on the chunk
|
||||
int tx = _cxpos[ii] + _hcwid, ty = _cypos[ii] + _hchei;
|
||||
gfx.translate(tx, ty);
|
||||
|
||||
// set up the desired rotation
|
||||
gfx.rotate(_angle);
|
||||
|
||||
if (_image != null) {
|
||||
// draw the image chunk
|
||||
gfx.clipRect(-_hcwid, -_hchei, _cwid, _chei);
|
||||
_image.paint(gfx, -_hcwid + xoff, -_hchei + yoff);
|
||||
|
||||
} else {
|
||||
// draw the color chunk
|
||||
gfx.setColor(_color);
|
||||
gfx.fillRect(-_hcwid, -_hchei, _cwid, _chei);
|
||||
}
|
||||
|
||||
// restore the original transform and clip
|
||||
gfx.rotate(-_angle);
|
||||
gfx.translate(-tx, -ty);
|
||||
gfx.setClip(oclip);
|
||||
}
|
||||
|
||||
if (_info.delay != -1) {
|
||||
// restore the original composite
|
||||
gfx.setComposite(ocomp);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
|
||||
buf.append(", ox=").append(_ox);
|
||||
buf.append(", oy=").append(_oy);
|
||||
buf.append(", cwid=").append(_cwid);
|
||||
buf.append(", chei=").append(_chei);
|
||||
buf.append(", hcwid=").append(_hcwid);
|
||||
buf.append(", hchei=").append(_hchei);
|
||||
buf.append(", chunkcount=").append(_chunkcount);
|
||||
buf.append(", info=").append(_info);
|
||||
}
|
||||
|
||||
/** The current chunk rotation. */
|
||||
protected float _angle;
|
||||
|
||||
/** The starting x-axis velocity of each chunk. */
|
||||
protected float[] _sxvel;
|
||||
|
||||
/** The starting y-axis velocity of each chunk. */
|
||||
protected float[] _syvel;
|
||||
|
||||
/** The current x-axis position of each chunk. */
|
||||
protected int[] _cxpos;
|
||||
|
||||
/** The current y-axis position of each chunk. */
|
||||
protected int[] _cypos;
|
||||
|
||||
/** The individual chunk dimensions in pixels. */
|
||||
protected int _cwid, _chei;
|
||||
|
||||
/** The individual chunk dimensions in pixels, halved for handy use in
|
||||
* repeated calculations. */
|
||||
protected int _hcwid, _hchei;
|
||||
|
||||
/** The total number of image chunks. */
|
||||
protected int _chunkcount;
|
||||
|
||||
/** The explode info. */
|
||||
protected ExplodeInfo _info;
|
||||
|
||||
/** The exploding object position and dimensions. */
|
||||
protected int _ox, _oy, _owid, _ohei;
|
||||
|
||||
/** The color to render the object chunks in if we're using a color. */
|
||||
protected Color _color;
|
||||
|
||||
/** The image to animate if we're using an image. */
|
||||
protected Mirage _image;
|
||||
|
||||
/** The starting animation time. */
|
||||
protected long _start;
|
||||
|
||||
/** The ending animation time. */
|
||||
protected long _end;
|
||||
|
||||
/** The percent alpha with which to render the chunks. */
|
||||
protected float _alpha;
|
||||
|
||||
/** A reusable working rectangle. */
|
||||
protected Rectangle _wrect = new Rectangle();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// $Id: FadeAnimation.java 3427 2005-03-24 04:50:52Z 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.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
import com.threerings.media.effects.FadeEffect;
|
||||
|
||||
/**
|
||||
* An animation that displays an image fading from one alpha level to
|
||||
* another in specified increments over time. The animation is finished
|
||||
* when the specified target alpha is reached.
|
||||
*/
|
||||
public abstract class FadeAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs a fade animation.
|
||||
*
|
||||
* @param bounds our bounds.
|
||||
* @param alpha the starting alpha.
|
||||
* @param step the alpha amount to step by each millisecond.
|
||||
* @param target the target alpha level.
|
||||
*/
|
||||
protected FadeAnimation (
|
||||
Rectangle bounds, float alpha, float step, float target)
|
||||
{
|
||||
super(bounds);
|
||||
_effect = new FadeEffect(alpha, step, target);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
if (_effect.tick(timestamp)) {
|
||||
_finished = _effect.finished();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
_effect.beforePaint(gfx);
|
||||
paintAnimation(gfx);
|
||||
_effect.afterPaint(gfx);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void willStart (long tickStamp)
|
||||
{
|
||||
super.willStart(tickStamp);
|
||||
_effect.init(tickStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Here is where derived animations actually render their image.
|
||||
*/
|
||||
protected abstract void paintAnimation (Graphics2D gfx);
|
||||
|
||||
/** This handles the main work of fading. */
|
||||
protected FadeEffect _effect;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// $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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* Fades an image in or out by varying the alpha level during rendering.
|
||||
*/
|
||||
public class FadeImageAnimation extends FadeAnimation
|
||||
{
|
||||
/**
|
||||
* Creates an image fading animation.
|
||||
*/
|
||||
public FadeImageAnimation (Mirage image, int x, int y,
|
||||
float alpha, float step, float target)
|
||||
{
|
||||
super(new Rectangle(x, y, image.getWidth(), image.getHeight()),
|
||||
alpha, step, target);
|
||||
_image = image;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void paintAnimation (Graphics2D gfx)
|
||||
{
|
||||
_image.paint(gfx, _bounds.x, _bounds.y);
|
||||
}
|
||||
|
||||
protected Mirage _image;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// $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.animation;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
|
||||
import com.samskivert.swing.Label;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Does something extraordinary.
|
||||
*/
|
||||
public class FadeLabelAnimation extends FadeAnimation
|
||||
{
|
||||
/**
|
||||
* Creates a label fading animation.
|
||||
*/
|
||||
public FadeLabelAnimation (Label label, int x, int y,
|
||||
float alpha, float step, float target)
|
||||
{
|
||||
super(new Rectangle(x, y, 0, 0), alpha, step, target);
|
||||
_label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that our label should be rendered with antialiased text.
|
||||
*/
|
||||
public void setAntiAliased (boolean antiAliased)
|
||||
{
|
||||
_antiAliased = antiAliased;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void init ()
|
||||
{
|
||||
super.init();
|
||||
|
||||
// if our label is not yet laid out, do the deed
|
||||
if (!_label.isLaidOut()) {
|
||||
Graphics2D gfx = (Graphics2D)_mgr.getMediaPanel().getGraphics();
|
||||
if (gfx != null) {
|
||||
gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
_antiAliased ?
|
||||
RenderingHints.VALUE_ANTIALIAS_ON :
|
||||
RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||
_label.layout(gfx);
|
||||
gfx.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// size the bounds to fit our label
|
||||
Dimension size = _label.getSize();
|
||||
_bounds.width = size.width;
|
||||
_bounds.height = size.height;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void paintAnimation (Graphics2D gfx)
|
||||
{
|
||||
Object ohints = null;
|
||||
if (_antiAliased) {
|
||||
ohints = SwingUtil.activateAntiAliasing(gfx);
|
||||
}
|
||||
_label.render(gfx, _bounds.x, _bounds.y);
|
||||
if (_antiAliased) {
|
||||
SwingUtil.restoreAntiAliasing(gfx, ohints);
|
||||
}
|
||||
}
|
||||
|
||||
/** The label we are rendering. */
|
||||
protected Label _label;
|
||||
|
||||
/** Whether or not to use anti-aliased rendering. */
|
||||
protected boolean _antiAliased;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// $Id: FloatingTextAnimation.java 3212 2004-11-12 00:33:38Z 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.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.swing.Label;
|
||||
|
||||
public class FloatingTextAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs an animation for the given text centered at the given
|
||||
* coordinates.
|
||||
*/
|
||||
public FloatingTextAnimation (Label label, int x, int y)
|
||||
{
|
||||
this(label, x, y, DEFAULT_FLOAT_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an animation for the given text centered at the given
|
||||
* coordinates. The animation will float up the screen for 30 pixels.
|
||||
*/
|
||||
public FloatingTextAnimation (Label label, int x, int y, long floatPeriod)
|
||||
{
|
||||
this(label, x, y, x, y - DELTA_Y, floatPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an animation for the given text starting at the given
|
||||
* coordinates and floating toward the specified coordinates.
|
||||
*/
|
||||
public FloatingTextAnimation (Label label, int sx, int sy,
|
||||
int destx, int desty, long floatPeriod)
|
||||
{
|
||||
super(new Rectangle(sx, sy, label.getSize().width,
|
||||
label.getSize().height));
|
||||
|
||||
// save things off
|
||||
_label = label;
|
||||
_startX = _x = sx;
|
||||
_startY = _y = sy;
|
||||
_destx = destx;
|
||||
_desty = desty;
|
||||
_floatPeriod = floatPeriod;
|
||||
|
||||
// calculate our deltas
|
||||
_dx = (destx - sx);
|
||||
_dy = (desty - sy);
|
||||
|
||||
// initialize our starting alpha
|
||||
_alpha = 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to change the direction 180 degrees.
|
||||
*/
|
||||
public void flipDirection ()
|
||||
{
|
||||
_dx = -_dx;
|
||||
_dy = -_dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label used to render this score animation.
|
||||
*/
|
||||
public Label getLabel ()
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setLocation (int x, int y)
|
||||
{
|
||||
super.setLocation(x, y);
|
||||
|
||||
// update our destination coordinates
|
||||
_destx += (x - _startX);
|
||||
_desty += (y - _startY);
|
||||
|
||||
// update our initial coordinates
|
||||
_startX = _x = x;
|
||||
_startY = _y = y;
|
||||
|
||||
// recalculate our deltas
|
||||
_dx = (_destx - x);
|
||||
_dy = (_desty - y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration of this score animation to the specified time in
|
||||
* milliseconds. This should be called before the animation is added
|
||||
* to the animation manager.
|
||||
*/
|
||||
public void setFloatPeriod (long floatPeriod)
|
||||
{
|
||||
_floatPeriod = floatPeriod;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
boolean invalid = false;
|
||||
if (_start == 0) {
|
||||
// initialize our starting time
|
||||
_start = timestamp;
|
||||
// we need to make sure to invalidate ourselves initially
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
long fadeDelay = _floatPeriod/2;
|
||||
long fadePeriod = _floatPeriod - fadeDelay;
|
||||
|
||||
// figure out the current alpha
|
||||
long msecs = timestamp - _start;
|
||||
float oalpha = _alpha;
|
||||
if (msecs > fadeDelay) {
|
||||
long rmsecs = msecs - fadeDelay;
|
||||
_alpha = Math.max(1.0f - (rmsecs / (float)fadePeriod), 0.0f);
|
||||
_alpha = Math.min(_alpha, 1.0f);
|
||||
}
|
||||
|
||||
// get the alpha composite
|
||||
_comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alpha);
|
||||
|
||||
// determine the new y-position of the score
|
||||
float pctdone = (float)msecs / _floatPeriod;
|
||||
int ox = _x, oy = _y;
|
||||
_x = _startX + (int)(_dx * pctdone);
|
||||
_y = _startY + (int)(_dy * pctdone);
|
||||
|
||||
// only update our location and dirty ourselves if we actually
|
||||
// moved or our alpha changed
|
||||
if (ox != _x || oy != _y) {
|
||||
// dirty our old location
|
||||
invalidate();
|
||||
_bounds.setLocation(_x, _y);
|
||||
invalid = true;
|
||||
|
||||
} else if (oalpha != _alpha) {
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
if (invalid) {
|
||||
// dirty our current location
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// note whether we're done
|
||||
_finished = (msecs >= _floatPeriod);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
if (_start > 0) {
|
||||
_start += timeDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
Composite ocomp = gfx.getComposite();
|
||||
if (_comp != null) {
|
||||
gfx.setComposite(_comp);
|
||||
}
|
||||
paintLabels(gfx, _x, _y);
|
||||
gfx.setComposite(ocomp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes may wish to extend score animation and render more than
|
||||
* just the standard single label.
|
||||
*
|
||||
* @param x the upper left coordinate of the animation.
|
||||
* @param y the upper left coordinate of the animation.
|
||||
*/
|
||||
protected void paintLabels (Graphics2D gfx, int x, int y)
|
||||
{
|
||||
_label.render(gfx, x, y);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
|
||||
buf.append(", x=").append(_x);
|
||||
buf.append(", y=").append(_y);
|
||||
buf.append(", alpha=").append(_alpha);
|
||||
}
|
||||
|
||||
/** The starting animation time. */
|
||||
protected long _start;
|
||||
|
||||
/** The label we're animating. */
|
||||
protected Label _label;
|
||||
|
||||
/** The starting coordinates of the score. */
|
||||
protected int _startX, _startY;
|
||||
|
||||
/** The current coordinates of the score. */
|
||||
protected int _x, _y;
|
||||
|
||||
/** The destination coordinates towards which the animation travels. */
|
||||
protected int _destx, _desty;
|
||||
|
||||
/** The distance to be traveled by the score animation. */
|
||||
protected int _dx, _dy;
|
||||
|
||||
/** The duration for which we float up the screen. */
|
||||
protected long _floatPeriod;
|
||||
|
||||
/** The current alpha level used to render the score. */
|
||||
protected float _alpha;
|
||||
|
||||
/** The composite used to render the score. */
|
||||
protected Composite _comp;
|
||||
|
||||
/** The time in milliseconds during which the score is visible. */
|
||||
protected static final long DEFAULT_FLOAT_PERIOD = 1500L;
|
||||
|
||||
/** The total vertical distance the score travels. */
|
||||
protected static final int DELTA_Y = 30;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// $Id: GleamAnimation.java 4191 2006-06-13 22:42:20Z ray $
|
||||
|
||||
package com.threerings.media.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Transparency;
|
||||
|
||||
import com.threerings.media.sprite.Sprite;
|
||||
import com.threerings.media.sprite.SpriteManager;
|
||||
import com.threerings.media.util.LinearTimeFunction;
|
||||
import com.threerings.media.util.TimeFunction;
|
||||
|
||||
/**
|
||||
* Washes all non-transparent pixels in a sprite with a particular color
|
||||
* (by compositing them with the solid color with progressively higher
|
||||
* alpha values) and then back again.
|
||||
*/
|
||||
public class GleamAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Creates a gleam animation with the supplied sprite. The sprite will
|
||||
* be faded to the specified color and then back again. The sprite may
|
||||
* be already added to the supplied sprite manager or not, but when
|
||||
* the animation is complete, it will have been added.
|
||||
*
|
||||
* @param fadeIn if true, the sprite itself will be faded in as we
|
||||
* fade up to the gleam color and the gleam color will fade out,
|
||||
* leaving just the sprite imagery.
|
||||
*/
|
||||
public GleamAnimation (SpriteManager spmgr, Sprite sprite, Color color,
|
||||
int upmillis, int downmillis, boolean fadeIn)
|
||||
{
|
||||
super(sprite.getBounds());
|
||||
_spmgr = spmgr;
|
||||
_sprite = sprite;
|
||||
_color = color;
|
||||
_upfunc = new LinearTimeFunction(0, 750, upmillis);
|
||||
_downfunc = new LinearTimeFunction(750, 0, downmillis);
|
||||
_fadeIn = fadeIn;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
int alpha;
|
||||
if (_upfunc != null) {
|
||||
if ((alpha = _upfunc.getValue(timestamp)) == 750) {
|
||||
_upfunc = null;
|
||||
}
|
||||
} else if (_downfunc != null) {
|
||||
if ((alpha = _downfunc.getValue(timestamp)) == 0) {
|
||||
_downfunc = null;
|
||||
}
|
||||
} else {
|
||||
_finished = true;
|
||||
_spmgr.addSprite(_sprite);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_alpha != alpha) {
|
||||
_alpha = alpha;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
if (_upfunc != null) {
|
||||
_upfunc.fastForward(timeDelta);
|
||||
} else if (_downfunc != null) {
|
||||
_downfunc.fastForward(timeDelta);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// TODO: recreate our off image if the sprite bounds changed; we
|
||||
// also need to change the bounds of our animation which might
|
||||
// require some jockeying (especially if we shrink)
|
||||
if (_offimg == null) {
|
||||
_offimg = gfx.getDeviceConfiguration().createCompatibleImage(
|
||||
_bounds.width, _bounds.height, Transparency.TRANSLUCENT);
|
||||
}
|
||||
|
||||
// create a mask image with our sprite and the appropriate color
|
||||
Graphics2D ogfx = (Graphics2D)_offimg.getGraphics();
|
||||
try {
|
||||
ogfx.setColor(_color);
|
||||
ogfx.fillRect(0, 0, _bounds.width, _bounds.height);
|
||||
ogfx.setComposite(AlphaComposite.DstAtop);
|
||||
ogfx.translate(-_sprite.getX(), -_sprite.getY());
|
||||
_sprite.paint(ogfx);
|
||||
} finally {
|
||||
ogfx.dispose();
|
||||
}
|
||||
|
||||
Composite ocomp = null;
|
||||
Composite ncomp = AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, _alpha/1000f);
|
||||
|
||||
// if we're fading the sprite in on the way up, set our alpha
|
||||
// composite before we render the sprite
|
||||
if (_fadeIn && _upfunc != null) {
|
||||
ocomp = gfx.getComposite();
|
||||
gfx.setComposite(ncomp);
|
||||
}
|
||||
|
||||
// next render the sprite
|
||||
_sprite.paint(gfx);
|
||||
|
||||
// if we're not fading in, we still need to alpha the white bits
|
||||
if (ocomp == null) {
|
||||
ocomp = gfx.getComposite();
|
||||
gfx.setComposite(ncomp);
|
||||
}
|
||||
|
||||
// now alpha composite our mask atop the sprite
|
||||
gfx.drawImage(_offimg, _sprite.getX(), _sprite.getY(), null);
|
||||
gfx.setComposite(ocomp);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void willStart (long tickStamp)
|
||||
{
|
||||
super.willStart(tickStamp);
|
||||
|
||||
// remove the sprite we're fiddling with from the manager; we'll
|
||||
// add it back when we're done
|
||||
if (_spmgr.isManaged(_sprite)) {
|
||||
_spmgr.removeSprite(_sprite);
|
||||
}
|
||||
}
|
||||
|
||||
protected SpriteManager _spmgr;
|
||||
protected Sprite _sprite;
|
||||
protected Color _color;
|
||||
protected Image _offimg;
|
||||
protected boolean _fadeIn;
|
||||
|
||||
protected TimeFunction _upfunc;
|
||||
protected TimeFunction _downfunc;
|
||||
protected int _alpha = -1;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// $Id: MultiFrameAnimation.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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.util.FrameSequencer;
|
||||
import com.threerings.media.util.MultiFrameImage;
|
||||
|
||||
/**
|
||||
* Animates a sequence of image frames in place with a particular frame
|
||||
* rate.
|
||||
*/
|
||||
public class MultiFrameAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Creates a multi-frame animation with the specified source image
|
||||
* frames and the specified target frame rate (in frames per second).
|
||||
*
|
||||
* @param frames the source frames of the animation.
|
||||
* @param fps the target number of frames per second.
|
||||
* @param loop whether the animation should loop indefinitely or
|
||||
* finish after one shot.
|
||||
*/
|
||||
public MultiFrameAnimation (
|
||||
MultiFrameImage frames, double fps, boolean loop)
|
||||
{
|
||||
this(frames, new FrameSequencer.ConstantRate(fps, loop));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-frame animation with the specified source image
|
||||
* frames and the specified target frame rate (in frames per second).
|
||||
*/
|
||||
public MultiFrameAnimation (MultiFrameImage frames, FrameSequencer seeker)
|
||||
{
|
||||
// we'll set up our bounds via setLocation() and in reset()
|
||||
super(new Rectangle());
|
||||
|
||||
_frames = frames;
|
||||
_seeker = seeker;
|
||||
|
||||
// reset ourselves to start things off
|
||||
reset();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Rectangle getBounds ()
|
||||
{
|
||||
// fill in the bounds with our current animation frame's bounds
|
||||
return _bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this animation has run to completion, it can be reset to prepare
|
||||
* it for another go.
|
||||
*/
|
||||
public void reset ()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
// set the frame number to -1 so that we don't ignore the
|
||||
// transition to frame zero on the first call to tick()
|
||||
_fidx = -1;
|
||||
|
||||
// reset our frame sequencer
|
||||
_seeker.init(_frames);
|
||||
if (_seeker instanceof AnimationFrameSequencer) {
|
||||
((AnimationFrameSequencer) _seeker).setAnimation(this);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
int fidx = _seeker.tick(tickStamp);
|
||||
if (fidx == -1) {
|
||||
_finished = true;
|
||||
|
||||
} else if (fidx != _fidx) {
|
||||
// update our frame index and bounds
|
||||
setFrameIndex(fidx);
|
||||
|
||||
// and have ourselves repainted
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame index and updates our dimensions.
|
||||
*/
|
||||
protected void setFrameIndex (int fidx)
|
||||
{
|
||||
_fidx = fidx;
|
||||
_bounds.width = _frames.getWidth(_fidx);
|
||||
_bounds.height = _frames.getHeight(_fidx);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
_frames.paintFrame(gfx, _fidx, _bounds.x, _bounds.y);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_seeker.fastForward(timeDelta);
|
||||
}
|
||||
|
||||
protected MultiFrameImage _frames;
|
||||
protected FrameSequencer _seeker;
|
||||
protected int _fidx;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// $Id: RainAnimation.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.animation;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
|
||||
/**
|
||||
* An animation that displays raindrops spattering across an image.
|
||||
*/
|
||||
public class RainAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs a rain animation with reasonable defaults for the number
|
||||
* of raindrops and their dimensions.
|
||||
*
|
||||
* @param bounds the bounding rectangle for the animation.
|
||||
* @param duration the number of seconds the animation should last.
|
||||
*/
|
||||
public RainAnimation (Rectangle bounds, long duration)
|
||||
{
|
||||
super(bounds);
|
||||
|
||||
init(duration, DEFAULT_COUNT, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a rain animation.
|
||||
*
|
||||
* @param bounds the bounding rectangle for the animation.
|
||||
* @param duration the number of seconds the animation should last.
|
||||
* @param count the number of raindrops to render in each frame.
|
||||
* @param wid the width of a raindrop's bounding rectangle.
|
||||
* @param hei the height of a raindrop's bounding rectangle.
|
||||
*/
|
||||
public RainAnimation (
|
||||
Rectangle bounds, long duration, int count, int wid, int hei)
|
||||
{
|
||||
super(bounds);
|
||||
init(duration, count, wid, hei);
|
||||
}
|
||||
|
||||
protected void init (long duration, int count, int wid, int hei)
|
||||
{
|
||||
// save things off
|
||||
_count = count;
|
||||
_wid = wid;
|
||||
_hei = hei;
|
||||
|
||||
// create the raindrop array
|
||||
_drops = new int[count];
|
||||
|
||||
// calculate ending time
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
// grab our ending time on our first tick
|
||||
if (_end == 0L) {
|
||||
_end = tickStamp + _duration;
|
||||
}
|
||||
|
||||
_finished = (tickStamp >= _end);
|
||||
|
||||
// calculate the latest raindrop locations
|
||||
for (int ii = 0; ii < _count; ii++) {
|
||||
int x = RandomUtil.getInt(_bounds.width);
|
||||
int y = RandomUtil.getInt(_bounds.height);
|
||||
_drops[ii] = (x << 16 | y);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_end += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
gfx.setColor(Color.white);
|
||||
for (int ii = 0; ii < _count; ii++) {
|
||||
int x = _drops[ii] >> 16;
|
||||
int y = _drops[ii] & 0xFFFF;
|
||||
gfx.drawLine(x, y, x + _wid, y + _hei);
|
||||
}
|
||||
}
|
||||
|
||||
/** The number of raindrops. */
|
||||
protected static final int DEFAULT_COUNT = 300;
|
||||
|
||||
/** The raindrop streak dimensions. */
|
||||
protected static final int DEFAULT_WIDTH = 13;
|
||||
protected static final int DEFAULT_HEIGHT = 10;
|
||||
|
||||
/** The number of raindrops. */
|
||||
protected int _count;
|
||||
|
||||
/** The dimensions of each raindrop's bounding rectangle. */
|
||||
protected int _wid, _hei;
|
||||
|
||||
/** The raindrop locations. */
|
||||
protected int[] _drops;
|
||||
|
||||
/** Animation ending timing information. */
|
||||
protected long _duration, _end;
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// $Id: ScaleAnimation.java 3123 2004-09-18 22:58:39Z mdb $
|
||||
|
||||
package com.threerings.media.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Image;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Transparency;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.media.sprite.Sprite;
|
||||
import com.threerings.media.sprite.SpriteManager;
|
||||
import com.threerings.media.util.LinearTimeFunction;
|
||||
import com.threerings.media.util.TimeFunction;
|
||||
|
||||
/**
|
||||
* Animates an image changing size about its center point.
|
||||
*/
|
||||
public class ScaleAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Creates a scale animation with the supplied image. If the image's
|
||||
* size would ever be 0 or less, it is not drawn.
|
||||
*
|
||||
* @param image The image to paint.
|
||||
*
|
||||
* @param center The screen coordinates of the pixel upon which the
|
||||
* image's center should always be rendered.
|
||||
*
|
||||
* @param startScale The amount to scale the image when it is rendered
|
||||
* at time 0.
|
||||
*
|
||||
* @param endScale The amount to scale the image at the final frame
|
||||
* of animation.
|
||||
*
|
||||
* @param duration The time in milliseconds the anim takes to complete.
|
||||
*/
|
||||
public ScaleAnimation (Mirage image, Point center,
|
||||
float startScale, float endScale, int duration)
|
||||
{
|
||||
super(getBounds(Math.max(startScale, endScale), center, image));
|
||||
|
||||
// Save inputted variables
|
||||
_image = image;
|
||||
_bufferedImage = _image.getSnapshot();
|
||||
_center = new Point(center);
|
||||
_startScale = startScale;
|
||||
_endScale = endScale;
|
||||
_duration = duration;
|
||||
|
||||
// Hack the LinearTimeFunction to use fixed point rationals
|
||||
//
|
||||
// FIXME: This class doesn't seem to be saving me a lot of
|
||||
// work, since I have to repackage the outputs into floats
|
||||
// anyway. Find some way to make the LinearTimeFunction do
|
||||
// more of this work for us, or write a new class that does.
|
||||
// Maybe IntLinearTimeFunction and FloatLinearTimeFunction
|
||||
// classes would be useful.
|
||||
_scaleFunc = new LinearTimeFunction(0, 10000, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Java wants the first call in a constructor to be super()
|
||||
* if it exists at all, so we have to trick it with this function.
|
||||
*
|
||||
* Oh, and this function computes how big the bounding box needs
|
||||
* to be to bound the inputted image scaled to the inputted size
|
||||
* centered around the inputted center poitn.
|
||||
*/
|
||||
public static Rectangle getBounds (float scale, Point center, Mirage image)
|
||||
{
|
||||
Point size = getSize(scale, image);
|
||||
Point corner = getCorner(center, size);
|
||||
return new Rectangle(corner.x, corner.y, size.x, size.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the bounds to use to render the animation's image
|
||||
* right now.
|
||||
*/
|
||||
public Rectangle getBounds ()
|
||||
{
|
||||
return getBounds(_scale, _center, _image);
|
||||
}
|
||||
|
||||
/** Computes the width and height to which an image should be scaled. */
|
||||
public static Point getSize (float scale, Mirage image)
|
||||
{
|
||||
int width = Math.max(0, Math.round(image.getWidth() * scale));
|
||||
int height = Math.max(0, Math.round(image.getHeight() * scale));
|
||||
return new Point(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the upper left corner where the image should be drawn,
|
||||
* given the center and dimensions to which the image should be scaled.
|
||||
*/
|
||||
public static Point getCorner (Point center, Point size)
|
||||
{
|
||||
return new Point(center.x - size.x/2, center.y - size.y/2);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
// Compute the new scaling value
|
||||
float weight = _scaleFunc.getValue(tickStamp) / 10000.0f;
|
||||
float scale = ((1.0f - weight) * _startScale) +
|
||||
(( weight) * _endScale);
|
||||
|
||||
// Update the animation if the scaling changes
|
||||
if (_scale != scale)
|
||||
{
|
||||
_scale = scale;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// Check if the animation completed
|
||||
if (weight >= 1.0f) {
|
||||
_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_scaleFunc.fastForward(timeDelta);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// Compute the bounding box to render this image
|
||||
Rectangle bounds = getBounds();
|
||||
|
||||
// Paint nothing if the image was scaled to nothing
|
||||
if (bounds.width <= 0 || bounds.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Smooth out the image scaling
|
||||
//
|
||||
// FIXME: Should this be turned off when the painting is done?
|
||||
gfx.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
|
||||
// Paint the image scaled to this location
|
||||
gfx.drawImage(_bufferedImage,
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.x + bounds.width,
|
||||
bounds.y + bounds.height,
|
||||
0,
|
||||
0,
|
||||
_bufferedImage.getWidth(),
|
||||
_bufferedImage.getHeight(),
|
||||
null);
|
||||
}
|
||||
|
||||
/** The image to scale. */
|
||||
protected Mirage _image;
|
||||
|
||||
/** The image converted to a format Graphics2D likes, and cached. */
|
||||
protected BufferedImage _bufferedImage;
|
||||
|
||||
/** The center pixel to render the image around. */
|
||||
protected Point _center;
|
||||
|
||||
/** The amount of time the animation should last. */
|
||||
//XXX Is this needed?
|
||||
protected long _duration;
|
||||
|
||||
/** The amount to scale the image at the start of the animation. */
|
||||
protected float _startScale;
|
||||
|
||||
/** The amount to scale the image at the end of the animation. */
|
||||
protected float _endScale;
|
||||
|
||||
/** The current amount of scaling to render. */
|
||||
protected float _scale;
|
||||
|
||||
/** Computes the image scaling to use at the specified time. */
|
||||
protected TimeFunction _scaleFunc;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// $Id: SequencedAnimationObserver.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.animation;
|
||||
|
||||
/**
|
||||
* Extends the animation observer interface with extra goodies.
|
||||
*/
|
||||
public interface SequencedAnimationObserver extends AnimationObserver
|
||||
{
|
||||
/**
|
||||
* Called when the observed animation -- previously configured with an
|
||||
* {@link AnimationFrameSequencer} -- reached the specified frame.
|
||||
*/
|
||||
public void frameReached (Animation anim, long when,
|
||||
int frameIdx, int frameSeq);
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
//
|
||||
// $Id: SparkAnimation.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.animation;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
|
||||
import com.samskivert.util.RandomUtil;
|
||||
|
||||
import com.threerings.media.animation.Animation;
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Displays a set of spark images originating from a specified position
|
||||
* and flying outward in random directions, fading out as they go, for a
|
||||
* specified period of time.
|
||||
*/
|
||||
public class SparkAnimation extends Animation
|
||||
{
|
||||
/**
|
||||
* Constructs a spark animation with the supplied parameters.
|
||||
*
|
||||
* @param bounds the bounding rectangle for the animation.
|
||||
* @param x the starting x-position for the sparks.
|
||||
* @param y the starting y-position for the sparks.
|
||||
* @param xjog the maximum X distance by which to "jog" the initial spark
|
||||
* positions, or 0 if no jogging is desired.
|
||||
* @param yjog the maximum Y distance by which to "jog" the initial spark
|
||||
* positions, or 0 if no jogging is desired.
|
||||
* @param minxvel the minimum starting x-velocity of the sparks.
|
||||
* @param minyvel the minimum starting y-velocity of the sparks.
|
||||
* @param maxxvel the maximum x-velocity of the sparks.
|
||||
* @param maxyvel the maximum y-velocity of the sparks.
|
||||
* @param xacc the x axis acceleration, or 0 if none is desired.
|
||||
* @param yacc the y axis acceleration, or 0 if none is desired.
|
||||
* @param images the spark images to be animated.
|
||||
* @param delay the duration of the animation in milliseconds.
|
||||
* @param fade do the fade thing
|
||||
*/
|
||||
public SparkAnimation (Rectangle bounds, int x, int y, int xjog, int yjog,
|
||||
float minxvel, float minyvel,
|
||||
float maxxvel, float maxyvel,
|
||||
float xacc, float yacc,
|
||||
Mirage[] images, long delay, boolean fade)
|
||||
{
|
||||
super(bounds);
|
||||
|
||||
// save things off
|
||||
_xacc = xacc;
|
||||
_yacc = yacc;
|
||||
_images = images;
|
||||
_delay = delay;
|
||||
_fade = fade;
|
||||
|
||||
// initialize various things
|
||||
_icount = images.length;
|
||||
_ox = new int[_icount];
|
||||
_oy = new int[_icount];
|
||||
_xpos = new int[_icount];
|
||||
_ypos = new int[_icount];
|
||||
_sxvel = new float[_icount];
|
||||
_syvel = new float[_icount];
|
||||
|
||||
for (int ii = 0; ii < _icount; ii++) {
|
||||
// initialize spark position
|
||||
_ox[ii] = x +
|
||||
((xjog == 0) ? 0 : RandomUtil.getInt(xjog) * randomDirection());
|
||||
_oy[ii] = y +
|
||||
((yjog == 0) ? 0 : RandomUtil.getInt(yjog) * randomDirection());
|
||||
|
||||
// Choose random X and Y axis velocities between the inputted
|
||||
// bounds
|
||||
_sxvel[ii] = minxvel + RandomUtil.getFloat(1) * (maxxvel - minxvel);
|
||||
_syvel[ii] = minyvel + RandomUtil.getFloat(1) * (maxyvel - minyvel);
|
||||
|
||||
// If accelerationes were given, make the starting velocities
|
||||
// move against that acceleration; otherwise pick directions
|
||||
// at random
|
||||
if (_xacc > 0) {
|
||||
_sxvel[ii] = -_sxvel[ii];
|
||||
} else if (_xacc == 0) {
|
||||
_sxvel[ii] *= randomDirection();
|
||||
}
|
||||
if (_yacc > 0) {
|
||||
_syvel[ii] = -_syvel[ii];
|
||||
} else if (_yacc == 0) {
|
||||
_syvel[ii] *= randomDirection();
|
||||
}
|
||||
}
|
||||
|
||||
if (_fade) {
|
||||
_alpha = 1.0f;
|
||||
_comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns at random -1 for negative direction or +1 for positive.
|
||||
*/
|
||||
protected int randomDirection ()
|
||||
{
|
||||
return (RandomUtil.getInt(2) == 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void willStart (long stamp)
|
||||
{
|
||||
super.willStart(stamp);
|
||||
_start = stamp;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
_start += timeDelta;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
// figure out the distance the chunks have travelled
|
||||
long msecs = Math.max(timestamp - _start, 0);
|
||||
long msecsSq = msecs * msecs;
|
||||
|
||||
// calculate the alpha level with which to render the chunks
|
||||
if (_fade) {
|
||||
float pctdone = msecs / (float)_delay;
|
||||
_alpha = Math.max(0.1f, Math.min(1.0f, 1.0f - pctdone));
|
||||
_comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alpha);
|
||||
}
|
||||
|
||||
// assume all sparks have moved outside the bounds
|
||||
boolean allOutside = true;
|
||||
|
||||
// move all sparks and check whether any remain to be animated
|
||||
for (int ii = 0; ii < _icount; ii++) {
|
||||
// determine the travel distance
|
||||
int xtrav = (int)
|
||||
((_sxvel[ii] * msecs) + (0.5f * _xacc * msecsSq));
|
||||
int ytrav = (int)
|
||||
((_syvel[ii] * msecs) + (0.5f * _yacc * msecsSq));
|
||||
|
||||
// update the position
|
||||
_xpos[ii] = _ox[ii] + xtrav;
|
||||
_ypos[ii] = _oy[ii] + ytrav;
|
||||
|
||||
// check to see if any are still in. Stop looking
|
||||
// when we find one
|
||||
if (allOutside && _bounds.intersects(_xpos[ii], _ypos[ii],
|
||||
_images[ii].getWidth(), _images[ii].getHeight())) {
|
||||
allOutside = false;
|
||||
}
|
||||
}
|
||||
|
||||
// note whether we're finished
|
||||
_finished = allOutside || (msecs >= _delay);
|
||||
|
||||
// dirty ourselves
|
||||
// TODO: only do this if at least one spark actually moved
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
Shape oclip = gfx.getClip();
|
||||
gfx.clip(_bounds);
|
||||
Composite ocomp = gfx.getComposite();
|
||||
|
||||
if (_fade) {
|
||||
// set the alpha composite to reflect the current fade-out
|
||||
gfx.setComposite(_comp);
|
||||
}
|
||||
|
||||
// draw all sparks
|
||||
for (int ii = 0; ii < _icount; ii++) {
|
||||
_images[ii].paint(gfx, _xpos[ii], _ypos[ii]);
|
||||
}
|
||||
|
||||
// restore the original gfx settings
|
||||
gfx.setComposite(ocomp);
|
||||
gfx.setClip(oclip);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
|
||||
buf.append(", ox=").append(_ox);
|
||||
buf.append(", oy=").append(_oy);
|
||||
buf.append(", alpha=").append(_alpha);
|
||||
}
|
||||
|
||||
/** The spark images we're animating. */
|
||||
protected Mirage[] _images;
|
||||
|
||||
/** The number of images we're animating. */
|
||||
protected int _icount;
|
||||
|
||||
/** The x axis acceleration in pixels per millisecond. */
|
||||
protected float _xacc;
|
||||
|
||||
/** The y axis acceleration in pixels per millisecond. */
|
||||
protected float _yacc;
|
||||
|
||||
/** The starting x-axis velocity of each chunk. */
|
||||
protected float[] _sxvel;
|
||||
|
||||
/** The starting y-axis velocity of each chunk. */
|
||||
protected float[] _syvel;
|
||||
|
||||
/** The starting 'jog' positions for each spark. */
|
||||
protected int[] _ox, _oy;
|
||||
|
||||
/** The current positions of each spark. */
|
||||
protected int[] _xpos, _ypos;
|
||||
|
||||
/** The starting animation time. */
|
||||
protected long _start;
|
||||
|
||||
/** Whether or not we should fade the sparks out. */
|
||||
protected boolean _fade;
|
||||
|
||||
/** The percent alpha with which to render the images. */
|
||||
protected float _alpha;
|
||||
|
||||
/** The alpha composite with which to render the images. */
|
||||
protected AlphaComposite _comp;
|
||||
|
||||
/** The duration of the spark animation in milliseconds. */
|
||||
protected long _delay;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// $Id: SpriteAnimation.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.animation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.sprite.Sprite;
|
||||
import com.threerings.media.sprite.SpriteManager;
|
||||
import com.threerings.media.sprite.PathObserver;
|
||||
import com.threerings.media.util.Path;
|
||||
|
||||
public class SpriteAnimation extends Animation
|
||||
implements PathObserver
|
||||
{
|
||||
/**
|
||||
* Constructs a sprite animation for the given sprite. The first time
|
||||
* the animation is ticked, the sprite will be added to the given
|
||||
* sprite manager and started along the supplied path.
|
||||
*/
|
||||
public SpriteAnimation (SpriteManager spritemgr, Sprite sprite, Path path)
|
||||
{
|
||||
super(new Rectangle());
|
||||
|
||||
// save things off
|
||||
_spritemgr = spritemgr;
|
||||
_sprite = sprite;
|
||||
_path = path;
|
||||
|
||||
// set up our sprite business
|
||||
_sprite.addSpriteObserver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes can override tick if they want to end the animation
|
||||
* in some other way than the sprite completing a path.
|
||||
*/
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
// start the sprite moving on its path on our first tick
|
||||
if (_path != null) {
|
||||
_spritemgr.addSprite(_sprite);
|
||||
_sprite.move(_path);
|
||||
_path = null;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void pathCancelled (Sprite sprite, Path path)
|
||||
{
|
||||
_finished = true;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void pathCompleted (Sprite sprite, Path path, long when)
|
||||
{
|
||||
_finished = true;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void didFinish (long tickStamp)
|
||||
{
|
||||
super.didFinish(tickStamp);
|
||||
|
||||
_spritemgr.removeSprite(_sprite);
|
||||
_sprite = null;
|
||||
}
|
||||
|
||||
/** The sprite associated with this animation. */
|
||||
protected Sprite _sprite;
|
||||
|
||||
/** The sprite manager managing our sprite. */
|
||||
protected SpriteManager _spritemgr;
|
||||
|
||||
/** The path along which we'll move our sprite. */
|
||||
protected Path _path;
|
||||
}
|
||||
Reference in New Issue
Block a user