// // $Id: ExplodeAnimation.java,v 1.6 2002/01/31 17:34:20 shaper Exp $ package com.threerings.media.animation; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.Shape; import com.threerings.media.Log; import com.threerings.media.util.RandomUtil; /** * An animation that displays an object exploding into chunks. The * animation ends when all chunks have exited the animation bounds. */ 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; } /** * 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 ( Image 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); _cpos = 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; _cpos[ii] = ((_ox + (xpos * _cwid)) << 16 | (_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; } /** * Sets the animation starting time. */ public void setStartTime (long timestamp) { _start = timestamp; } // documentation inherited public void tick (long timestamp) { // figure out the distance the chunks have travelled long msecs = timestamp - _start; // move all chunks and check whether any remain to be animated int inside = 0; for (int ii = 0; ii < _chunkcount; ii++) { // retrieve the current chunk position int x = _cpos[ii] >> 16; int y = _cpos[ii] & 0xFFFF; // 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 x = _ox + (xpos * _cwid) + xtrav; y = _oy + (ypos * _chei) + ytrav; _cpos[ii] = (x << 16 | y); // note whether this chunk is still within our bounds if (_bounds.contains(x, y)) { inside++; } } // increment the rotation angle _angle += _info.rvel; _finished = (inside == 0) || (_info.delay > -1 && timestamp >= (_start + _info.delay)); invalidate(); } // documentation inherited public void paint (Graphics2D gfx) { for (int ii = 0; ii < _chunkcount; ii++) { // get the chunk location on-screen int x = _cpos[ii] >> 16; int y = _cpos[ii] & 0xFFFF; // 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); // draw the chunk Shape oclip = gfx.getClip(); // translate the origin to center on the chunk int tx = x + _hcwid, ty = y + _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); gfx.drawImage(_image, -_hcwid + xoff, -_hchei + yoff, null); gfx.setClip(oclip); } else { // draw the color chunk gfx.setColor(_color); gfx.fillRect(-_hcwid, -_hchei, _cwid, _chei); } // restore the original transform gfx.rotate(-_angle); gfx.translate(-tx, -ty); } } // documentation inherited protected void toString (StringBuffer buf) { super.toString(buf); buf.append(", sx=").append(_ox); buf.append(", sy=").append(_oy); } /** 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 position of each chunk. */ protected int[] _cpos; /** 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 Image _image; /** The starting animation time. */ protected long _start; }