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,384 @@
|
||||
//
|
||||
// $Id: ButtonSprite.java 3509 2005-04-20 17:15:36Z 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.sprite;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
|
||||
import com.samskivert.swing.Label;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
import com.threerings.media.sprite.action.ArmingSprite;
|
||||
import com.threerings.media.sprite.action.CommandSprite;
|
||||
import com.threerings.media.sprite.action.DisableableSprite;
|
||||
|
||||
/**
|
||||
* A sprite that acts as a button.
|
||||
*/
|
||||
public class ButtonSprite extends Sprite
|
||||
implements CommandSprite, ArmingSprite, DisableableSprite
|
||||
{
|
||||
/** The normal, square button style. */
|
||||
public static final int NORMAL = 0;
|
||||
|
||||
/** The rounded button style. */
|
||||
public static final int ROUNDED = 1;
|
||||
|
||||
/**
|
||||
* Constructs a button sprite.
|
||||
*
|
||||
* @param label the label to render on the button
|
||||
* @param style the style of button to render (NORMAL or ROUNDED)
|
||||
* @param backgroundColor the background color of the button
|
||||
* @param alternateColor the alternate (outline) color
|
||||
* @param actionCommand the button's command
|
||||
* @param commandArgument the button's command argument
|
||||
*/
|
||||
public ButtonSprite (Label label, int style, Color backgroundColor,
|
||||
Color alternateColor, String actionCommand, Object commandArgument)
|
||||
{
|
||||
_label = label;
|
||||
_style = style;
|
||||
_backgroundColor = backgroundColor;
|
||||
_alternateColor = alternateColor;
|
||||
_actionCommand = actionCommand;
|
||||
_commandArgument = commandArgument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a button sprite.
|
||||
*
|
||||
* @param label the label to render on the button
|
||||
* @param style the style of button to render (NORMAL or ROUNDED)
|
||||
* @param arcWidth the width of the corner arcs for rounded buttons
|
||||
* @param arcHeight the height of the corner arcs for rounded buttons
|
||||
* @param backgroundColor the background color of the button
|
||||
* @param alternateColor the alternate (outline) color
|
||||
* @param actionCommand the button's command
|
||||
* @param commandArgument the button's command argument
|
||||
*/
|
||||
public ButtonSprite (Label label, int style, int arcWidth, int arcHeight,
|
||||
Color backgroundColor, Color alternateColor, String actionCommand,
|
||||
Object commandArgument)
|
||||
{
|
||||
_label = label;
|
||||
_style = style;
|
||||
_arcWidth = arcWidth;
|
||||
_arcHeight = arcHeight;
|
||||
_backgroundColor = backgroundColor;
|
||||
_alternateColor = alternateColor;
|
||||
_actionCommand = actionCommand;
|
||||
_commandArgument = commandArgument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the label displayed by this sprite.
|
||||
*/
|
||||
public Label getLabel ()
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this sprite's bounds after a change to the label.
|
||||
*/
|
||||
public void updateBounds ()
|
||||
{
|
||||
// invalidate the old...
|
||||
invalidate();
|
||||
|
||||
// size the bounds to fit our label
|
||||
Dimension size = _label.getSize();
|
||||
_bounds.width = size.width + PADDING*2 +
|
||||
(_style == ROUNDED ? _arcWidth : 0);
|
||||
_bounds.height = size.height + PADDING*2;
|
||||
|
||||
// ...and the new
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style of this button.
|
||||
*/
|
||||
public void setStyle (int style)
|
||||
{
|
||||
_style = style;
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the style of this button.
|
||||
*/
|
||||
public int getStyle ()
|
||||
{
|
||||
return _style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arc width for rounded buttons.
|
||||
*/
|
||||
public void setArcWidth (int arcWidth)
|
||||
{
|
||||
_arcWidth = arcWidth;
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arc width for rounded buttons.
|
||||
*/
|
||||
public int getArcWidth ()
|
||||
{
|
||||
return _arcWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arc height for rounded buttons.
|
||||
*/
|
||||
public void setArcHeight (int arcHeight)
|
||||
{
|
||||
_arcHeight = arcHeight;
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arc height for rounded buttons.
|
||||
*/
|
||||
public int getArcHeight ()
|
||||
{
|
||||
return _arcHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background color of this button.
|
||||
*/
|
||||
public void setBackgroundColor (Color backgroundColor)
|
||||
{
|
||||
_backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the background color of this button.
|
||||
*/
|
||||
public Color getBackgroundColor ()
|
||||
{
|
||||
return _backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action command generated by this button.
|
||||
*/
|
||||
public void setActionCommand (String actionCommand)
|
||||
{
|
||||
_actionCommand = actionCommand;
|
||||
}
|
||||
|
||||
// documentation inherited from interface CommandSprite
|
||||
public String getActionCommand ()
|
||||
{
|
||||
return _actionCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command argument generated by this button.
|
||||
*/
|
||||
public void setCommandArgument (Object commandArgument)
|
||||
{
|
||||
_commandArgument = commandArgument;
|
||||
}
|
||||
|
||||
// documentation inherited from interface CommandSprite
|
||||
public Object getCommandArgument ()
|
||||
{
|
||||
return _commandArgument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this button is enabled.
|
||||
*/
|
||||
public void setEnabled (boolean enabled)
|
||||
{
|
||||
if (_enabled != enabled) {
|
||||
_enabled = enabled;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface DisableableSprite
|
||||
public boolean isEnabled ()
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
// documentation inherited from interface ArmingSprite
|
||||
public void setArmed (boolean pressed)
|
||||
{
|
||||
if (_pressed != pressed) {
|
||||
_pressed = pressed;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this button appears pressed.
|
||||
*/
|
||||
public boolean isArmed ()
|
||||
{
|
||||
return _pressed;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void init ()
|
||||
{
|
||||
super.init();
|
||||
|
||||
// lay out the label if not already
|
||||
if (!_label.isLaidOut()) {
|
||||
_label.layout(_mgr.getMediaPanel());
|
||||
}
|
||||
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
Color baseTextColor = _label.getTextColor(),
|
||||
baseAlternateColor = _label.getAlternateColor();
|
||||
|
||||
if (!_enabled) {
|
||||
_label.setTextColor(baseTextColor.darker());
|
||||
_label.setAlternateColor(baseAlternateColor.darker());
|
||||
}
|
||||
|
||||
switch (_style) {
|
||||
case NORMAL:
|
||||
gfx.setColor(_enabled ? _backgroundColor :
|
||||
_backgroundColor.darker());
|
||||
gfx.fill3DRect(_bounds.x, _bounds.y, _bounds.width,
|
||||
_bounds.height, !_pressed);
|
||||
_label.render(gfx, _bounds.x + (_pressed ? PADDING :
|
||||
PADDING - 1), _bounds.y + (_pressed ? PADDING :
|
||||
PADDING - 1));
|
||||
break;
|
||||
case ROUNDED:
|
||||
Object aaState = SwingUtil.activateAntiAliasing(gfx);
|
||||
// draw outline
|
||||
gfx.setColor(_alternateColor);
|
||||
gfx.fillRoundRect(_bounds.x, _bounds.y, _bounds.width,
|
||||
_bounds.height, _arcWidth, _arcHeight);
|
||||
// draw foreground
|
||||
gfx.setColor(_enabled ? _backgroundColor :
|
||||
_backgroundColor.darker());
|
||||
int innerBoundsX = _bounds.x+1, innerBoundsY = _bounds.y+1,
|
||||
innerBoundsWidth = _bounds.width-2,
|
||||
innerBoundsHeight = _bounds.height-2,
|
||||
innerBoundsArcWidth = _arcWidth-2,
|
||||
innerBoundsArcHeight = _arcHeight-2;
|
||||
gfx.fillRoundRect(innerBoundsX, innerBoundsY,
|
||||
innerBoundsWidth, innerBoundsHeight,
|
||||
innerBoundsArcWidth, innerBoundsArcHeight);
|
||||
Color brighter = _enabled ? _backgroundColor.brighter() :
|
||||
_backgroundColor, darker = _enabled ?
|
||||
_backgroundColor.darker() :
|
||||
_backgroundColor.darker().darker();
|
||||
// draw the upper left/lower right corners (always dark)
|
||||
gfx.setColor(darker);
|
||||
gfx.drawArc(innerBoundsX, innerBoundsY, innerBoundsArcWidth,
|
||||
innerBoundsArcHeight, 90, 90);
|
||||
gfx.drawArc(innerBoundsX + innerBoundsWidth -
|
||||
innerBoundsArcWidth - 1,
|
||||
innerBoundsY + innerBoundsHeight -
|
||||
innerBoundsArcHeight - 1,
|
||||
innerBoundsArcWidth, innerBoundsArcHeight, 270, 90);
|
||||
// draw the upper right (dark when pressed)
|
||||
gfx.setColor(_pressed ? darker : brighter);
|
||||
gfx.drawLine(innerBoundsX + innerBoundsArcWidth/2,
|
||||
innerBoundsY, innerBoundsX + innerBoundsWidth -
|
||||
innerBoundsArcWidth/2, innerBoundsY);
|
||||
gfx.drawArc(innerBoundsX + innerBoundsWidth -
|
||||
innerBoundsArcWidth - 1, innerBoundsY,
|
||||
innerBoundsArcWidth, innerBoundsArcHeight, 0, 90);
|
||||
gfx.drawLine(innerBoundsX + innerBoundsWidth - 1,
|
||||
innerBoundsY + innerBoundsArcHeight/2,
|
||||
innerBoundsX + innerBoundsWidth - 1, innerBoundsY +
|
||||
innerBoundsHeight - innerBoundsArcHeight/2);
|
||||
// draw the lower left (light when pressed)
|
||||
gfx.setColor(_pressed ? brighter : darker);
|
||||
gfx.drawLine(innerBoundsX, innerBoundsY +
|
||||
innerBoundsArcHeight/2, innerBoundsX,
|
||||
innerBoundsY + innerBoundsHeight -
|
||||
innerBoundsArcHeight/2);
|
||||
gfx.drawArc(innerBoundsX, innerBoundsY + innerBoundsHeight -
|
||||
innerBoundsArcHeight - 1,
|
||||
innerBoundsArcWidth, innerBoundsArcHeight, 180, 90);
|
||||
gfx.drawLine(innerBoundsX + innerBoundsArcWidth/2,
|
||||
innerBoundsY + innerBoundsHeight - 1,
|
||||
innerBoundsX + innerBoundsWidth - innerBoundsArcWidth/2,
|
||||
innerBoundsY + innerBoundsHeight - 1);
|
||||
SwingUtil.restoreAntiAliasing(gfx, aaState);
|
||||
_label.render(gfx, _bounds.x + PADDING + _arcWidth/2 -
|
||||
(_pressed ? 2 : 1),
|
||||
_bounds.y + PADDING + (_pressed ? 1 : 0));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_enabled) {
|
||||
_label.setTextColor(baseTextColor);
|
||||
_label.setAlternateColor(baseAlternateColor);
|
||||
}
|
||||
}
|
||||
|
||||
/** The number of pixels to add between the text and the border. */
|
||||
protected static final int PADDING = 2;
|
||||
|
||||
/** The label associated with this sprite. */
|
||||
protected Label _label;
|
||||
|
||||
/** The button style. */
|
||||
protected int _style;
|
||||
|
||||
/** The width of the corner arcs for rounded rectangle buttons. */
|
||||
protected int _arcWidth;
|
||||
|
||||
/** The height of the corner arcs for rounded rectangle buttons. */
|
||||
protected int _arcHeight;
|
||||
|
||||
/** The action command generated by this button. */
|
||||
protected String _actionCommand;
|
||||
|
||||
/** The command argument generated by this button. */
|
||||
protected Object _commandArgument;
|
||||
|
||||
/** The background color of this sprite. */
|
||||
protected Color _backgroundColor;
|
||||
|
||||
/** The alternate (outline) color of this sprite. */
|
||||
protected Color _alternateColor;
|
||||
|
||||
/** Whether or not the button is currently enabled. */
|
||||
protected boolean _enabled = true;
|
||||
|
||||
/** Whether or not the button is currently pressed. */
|
||||
protected boolean _pressed;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package com.threerings.media.sprite;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Composite;
|
||||
|
||||
import com.threerings.media.util.Path;
|
||||
|
||||
public class FadableImageSprite extends OrientableImageSprite
|
||||
{
|
||||
/**
|
||||
* Fades this sprite in over the specified duration after
|
||||
* waiting for the specified delay.
|
||||
*/
|
||||
public void fadeIn (long delay, long duration)
|
||||
{
|
||||
setAlpha(0.0f);
|
||||
|
||||
_fadeStamp = 0;
|
||||
_fadeDelay = delay;
|
||||
_fadeInDuration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts this sprite on the specified path and fades it in over
|
||||
* the specified duration.
|
||||
*
|
||||
* @param path the path to move along
|
||||
* @param fadePortion the portion of time to spend fading in, from 0.0f
|
||||
* (no time) to 1.0f (the entire time)
|
||||
*/
|
||||
public void moveAndFadeIn (Path path, long pathDuration, float fadePortion)
|
||||
{
|
||||
move(path);
|
||||
|
||||
setAlpha(0.0f);
|
||||
|
||||
_fadeInDuration = (long)(pathDuration*fadePortion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts this sprite on the specified path and fades it out over
|
||||
* the specified duration.
|
||||
*
|
||||
* @param path the path to move along
|
||||
* @param pathDuration the duration of the path
|
||||
* @param fadePortion the portion of time to spend fading out, from 0.0f
|
||||
* (no time) to 1.0f (the entire time)
|
||||
*/
|
||||
public void moveAndFadeOut (Path path, long pathDuration, float fadePortion)
|
||||
{
|
||||
move(path);
|
||||
|
||||
setAlpha(1.0f);
|
||||
|
||||
_pathDuration = pathDuration;
|
||||
_fadeOutDuration = (long)(pathDuration*fadePortion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts this sprite on the specified path, fading it in over the specified
|
||||
* duration at the beginning and fading it out at the end.
|
||||
*
|
||||
* @param path the path to move along
|
||||
* @param pathDuration the duration of the path
|
||||
* @param fadePortion the portion of time to spend fading in/out, from
|
||||
* 0.0f (no time) to 1.0f (the entire time)
|
||||
*/
|
||||
public void moveAndFadeInAndOut (Path path, long pathDuration,
|
||||
float fadePortion)
|
||||
{
|
||||
move(path);
|
||||
|
||||
setAlpha(0.0f);
|
||||
|
||||
_pathDuration = pathDuration;
|
||||
_fadeInDuration = _fadeOutDuration = (long)(pathDuration*fadePortion);
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
super.tick(tickStamp);
|
||||
|
||||
if (_fadeInDuration != -1) {
|
||||
if (_path != null && (tickStamp-_pathStamp) <= _fadeInDuration) {
|
||||
// fading in while moving
|
||||
float alpha = (float)(tickStamp-_pathStamp)/_fadeInDuration;
|
||||
if (alpha >= 1.0f) {
|
||||
// fade-in complete
|
||||
setAlpha(1.0f);
|
||||
_fadeInDuration = -1;
|
||||
|
||||
} else {
|
||||
setAlpha(alpha);
|
||||
}
|
||||
|
||||
} else {
|
||||
// fading in while stationary
|
||||
if (_fadeStamp == 0) {
|
||||
// store the time at which fade started
|
||||
_fadeStamp = tickStamp;
|
||||
}
|
||||
if (tickStamp > _fadeStamp + _fadeDelay) {
|
||||
// initial delay has passed
|
||||
float alpha = (float)(tickStamp-_fadeStamp-_fadeDelay)/
|
||||
_fadeInDuration;
|
||||
if (alpha >= 1.0f) {
|
||||
// fade-in complete
|
||||
setAlpha(1.0f);
|
||||
_fadeInDuration = -1;
|
||||
|
||||
} else {
|
||||
setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (_fadeOutDuration != -1 && _pathStamp+_pathDuration-tickStamp
|
||||
<= _fadeOutDuration) {
|
||||
// fading out while moving
|
||||
float alpha = (float)(_pathStamp+_pathDuration-tickStamp)/
|
||||
_fadeOutDuration;
|
||||
setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
public void pathCompleted (long timestamp)
|
||||
{
|
||||
super.pathCompleted(timestamp);
|
||||
|
||||
if (_fadeInDuration != -1) {
|
||||
setAlpha(1.0f);
|
||||
_fadeInDuration = -1;
|
||||
|
||||
} else if (_fadeOutDuration != -1) {
|
||||
setAlpha(0.0f);
|
||||
_fadeOutDuration = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
if (_alphaComposite.getAlpha() < 1.0f) {
|
||||
Composite ocomp = gfx.getComposite();
|
||||
gfx.setComposite(_alphaComposite);
|
||||
super.paint(gfx);
|
||||
gfx.setComposite(ocomp);
|
||||
|
||||
} else {
|
||||
super.paint(gfx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha value of this sprite.
|
||||
*/
|
||||
public void setAlpha (float alpha)
|
||||
{
|
||||
if (alpha < 0.0f) {
|
||||
alpha = 0.0f;
|
||||
|
||||
} else if (alpha > 1.0f) {
|
||||
alpha = 1.0f;
|
||||
}
|
||||
if (alpha != _alphaComposite.getAlpha()) {
|
||||
_alphaComposite =
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
|
||||
if (_mgr != null) {
|
||||
_mgr.getRegionManager().invalidateRegion(_bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alpha value of this sprite.
|
||||
*/
|
||||
public float getAlpha ()
|
||||
{
|
||||
return _alphaComposite.getAlpha();
|
||||
}
|
||||
|
||||
/** The alpha composite. */
|
||||
protected AlphaComposite _alphaComposite =
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
|
||||
|
||||
/** If fading in, the fade-in duration (otherwise -1). */
|
||||
protected long _fadeInDuration = -1;
|
||||
|
||||
/** If fading in without moving, the fade-in delay. */
|
||||
protected long _fadeDelay;
|
||||
|
||||
/** The time at which fading started. */
|
||||
protected long _fadeStamp = -1;
|
||||
|
||||
/** If fading out, the fade-out duration (otherwise -1). */
|
||||
protected long _fadeOutDuration = -1;
|
||||
|
||||
/** If fading out, the path duration. */
|
||||
protected long _pathDuration;
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
//
|
||||
// $Id: ImageSprite.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.sprite;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.media.util.MultiFrameImage;
|
||||
import com.threerings.media.util.SingleFrameImageImpl;
|
||||
|
||||
/**
|
||||
* Extends the sprite class to support rendering the sprite with one or
|
||||
* more frames of image animation. Overrides various methods to provide
|
||||
* correspondingly desirable functionality, e.g., {@link #hitTest} only
|
||||
* reports a hit if the specified point is within a non-transparent pixel
|
||||
* for the sprite's current image frame.
|
||||
*/
|
||||
public class ImageSprite extends Sprite
|
||||
{
|
||||
/** Default frame rate. */
|
||||
public static final int DEFAULT_FRAME_RATE = 15;
|
||||
|
||||
/** Animation mode indicating no animation. */
|
||||
public static final int NO_ANIMATION = 0;
|
||||
|
||||
/** Animation mode indicating movement cued animation. */
|
||||
public static final int MOVEMENT_CUED = 1;
|
||||
|
||||
/** Animation mode indicating time based animation. */
|
||||
public static final int TIME_BASED = 2;
|
||||
|
||||
/** Animation mode indicating sequential progressive animation.
|
||||
* Frame 0 is guaranteed to be shown first for the full duration, and
|
||||
* so on. */
|
||||
public static final int TIME_SEQUENTIAL = 3;
|
||||
|
||||
/**
|
||||
* Constructs an image sprite without any associated frames and with
|
||||
* an invalid default initial location. The sprite should be populated
|
||||
* with a set of frames used to display it via a subsequent call to
|
||||
* {@link #setFrames}, and its location updated with {@link
|
||||
* #setLocation}.
|
||||
*/
|
||||
public ImageSprite ()
|
||||
{
|
||||
this((MultiFrameImage)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an image sprite.
|
||||
*
|
||||
* @param frames the multi-frame image used to display the sprite.
|
||||
*/
|
||||
public ImageSprite (MultiFrameImage frames)
|
||||
{
|
||||
// initialize frame animation member data
|
||||
_frames = frames;
|
||||
_frameIdx = 0;
|
||||
_animMode = NO_ANIMATION;
|
||||
_frameDelay = 1000L/DEFAULT_FRAME_RATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an image sprite that will display the supplied single
|
||||
* image when rendering itself.
|
||||
*/
|
||||
public ImageSprite (Mirage image)
|
||||
{
|
||||
this(new SingleFrameImageImpl(image));
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void init ()
|
||||
{
|
||||
super.init();
|
||||
|
||||
// now that we have our sprite manager, we can lay ourselves out
|
||||
// and initialize our frames
|
||||
layout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the sprite's bounds contain the specified point,
|
||||
* and if there is a non-transparent pixel in the sprite's image at
|
||||
* the specified point, false if not.
|
||||
*/
|
||||
public boolean hitTest (int x, int y)
|
||||
{
|
||||
// first check to see that we're in the sprite's bounds and that
|
||||
// we've got a frame image (if we've got no image, there's nothing
|
||||
// to be hit)
|
||||
if (!super.hitTest(x, y) || _frames == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _frames.hitTest(_frameIdx, x - _bounds.x, y - _bounds.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the animation mode for this sprite. The available modes are:
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>TIME_BASED</code>: cues the animation based on a target
|
||||
* frame rate (specified via {@link #setFrameRate}).
|
||||
* <li><code>MOVEMENT_CUED</code>: ticks the animation to the next
|
||||
* frame every time the sprite is moved along its path.
|
||||
* <li><code>NO_ANIMATION</code>: disables animation.
|
||||
* </ul>
|
||||
*
|
||||
* @param mode the desired animation mode.
|
||||
*/
|
||||
public void setAnimationMode (int mode)
|
||||
{
|
||||
_animMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of frames per second desired for the sprite
|
||||
* animation. This is only used when the animation mode is
|
||||
* <code>TIME_BASED</code>.
|
||||
*
|
||||
* @param fps the desired frames per second.
|
||||
*/
|
||||
public void setFrameRate (float fps)
|
||||
{
|
||||
_frameDelay = (long)(1000/fps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image to be used for this sprite.
|
||||
*/
|
||||
public void setMirage (Mirage mirage)
|
||||
{
|
||||
setFrames(new SingleFrameImageImpl(mirage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image array used to render the sprite.
|
||||
*
|
||||
* @param frames the sprite images.
|
||||
*/
|
||||
public void setFrames (MultiFrameImage frames)
|
||||
{
|
||||
if (frames == null) {
|
||||
// Log.warning("Someone set up us the null frames! " +
|
||||
// "[sprite=" + this + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// if these are the same frames we already had, no need to do a
|
||||
// bunch of pointless business
|
||||
if (frames == _frames) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set and init our frames
|
||||
_frames = frames;
|
||||
_frameIdx = 0;
|
||||
layout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs this sprite to lay out its current frame and any
|
||||
* accoutrements.
|
||||
*/
|
||||
public void layout ()
|
||||
{
|
||||
if (_frames != null) {
|
||||
setFrameIndex(_frameIdx, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the sprite to display the specified frame index.
|
||||
*/
|
||||
protected void setFrameIndex (int frameIdx, boolean forceUpdate)
|
||||
{
|
||||
// make sure we're displaying a valid frame
|
||||
frameIdx = (frameIdx % _frames.getFrameCount());
|
||||
|
||||
// if this is the same frame we're already displaying and we're
|
||||
// not being forced to update, we can stop now
|
||||
if (frameIdx == _frameIdx && !forceUpdate) {
|
||||
return;
|
||||
} else {
|
||||
_frameIdx = frameIdx;
|
||||
}
|
||||
|
||||
// start with our old bounds
|
||||
Rectangle dirty = new Rectangle(_bounds);
|
||||
|
||||
// determine our drawing offsets and rendered rectangle size
|
||||
accomodateFrame(_frameIdx, _frames.getWidth(_frameIdx),
|
||||
_frames.getHeight(_frameIdx));
|
||||
|
||||
// add our new bounds
|
||||
dirty.add(_bounds);
|
||||
|
||||
// give the dirty rectangle to the region manager
|
||||
if (_mgr != null) {
|
||||
_mgr.getRegionManager().addDirtyRegion(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must adjust the bounds to accomodate the our new frame. This
|
||||
* includes changing the width and height to reflect the size of the
|
||||
* new frame and also updating the render origin (if necessary) and
|
||||
* calling {@link #updateRenderOrigin} to reflect those changes in the
|
||||
* sprite's bounds.
|
||||
*
|
||||
* @param frameIdx the index of our new frame.
|
||||
* @param width the width of the new frame.
|
||||
* @param height the height of the new frame.
|
||||
*/
|
||||
protected void accomodateFrame (int frameIdx, int width, int height)
|
||||
{
|
||||
_bounds.width = width;
|
||||
_bounds.height = height;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
if (_frames != null) {
|
||||
// // DEBUG: fill our background with an alpha'd rectangle
|
||||
// Composite ocomp = gfx.getComposite();
|
||||
// gfx.setComposite(ALPHA_BOUNDS);
|
||||
// gfx.setColor(Color.blue);
|
||||
// gfx.fill(_bounds);
|
||||
// gfx.setComposite(ocomp);
|
||||
|
||||
// render our frame
|
||||
_frames.paintFrame(gfx, _frameIdx, _bounds.x, _bounds.y);
|
||||
|
||||
} else {
|
||||
super.paint(gfx);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long timestamp)
|
||||
{
|
||||
// if we have no frames, we're hosulated (to use a Greenwell term)
|
||||
if (_frames == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fcount = _frames.getFrameCount();
|
||||
boolean moved = false;
|
||||
|
||||
// move the sprite along toward its destination, if any
|
||||
moved = tickPath(timestamp);
|
||||
|
||||
// increment the display image if performing image animation
|
||||
int nfidx = _frameIdx;
|
||||
switch (_animMode) {
|
||||
case NO_ANIMATION:
|
||||
// nothing doing
|
||||
break;
|
||||
|
||||
case TIME_BASED:
|
||||
nfidx = (int)((timestamp/_frameDelay) % fcount);
|
||||
break;
|
||||
|
||||
case TIME_SEQUENTIAL:
|
||||
if (_firstStamp == 0L) {
|
||||
_firstStamp = timestamp;
|
||||
}
|
||||
nfidx = (int) (((timestamp - _firstStamp) / _frameDelay) % fcount);
|
||||
break;
|
||||
|
||||
case MOVEMENT_CUED:
|
||||
// update the frame if the sprite moved
|
||||
if (moved) {
|
||||
nfidx = (_frameIdx + 1) % fcount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// update our frame (which will do nothing if this is the same as
|
||||
// our existing frame index)
|
||||
setFrameIndex(nfidx, false);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", fidx=").append(_frameIdx);
|
||||
}
|
||||
|
||||
/** The images used to render the sprite. */
|
||||
protected MultiFrameImage _frames;
|
||||
|
||||
/** The current frame index to render. */
|
||||
protected int _frameIdx;
|
||||
|
||||
/** What type of animation is desired for this sprite. */
|
||||
protected int _animMode;
|
||||
|
||||
/** For how many milliseconds to display an animation frame. */
|
||||
protected long _frameDelay;
|
||||
|
||||
/** The first timestamp seen (in TIME_SEQUENTIAL mode). */
|
||||
protected long _firstStamp = 0L;
|
||||
|
||||
// /** DEBUG: The alpha level used when rendering our bounds. */
|
||||
// protected static final Composite ALPHA_BOUNDS =
|
||||
// AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// $Id: LabelSprite.java 3542 2005-05-06 03:01:43Z 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.sprite;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
|
||||
import com.samskivert.swing.Label;
|
||||
|
||||
/**
|
||||
* A sprite that uses a label to render itself. If the label has not been
|
||||
* previously laid out (see {@link Label#layout}) it will be done when the
|
||||
* sprite is added to a media panel. If the label is altered after the
|
||||
* sprite is created, {@link #updateBounds} should be called.
|
||||
*/
|
||||
public class LabelSprite extends Sprite
|
||||
{
|
||||
/**
|
||||
* Constructs a label sprite that renders itself with the specified
|
||||
* label.
|
||||
*/
|
||||
public LabelSprite (Label label)
|
||||
{
|
||||
_label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label displayed by this sprite.
|
||||
*/
|
||||
public Label getLabel ()
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that our label should be rendered with antialiased text.
|
||||
*/
|
||||
public void setAntiAliased (boolean antiAliased)
|
||||
{
|
||||
_antiAliased = antiAliased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the bounds of the sprite after a change to the label.
|
||||
*/
|
||||
public void updateBounds ()
|
||||
{
|
||||
Dimension size = _label.getSize();
|
||||
_bounds.width = size.width;
|
||||
_bounds.height = size.height;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void init ()
|
||||
{
|
||||
super.init();
|
||||
|
||||
// if our label is not yet laid out, do the deed
|
||||
if (!_label.isLaidOut()) {
|
||||
layoutLabel();
|
||||
}
|
||||
|
||||
// size the bounds to fit our label
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
_label.render(gfx, _bounds.x, _bounds.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lays out our underlying label which must be done if the text is
|
||||
* changed.
|
||||
*/
|
||||
protected void layoutLabel ()
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/** The label associated with this sprite. */
|
||||
protected Label _label;
|
||||
|
||||
/** Whether or not to use anti-aliased rendering. */
|
||||
protected boolean _antiAliased;
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
//
|
||||
// $Id: OrientableImageSprite.java 3586 2005-06-05 16:41:10Z 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.sprite;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
import com.threerings.media.util.MultiFrameImage;
|
||||
|
||||
/**
|
||||
* An image sprite that uses AWT's rotation methods to render itself in
|
||||
* different orientations.
|
||||
*/
|
||||
public class OrientableImageSprite extends ImageSprite
|
||||
{
|
||||
/**
|
||||
* Creates a new orientable image sprite.
|
||||
*/
|
||||
public OrientableImageSprite ()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Creates a new orientable image sprite.
|
||||
*
|
||||
* @param image the image to render
|
||||
*/
|
||||
public OrientableImageSprite (Mirage image)
|
||||
{
|
||||
super(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new orientable image sprite.
|
||||
*
|
||||
* @param frames the frames to render
|
||||
*/
|
||||
public OrientableImageSprite (MultiFrameImage frames)
|
||||
{
|
||||
super(frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the rotation transform for this
|
||||
* sprite.
|
||||
*
|
||||
* @return the newly computed rotation transform
|
||||
*/
|
||||
private AffineTransform getRotationTransform ()
|
||||
{
|
||||
double theta;
|
||||
|
||||
switch (_orient) {
|
||||
case NORTH:
|
||||
default:
|
||||
theta = 0.0;
|
||||
break;
|
||||
|
||||
case SOUTH:
|
||||
theta = Math.PI;
|
||||
break;
|
||||
|
||||
case EAST:
|
||||
theta = Math.PI*0.5;
|
||||
break;
|
||||
|
||||
case WEST:
|
||||
theta = -Math.PI*0.5;
|
||||
break;
|
||||
|
||||
case NORTHEAST:
|
||||
theta = Math.PI*0.25;
|
||||
break;
|
||||
|
||||
case NORTHWEST:
|
||||
theta = -Math.PI*0.25;
|
||||
break;
|
||||
|
||||
case SOUTHEAST:
|
||||
theta = Math.PI*0.75;
|
||||
break;
|
||||
|
||||
case SOUTHWEST:
|
||||
theta = -Math.PI*0.75;
|
||||
break;
|
||||
|
||||
case NORTHNORTHEAST:
|
||||
theta = -Math.PI*0.125;
|
||||
break;
|
||||
|
||||
case NORTHNORTHWEST:
|
||||
theta = Math.PI*0.125;
|
||||
break;
|
||||
|
||||
case SOUTHSOUTHEAST:
|
||||
theta = -Math.PI*0.875;
|
||||
break;
|
||||
|
||||
case SOUTHSOUTHWEST:
|
||||
theta = Math.PI*0.875;
|
||||
break;
|
||||
|
||||
case EASTNORTHEAST:
|
||||
theta = -Math.PI*0.375;
|
||||
break;
|
||||
|
||||
case EASTSOUTHEAST:
|
||||
theta = -Math.PI*0.625;
|
||||
break;
|
||||
|
||||
case WESTNORTHWEST:
|
||||
theta = Math.PI*0.375;
|
||||
break;
|
||||
|
||||
case WESTSOUTHWEST:
|
||||
theta = Math.PI*0.625;
|
||||
break;
|
||||
}
|
||||
|
||||
return AffineTransform.getRotateInstance(
|
||||
theta,
|
||||
(_ox - _oxoff) + _frames.getWidth(_frameIdx)/2,
|
||||
(_oy - _oyoff) + _frames.getHeight(_frameIdx)/2
|
||||
);
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
protected void accomodateFrame (int frameIdx, int width, int height)
|
||||
{
|
||||
Area area = new Area(
|
||||
new Rectangle(
|
||||
(_ox - _oxoff),
|
||||
(_oy - _oyoff),
|
||||
width,
|
||||
height
|
||||
)
|
||||
);
|
||||
|
||||
area.transform(getRotationTransform());
|
||||
|
||||
_bounds = area.getBounds();
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
public void setOrientation (int orient)
|
||||
{
|
||||
super.setOrientation(orient);
|
||||
|
||||
layout();
|
||||
}
|
||||
|
||||
// Documentation inherited.
|
||||
public void paint (Graphics2D graphics)
|
||||
{
|
||||
AffineTransform at = graphics.getTransform();
|
||||
|
||||
graphics.transform(getRotationTransform());
|
||||
|
||||
if (_frames != null) {
|
||||
_frames.paintFrame(
|
||||
graphics,
|
||||
_frameIdx,
|
||||
_ox - _oxoff,
|
||||
_oy - _oyoff
|
||||
);
|
||||
}
|
||||
else {
|
||||
super.paint(graphics);
|
||||
}
|
||||
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// $Id: PathAdapter.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.sprite;
|
||||
|
||||
import com.threerings.media.util.Path;
|
||||
|
||||
/**
|
||||
* An adapter class for {@link PathObserver}.
|
||||
*/
|
||||
public class PathAdapter implements PathObserver
|
||||
{
|
||||
// documentation inherited from interface
|
||||
public void pathCancelled (Sprite sprite, Path path)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void pathCompleted (Sprite sprite, Path path, long when)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// $Id: PathObserver.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.sprite;
|
||||
|
||||
import com.threerings.media.util.Path;
|
||||
|
||||
/**
|
||||
* An interface to be implemented by classes that would like to be
|
||||
* notified when a sprite completes or cancels its path.
|
||||
*/
|
||||
public interface PathObserver
|
||||
{
|
||||
/**
|
||||
* Called when a sprite's path is cancelled either because a new path
|
||||
* was started or the path was explicitly cancelled with {@link
|
||||
* Sprite#cancelMove}.
|
||||
*/
|
||||
public void pathCancelled (Sprite sprite, Path path);
|
||||
|
||||
/**
|
||||
* Called when a sprite completes its traversal of a path.
|
||||
*
|
||||
* @param sprite the sprite that completed its path.
|
||||
* @param path the path that was completed.
|
||||
* @param when the tick stamp of the media tick on which the path was
|
||||
* completed (see {@link SpriteManager#tick}) (this may not be in the
|
||||
* same time domain as {@link System#currentTimeMillis}).
|
||||
*/
|
||||
public void pathCompleted (Sprite sprite, Path path, long when);
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
//
|
||||
// $Id: Sprite.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.sprite;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
|
||||
import com.samskivert.util.ObserverList;
|
||||
import com.threerings.util.DirectionCodes;
|
||||
|
||||
import com.threerings.media.AbstractMedia;
|
||||
import com.threerings.media.util.Path;
|
||||
import com.threerings.media.util.Pathable;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* The sprite class represents a single moveable object in an animated
|
||||
* view. A sprite has a position and orientation within the view, and can
|
||||
* be moved along a path.
|
||||
*/
|
||||
public abstract class Sprite extends AbstractMedia
|
||||
implements DirectionCodes, Pathable
|
||||
{
|
||||
/**
|
||||
* Constructs a sprite with an initially invalid location. Because
|
||||
* sprite derived classes generally want to get in on the business
|
||||
* when a sprite's location is set, it is not safe to do so in the
|
||||
* constructor because their derived methods will be called before
|
||||
* their constructor has been called. Thus a sprite should be fully
|
||||
* constructed and <em>then</em> its location should be set.
|
||||
*/
|
||||
public Sprite ()
|
||||
{
|
||||
this(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a sprite with the supplied dimensions. Because
|
||||
* sprite derived classes generally want to get in on the business
|
||||
* when a sprite's location is set, it is not safe to do so in the
|
||||
* constructor because their derived methods will be called before
|
||||
* their constructor has been called. Thus a sprite should be fully
|
||||
* constructed and <em>then</em> its location should be set.
|
||||
*/
|
||||
public Sprite (int width, int height)
|
||||
{
|
||||
super(new Rectangle(0, 0, width, height));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite's x position in screen coordinates. This is the
|
||||
* x coordinate of the sprite's origin, not the upper left of its
|
||||
* bounds.
|
||||
*/
|
||||
public int getX ()
|
||||
{
|
||||
return _ox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite's y position in screen coordinates. This is the
|
||||
* y coordinate of the sprite's origin, not the upper left of its
|
||||
* bounds.
|
||||
*/
|
||||
public int getY ()
|
||||
{
|
||||
return _oy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset to the sprite's origin from the upper-left of
|
||||
* the sprite's image.
|
||||
*/
|
||||
public int getXOffset ()
|
||||
{
|
||||
return _oxoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset to the sprite's origin from the upper-left of
|
||||
* the sprite's image.
|
||||
*/
|
||||
public int getYOffset ()
|
||||
{
|
||||
return _oyoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite's width in pixels.
|
||||
*/
|
||||
public int getWidth ()
|
||||
{
|
||||
return _bounds.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite's height in pixels.
|
||||
*/
|
||||
public int getHeight ()
|
||||
{
|
||||
return _bounds.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sprites have an orientation in one of the eight cardinal
|
||||
* directions: <code>NORTH</code>, <code>NORTHEAST</code>, etc.
|
||||
* Derived classes can choose to override this member function and
|
||||
* select a different set of images based on their orientation, or
|
||||
* they can ignore the orientation information.
|
||||
*
|
||||
* @see DirectionCodes
|
||||
*/
|
||||
public void setOrientation (int orient)
|
||||
{
|
||||
_orient = orient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sprite's orientation as one of the eight cardinal
|
||||
* directions: <code>NORTH</code>, <code>NORTHEAST</code>, etc.
|
||||
*
|
||||
* @see DirectionCodes
|
||||
*/
|
||||
public int getOrientation ()
|
||||
{
|
||||
return _orient;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setLocation (int x, int y)
|
||||
{
|
||||
if (x == _ox && y == _oy) {
|
||||
return; // no-op
|
||||
}
|
||||
|
||||
// start with our current bounds
|
||||
Rectangle dirty = new Rectangle(_bounds);
|
||||
|
||||
// move ourselves
|
||||
_ox = x;
|
||||
_oy = y;
|
||||
|
||||
// we need to update our draw position which is based on the size
|
||||
// of our current bounds
|
||||
updateRenderOrigin();
|
||||
|
||||
// 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
|
||||
public void paint (Graphics2D gfx)
|
||||
{
|
||||
gfx.drawRect(_bounds.x, _bounds.y, _bounds.width-1, _bounds.height-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the sprite's path, if any, to the specified graphics context.
|
||||
*
|
||||
* @param gfx the graphics context.
|
||||
*/
|
||||
public void paintPath (Graphics2D gfx)
|
||||
{
|
||||
if (_path != null) {
|
||||
_path.paint(gfx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the sprite's bounds contain the specified point,
|
||||
* false if not.
|
||||
*/
|
||||
public boolean contains (int x, int y)
|
||||
{
|
||||
return _bounds.contains(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the sprite's bounds contain the specified point,
|
||||
* false if not.
|
||||
*/
|
||||
public boolean hitTest (int x, int y)
|
||||
{
|
||||
return _bounds.contains(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sprite is inside the given shape in pixel
|
||||
* coordinates.
|
||||
*/
|
||||
public boolean inside (Shape shape)
|
||||
{
|
||||
return shape.contains(_ox, _oy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sprite's drawn rectangle intersects the given
|
||||
* shape in pixel coordinates.
|
||||
*/
|
||||
public boolean intersects (Shape shape)
|
||||
{
|
||||
return shape.intersects(_bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this sprite is currently following a path, false if
|
||||
* it is not.
|
||||
*/
|
||||
public boolean isMoving ()
|
||||
{
|
||||
return (_path != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sprite's active path and start moving it along its merry
|
||||
* way. If the sprite is already moving along a previous path the old
|
||||
* path will be lost and the new path will begin to be traversed.
|
||||
*
|
||||
* @param path the path to follow.
|
||||
*/
|
||||
public void move (Path path)
|
||||
{
|
||||
// if there's a previous path, let it know that it's going away
|
||||
cancelMove();
|
||||
|
||||
// save off this path
|
||||
_path = path;
|
||||
|
||||
// we'll initialize it on our next tick thanks to a zero path stamp
|
||||
_pathStamp = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any path that the sprite may currently be moving along.
|
||||
*/
|
||||
public void cancelMove ()
|
||||
{
|
||||
if (_path != null) {
|
||||
Path oldpath = _path;
|
||||
_path = null;
|
||||
oldpath.wasRemoved(this);
|
||||
if (_observers != null) {
|
||||
_observers.apply(new CancelledOp(this, oldpath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path being followed by this sprite or null if the
|
||||
* sprite is not following a path.
|
||||
*/
|
||||
public Path getPath ()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the active path when it begins.
|
||||
*/
|
||||
public void pathBeginning ()
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the active path when it has completed.
|
||||
*/
|
||||
public void pathCompleted (long timestamp)
|
||||
{
|
||||
Path oldpath = _path;
|
||||
_path = null;
|
||||
oldpath.wasRemoved(this);
|
||||
if (_observers != null) {
|
||||
_observers.apply(new CompletedOp(this, oldpath, timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void tick (long tickStamp)
|
||||
{
|
||||
tickPath(tickStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticks any path assigned to this sprite.
|
||||
*
|
||||
* @return true if the path relocated the sprite as a result of this
|
||||
* tick, false if it remained in the same position.
|
||||
*/
|
||||
protected boolean tickPath (long tickStamp)
|
||||
{
|
||||
if (_path == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize the path if we haven't yet
|
||||
if (_pathStamp == 0) {
|
||||
_path.init(this, _pathStamp = tickStamp);
|
||||
}
|
||||
|
||||
// it's possible that as a result of init() the path completed and
|
||||
// removed itself with a call to pathCompleted(), so we have to be
|
||||
// careful here
|
||||
return (_path == null) ? true : _path.tick(this, tickStamp);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void fastForward (long timeDelta)
|
||||
{
|
||||
// fast forward any path we're following
|
||||
if (_path != null) {
|
||||
_path.fastForward(timeDelta);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the coordinates at which the sprite image is drawn to
|
||||
* reflect the sprite's current position.
|
||||
*/
|
||||
protected void updateRenderOrigin ()
|
||||
{
|
||||
// our bounds origin may differ from the sprite's origin
|
||||
_bounds.x = _ox - _oxoff;
|
||||
_bounds.y = _oy - _oyoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sprite observer to observe this sprite's events.
|
||||
*
|
||||
* @param obs the sprite observer.
|
||||
*/
|
||||
public void addSpriteObserver (Object obs)
|
||||
{
|
||||
addObserver(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a sprite observer.
|
||||
*/
|
||||
public void removeSpriteObserver (Object obs)
|
||||
{
|
||||
removeObserver(obs);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void viewLocationDidChange (int dx, int dy)
|
||||
{
|
||||
if (_renderOrder >= HUD_LAYER) {
|
||||
setLocation(_ox + dx, _oy + dy);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void shutdown ()
|
||||
{
|
||||
super.shutdown();
|
||||
cancelMove(); // cancel any active path
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", ox=").append(_ox);
|
||||
buf.append(", oy=").append(_oy);
|
||||
buf.append(", oxoff=").append(_oxoff);
|
||||
buf.append(", oyoff=").append(_oyoff);
|
||||
}
|
||||
|
||||
/** Used to dispatch {@link PathObserver#pathCancelled}. */
|
||||
protected static class CancelledOp implements ObserverList.ObserverOp
|
||||
{
|
||||
public CancelledOp (Sprite sprite, Path path) {
|
||||
_sprite = sprite;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
public boolean apply (Object observer) {
|
||||
if (observer instanceof PathObserver) {
|
||||
((PathObserver)observer).pathCancelled(_sprite, _path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Sprite _sprite;
|
||||
protected Path _path;
|
||||
}
|
||||
|
||||
/** Used to dispatch {@link PathObserver#pathCompleted}. */
|
||||
protected static class CompletedOp implements ObserverList.ObserverOp
|
||||
{
|
||||
public CompletedOp (Sprite sprite, Path path, long when) {
|
||||
_sprite = sprite;
|
||||
_path = path;
|
||||
_when = when;
|
||||
}
|
||||
|
||||
public boolean apply (Object observer) {
|
||||
if (observer instanceof PathObserver) {
|
||||
((PathObserver)observer).pathCompleted(_sprite, _path, _when);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Sprite _sprite;
|
||||
protected Path _path;
|
||||
protected long _when;
|
||||
}
|
||||
|
||||
/** The location of the sprite's origin in pixel coordinates. If the
|
||||
* sprite positions itself via a hotspot that is not the upper left
|
||||
* coordinate of the sprite's bounds, the offset to the hotspot should
|
||||
* be maintained in {@link #_oxoff} and {@link #_oyoff}. */
|
||||
protected int _ox = Integer.MIN_VALUE, _oy = Integer.MIN_VALUE;
|
||||
|
||||
/** The offsets from our upper left coordinate to our origin (or hot
|
||||
* spot). Derived classes will need to update these values if the
|
||||
* sprite's origin is not coincident with the upper left coordinate of
|
||||
* its bounds. */
|
||||
protected int _oxoff, _oyoff;
|
||||
|
||||
/** The orientation of this sprite. */
|
||||
protected int _orient = NONE;
|
||||
|
||||
/** When moving, the path the sprite is traversing. */
|
||||
protected Path _path;
|
||||
|
||||
/** The timestamp at which we started along our path. */
|
||||
protected long _pathStamp;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// $Id: SpriteIcon.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.sprite;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
/**
|
||||
* Implements the icon interface, using a {@link Sprite} to render the
|
||||
* icon image.
|
||||
*/
|
||||
public class SpriteIcon implements Icon
|
||||
{
|
||||
/**
|
||||
* Creates a sprite icon that will use the supplied sprite to render
|
||||
* itself. This sprite should not be used for anything else while
|
||||
* being used in this icon because it will be "moved" when the icon is
|
||||
* rendered. The sprite's origin will be set to the bottom center of
|
||||
* the label.
|
||||
*/
|
||||
public SpriteIcon (Sprite sprite)
|
||||
{
|
||||
this(sprite, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sprite icon that will use the supplied sprite to render
|
||||
* itself. This sprite should not be used for anything else while
|
||||
* being used in this icon because it will be "moved" when the icon is
|
||||
* rendered. The sprite's origin will be set to the bottom center of
|
||||
* the label.
|
||||
*
|
||||
* @param sprite the sprite to render in this label.
|
||||
* @param padding the number of pixels of blank space to put on all
|
||||
* four sides of the sprite.
|
||||
*/
|
||||
public SpriteIcon (Sprite sprite, int padding)
|
||||
{
|
||||
_sprite = sprite;
|
||||
// the sprite should be ticked once so that we can safely paint it
|
||||
_sprite.tick(System.currentTimeMillis());
|
||||
_padding = padding;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void paintIcon (Component c, Graphics g, int x, int y)
|
||||
{
|
||||
// move the sprite to a "location" that results in its image being
|
||||
// in the upper left of the rectangle we desire
|
||||
_sprite.setLocation(x + _sprite.getXOffset() + _padding,
|
||||
y + _sprite.getYOffset() + _padding);
|
||||
_sprite.paint((Graphics2D)g);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getIconWidth ()
|
||||
{
|
||||
return _sprite.getWidth() + 2*_padding;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public int getIconHeight ()
|
||||
{
|
||||
return _sprite.getHeight() + 2*_padding;
|
||||
}
|
||||
|
||||
/** The sprite used to render this icon. */
|
||||
protected Sprite _sprite;
|
||||
|
||||
/** Used to put a bit of padding around the sprite image. */
|
||||
protected int _padding;
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
//
|
||||
// $Id: SpriteManager.java 3733 2005-10-13 19:00:08Z 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.sprite;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.threerings.media.AbstractMediaManager;
|
||||
import com.threerings.media.MediaPanel;
|
||||
|
||||
/**
|
||||
* The sprite manager manages the sprites running about in the game.
|
||||
*/
|
||||
public class SpriteManager extends AbstractMediaManager
|
||||
{
|
||||
/** A predicate used to operate on sprites (see {@link #removeSprites}. */
|
||||
public static interface Predicate
|
||||
{
|
||||
/** Returns true if this sprite is to be included by the predicate,
|
||||
* false if it should be excluded. */
|
||||
public boolean evaluate (Sprite sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct and initialize the sprite manager.
|
||||
*/
|
||||
public SpriteManager (MediaPanel panel)
|
||||
{
|
||||
super(panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* When an animated view processes its dirty rectangles, it may
|
||||
* require an expansion of the dirty region which may in turn
|
||||
* require the invalidation of more sprites than were originally
|
||||
* invalid. In such cases, the animated view can call back to the
|
||||
* sprite manager, asking it to append the sprites that intersect
|
||||
* a particular region to the given list.
|
||||
*
|
||||
* @param list the list to fill with any intersecting sprites.
|
||||
* @param shape the shape in which we have interest.
|
||||
*/
|
||||
public void getIntersectingSprites (List list, Shape shape)
|
||||
{
|
||||
int size = _media.size();
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
Sprite sprite = (Sprite)_media.get(ii);
|
||||
if (sprite.intersects(shape)) {
|
||||
list.add(sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When an animated view is determining what entity in its view is
|
||||
* under the mouse pointer, it may require a list of sprites that are
|
||||
* "hit" by a particular pixel. The sprites' bounds are first checked
|
||||
* and sprites with bounds that contain the supplied point are further
|
||||
* checked for a non-transparent at the specified location.
|
||||
*
|
||||
* @param list the list to fill with any intersecting sprites, the
|
||||
* sprites with the highest render order provided first.
|
||||
* @param x the x (screen) coordinate to be checked.
|
||||
* @param y the y (screen) coordinate to be checked.
|
||||
*/
|
||||
public void getHitSprites (List list, int x, int y)
|
||||
{
|
||||
for (int ii = _media.size() - 1; ii >= 0; ii--) {
|
||||
Sprite sprite = (Sprite)_media.get(ii);
|
||||
if (sprite.hitTest(x, y)) {
|
||||
list.add(sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the sprite with the highest render order that hits the
|
||||
* specified pixel.
|
||||
*
|
||||
* @param x the x (screen) coordinate to be checked
|
||||
* @param y the y (screen) coordinate to be checked
|
||||
* @return the highest sprite hit
|
||||
*/
|
||||
public Sprite getHighestHitSprite (int x, int y)
|
||||
{
|
||||
// since they're stored in lowest -> highest order..
|
||||
for (int ii = _media.size() - 1; ii >= 0; ii--) {
|
||||
Sprite sprite = (Sprite)_media.get(ii);
|
||||
if (sprite.hitTest(x, y)) {
|
||||
return sprite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sprite to the set of sprites managed by this manager.
|
||||
*
|
||||
* @param sprite the sprite to add.
|
||||
*/
|
||||
public void addSprite (Sprite sprite)
|
||||
{
|
||||
if (insertMedia(sprite)) {
|
||||
// and invalidate the sprite's original position
|
||||
sprite.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all sprites registered with the sprite manager.
|
||||
* The returned list is immutable, sprites should be added or removed
|
||||
* using {@link #addSprite} or {@link #removeSprite}.
|
||||
*/
|
||||
public List getSprites ()
|
||||
{
|
||||
return Collections.unmodifiableList(_media);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over our managed sprites. Do not call
|
||||
* {@link Iterator#remove}.
|
||||
*/
|
||||
public Iterator enumerateSprites ()
|
||||
{
|
||||
return _media.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified sprite from the set of sprites managed by
|
||||
* this manager.
|
||||
*
|
||||
* @param sprite the sprite to remove.
|
||||
*/
|
||||
public void removeSprite (Sprite sprite)
|
||||
{
|
||||
removeMedia(sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all sprites that match the supplied predicate.
|
||||
*/
|
||||
public void removeSprites (Predicate pred)
|
||||
{
|
||||
int idxoff = 0;
|
||||
for (int ii = 0, ll = _media.size(); ii < ll; ii++) {
|
||||
Sprite sprite = (Sprite)_media.get(ii-idxoff);
|
||||
if (pred.evaluate(sprite)) {
|
||||
_media.remove(sprite);
|
||||
sprite.invalidate();
|
||||
sprite.shutdown();
|
||||
// we need to preserve the original "index" relative to the
|
||||
// current tick position, so we don't decrement ii directly
|
||||
idxoff++;
|
||||
if (ii <= _tickpos) {
|
||||
_tickpos--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the sprite paths to the given graphics context.
|
||||
*
|
||||
* @param gfx the graphics context.
|
||||
*/
|
||||
public void renderSpritePaths (Graphics2D gfx)
|
||||
{
|
||||
for (int ii=0, nn=_media.size(); ii < nn; ii++) {
|
||||
Sprite sprite = (Sprite)_media.get(ii);
|
||||
sprite.paintPath(gfx);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE- collision handling code is turned off for now. To re-implement,
|
||||
// a new array should be kept with sprites sorted in some sort of x/y order
|
||||
//
|
||||
// /**
|
||||
// * Check all sprites for collisions with others and inform any
|
||||
// * sprite observers.
|
||||
// */
|
||||
// protected void handleCollisions ()
|
||||
// {
|
||||
// // gather a list of all sprite collisions
|
||||
// int size = _sprites.size();
|
||||
// for (int ii = 0; ii < size; ii++) {
|
||||
// Sprite sprite = (Sprite)_sprites.get(ii);
|
||||
// checkCollisions(ii, size, sprite);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Check a sprite for collision with any other sprites in the
|
||||
// * sprite list and notify the sprite observers associated with any
|
||||
// * sprites that do indeed collide.
|
||||
// *
|
||||
// * @param idx the starting sprite index.
|
||||
// * @param size the total number of sprites.
|
||||
// * @param sprite the sprite to check against other sprites for
|
||||
// * collisions.
|
||||
// */
|
||||
// protected void checkCollisions (int idx, int size, Sprite sprite)
|
||||
// {
|
||||
// // TODO: make this handle quickly moving objects that may pass
|
||||
// // through each other.
|
||||
//
|
||||
// // if we're the last sprite we know we've already handled any
|
||||
// // collisions
|
||||
// if (idx == (size - 1)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // calculate the x-position of the right edge of the sprite we're
|
||||
// // checking for collisions
|
||||
// Rectangle bounds = sprite.getBounds();
|
||||
// int edgeX = bounds.x + bounds.width;
|
||||
//
|
||||
// for (int ii = (idx + 1); ii < size; ii++) {
|
||||
// Sprite other = (Sprite)_sprites.get(ii);
|
||||
// Rectangle obounds = other.getBounds();
|
||||
// if (obounds.x > edgeX) {
|
||||
// // since sprites are stored in the list sorted by
|
||||
// // ascending x-position, we know this sprite and any
|
||||
// // other sprites farther on in the list can't possibly
|
||||
// // intersect with the sprite we're checking, so we're
|
||||
// // done.
|
||||
// return;
|
||||
//
|
||||
// } else if (obounds.intersects(bounds)) {
|
||||
// sprite.notifyObservers(new CollisionEvent(sprite, other));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// /** The comparator used to sort sprites by horizontal position. */
|
||||
// protected static final Comparator SPRITE_COMP = new SpriteComparator();
|
||||
//
|
||||
// /** Used to sort sprites. */
|
||||
// protected static class SpriteComparator implements Comparator
|
||||
// {
|
||||
// public int compare (Object o1, Object o2)
|
||||
// {
|
||||
// Sprite s1 = (Sprite)o1;
|
||||
// Sprite s2 = (Sprite)o2;
|
||||
// return (s2.getX() - s1.getX());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.media.sprite.action;
|
||||
|
||||
/**
|
||||
* An Action sprite is a sprite that may be pressed to generate an
|
||||
* ActionEvent that will be posted to the Controller hierarchy.
|
||||
*/
|
||||
public interface ActionSprite
|
||||
{
|
||||
/**
|
||||
* @return the action command to submit if this sprite is clicked.
|
||||
*/
|
||||
public String getActionCommand ();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.media.sprite.action;
|
||||
|
||||
/**
|
||||
* An ActionSprite that wishes to be notified of events when it is armed
|
||||
* or not.
|
||||
*/
|
||||
public interface ArmingSprite extends ActionSprite
|
||||
{
|
||||
/**
|
||||
* Render this sprite such that is is drawn "armed".
|
||||
*/
|
||||
public void setArmed (boolean armed);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.media.sprite.action;
|
||||
|
||||
/**
|
||||
* Extends CommandSprite to be a sprite that posts CommandEvents to
|
||||
* the Controller hierarchy.
|
||||
*/
|
||||
public interface CommandSprite extends ActionSprite
|
||||
{
|
||||
/**
|
||||
* @return the argument to the action command.
|
||||
*/
|
||||
public Object getCommandArgument();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.media.sprite.action;
|
||||
|
||||
/**
|
||||
* Indicates a Sprite that may or may not be enabled to receive
|
||||
* action / hover / arming notifications.
|
||||
*/
|
||||
public interface DisableableSprite
|
||||
{
|
||||
/**
|
||||
* @return true if this sprite is currently enabled.
|
||||
*/
|
||||
public boolean isEnabled ();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.media.sprite.action;
|
||||
|
||||
/**
|
||||
* An interface indicating that a sprite wishes to be notified when
|
||||
* the mouse hovers over it.
|
||||
*/
|
||||
public interface HoverSprite
|
||||
{
|
||||
/**
|
||||
* Set the current hover state.
|
||||
*/
|
||||
public void setHovered (boolean hovered);
|
||||
}
|
||||
Reference in New Issue
Block a user