
com.threerings.media.sprite.SpriteManager Maven / Gradle / Ivy
//
// 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.sprite;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.awt.Graphics2D;
import java.awt.Shape;
import com.google.common.base.Predicate;
import com.samskivert.util.SortableArrayList;
import com.threerings.media.AbstractMedia;
import com.threerings.media.AbstractMediaManager;
/**
* The sprite manager manages the sprites running about in the game.
*/
public class SpriteManager extends AbstractMediaManager
{
/**
* 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 = _sprites.size();
for (int ii = 0; ii < size; ii++) {
Sprite sprite = _sprites.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 = _sprites.size() - 1; ii >= 0; ii--) {
Sprite sprite = _sprites.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 = _sprites.size() - 1; ii >= 0; ii--) {
Sprite sprite = _sprites.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(_sprites);
}
/**
* Returns an iterator over our managed sprites. Do not call {@link Iterator#remove}.
*/
public Iterator enumerateSprites ()
{
return _sprites.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 = _sprites.size(); ii < ll; ii++) {
Sprite sprite = _sprites.get(ii-idxoff);
if (pred.apply(sprite)) {
_sprites.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 (Sprite sprite : _sprites) {
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 = _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 = _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 (Sprite s1, Sprite s2)
// {
// return (s2.getX() - s1.getX());
// }
// }
@Override
protected SortableArrayList extends AbstractMedia> createMediaList ()
{
return (_sprites = new SortableArrayList());
}
protected SortableArrayList _sprites;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy