
com.threerings.media.sprite.SpriteManager 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.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