
com.threerings.media.animation.ExplodeAnimation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nenya Show documentation
Show all versions of nenya Show documentation
Facilities for making networked multiplayer games.
The newest version!
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/nenya
//
// 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;
@Override
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;
}
@Override
public void fastForward (long timeDelta)
{
if (_start > 0) {
_start += timeDelta;
_end += timeDelta;
}
}
@Override
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 traveled
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();
}
@Override
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);
}
}
@Override
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();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy