[sf-library~sf:4] Added callback iterators, minor API aditions, bug fixes and performance i
- From: StudioFortress@kenai.com
- To: commits@sf-library.kenai.com
- Subject: [sf-library~sf:4] Added callback iterators, minor API aditions, bug fixes and performance i
- Date: Thu, 28 Jan 2010 21:45:00 +0000
Project: sf-library
Repository: sf
Revision: 4
Author: StudioFortress
Date: 2010-01-28 21:44:53 UTC
Link:
Log Message:
------------
Added callback iterators, minor API aditions, bug fixes and performance
improvements.
Revisions:
----------
4
Modified Paths:
---------------
SF/src/com/studiofortress/sf/util/structure/DeltaTimeEvent.java
SF/src/com/studiofortress/sf/util/collections/CachingHashSet.java
SF/src/com/studiofortress/sf/util/Resource.java
SF/src/com/studiofortress/sf/graphics/GraphicsCanvas.java
SF/src/com/studiofortress/sf/graphics/display/GraphicsWrapper.java
SF/src/com/studiofortress/sf/structure/WorldControls.java
SF/src/com/studiofortress/sf/graphics/display/GraphicsPanel.java
SF/src/com/studiofortress/sf/graphics/GLTextureManager.java
SF/src/com/studiofortress/sf/structure/SortedActors.java
SF/src/com/studiofortress/sf/structure/WorldControlsInner.java
SF/src/com/studiofortress/sf/graphics/GraphicsGL.java
SF/src/com/studiofortress/sf/structure/MainLoop.java
SF/src/com/studiofortress/sf/audio/InnerAudioPlayer.java
SF/src/com/studiofortress/sf/structure/collisions/GridCollisions.java
SF/src/com/studiofortress/sf/util/structure/loading/LoadTextureAction.java
SF/src/com/studiofortress/sf/graphics/display/Controls.java
SF/src/com/studiofortress/sf/util/CommonStartupApplet.java
SF/src/com/studiofortress/sf/util/collections/CachingLinkedList.java
SF/src/com/studiofortress/sf/structure/intersection/EllipseIntersection.java
SF/src/com/studiofortress/sf/graphics/display/DisplayControls.java
SF/src/com/studiofortress/sf/util/Timer.java
SF/src/com/studiofortress/sf/util/structure/loading/LoadingWorld.java
SF/src/com/studiofortress/sf/structure/World.java
SF/src/com/studiofortress/sf/util/collections/ClassInheritenceMap.java
SF/src/com/studiofortress/sf/graphics/GLTextureInner.java
SF/src/com/studiofortress/sf/util/Angle.java
SF/src/com/studiofortress/sf/util/collections/CachingHashMap.java
SF/src/com/studiofortress/sf/util/structure/ButtonActor.java
Added Paths:
------------
SF/src/com/studiofortress/sf/util/collections/CallbackPartialIterator.java
SF/src/com/studiofortress/sf/util/collections/CallbackIterator.java
SF/src/com/studiofortress/sf/util/collections/CallbackIterable.java
Diffs:
------
Index: SF/src/com/studiofortress/sf/graphics/GLTextureInner.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/GLTextureInner.java (revision 3)
+++ SF/src/com/studiofortress/sf/graphics/GLTextureInner.java (revision 4)
@@ -65,7 +65,7 @@
this.path = path;
this.isLoaded = false;
- GLTexture.getTextureManager().addInitializeTexture(this);
+ GLTexture.getTextureManager().addInitializeTexture( this );
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("The given path was not
found: " + path);
} catch (IOException e) {
Index: SF/src/com/studiofortress/sf/graphics/GraphicsGL.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/GraphicsGL.java (revision 3)
+++ SF/src/com/studiofortress/sf/graphics/GraphicsGL.java (revision 4)
@@ -215,9 +215,9 @@
{
texture.enable();
texture.bind();
- gl.glBegin(GL.GL_QUADS);
+ gl.glBegin( GL.GL_QUADS );
- if (centred) {
+ if ( centred ) {
x -= width/2;
y -= height/2;
}
@@ -310,7 +310,7 @@
* @param x The GL pipeline will be moved so this co-ordinate is it's
centre.
* @param rotation The pipeline will be rotated by this amount, in
degrees.
*/
- private void transform(final float x, final float y, float rotation)
+ protected void transform(final float x, final float y, float rotation)
{
// invert so it rotates clockwise
rotation = -rotation;
@@ -328,7 +328,7 @@
* Undo's the transformations from the last call to transform.
* This should not be called if there was no transform.
*/
- private void undoTransform()
+ protected void undoTransform()
{
gl.glRotatef(-undoTransformRotation, 0.0f, 0.0f, 1.0f);
gl.glTranslatef(-undoTransformX, -undoTransformY, 0.0f);
@@ -366,7 +366,7 @@
public void setColor(
final float red, final float green, final float blue)
{
- setColor(red, green, blue, 1);
+ setColor( red, green, blue, 1f );
}
public void setColor(
Index: SF/src/com/studiofortress/sf/graphics/display/GraphicsPanel.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/display/GraphicsPanel.java
(revision 3)
+++ SF/src/com/studiofortress/sf/graphics/display/GraphicsPanel.java
(revision 4)
@@ -1,5 +1,6 @@
package com.studiofortress.sf.graphics.display;
+import java.awt.Dimension;
import javax.swing.JPanel;
/**
@@ -25,5 +26,13 @@
public GraphicsPanel(int width, int height)
{
super(new JPanel(), width, height);
+
+ final JPanel innerComponent = getContainer();
+ final Dimension size = new Dimension( width, height );
+
+ innerComponent.setMinimumSize( size );
+ innerComponent.setMaximumSize( size );
+ innerComponent.setPreferredSize( size );
+ innerComponent.setSize( size );
}
}
\ No newline at end of file
Index: SF/src/com/studiofortress/sf/graphics/display/GraphicsWrapper.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/display/GraphicsWrapper.java
(revision 3)
+++ SF/src/com/studiofortress/sf/graphics/display/GraphicsWrapper.java
(revision 4)
@@ -39,7 +39,7 @@
this.innerComponent.add(canvas);
this.innerComponent.setIgnoreRepaint(true);
-
+
controls = createControls();
}
Index: SF/src/com/studiofortress/sf/graphics/display/Controls.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/display/Controls.java (revision 3)
+++ SF/src/com/studiofortress/sf/graphics/display/Controls.java (revision 4)
@@ -93,6 +93,15 @@
public boolean isKeyDown(String key);
/**
+ * Returns true if the given key has been pressed. The key should be a
+ * KeyEvent key code.
+ *
+ * @param keyCode The KeyEvent code for the key to check for.
+ * @return True if the key is pressed, otherwise false if not.
+ */
+ public boolean isKeyDown(int keyCode);
+
+ /**
* @return True if any key on the keyboard is currently pressed,
otherwise false.
*/
public boolean isAnyKeyDown();
Index: SF/src/com/studiofortress/sf/graphics/display/DisplayControls.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/display/DisplayControls.java
(revision 3)
+++ SF/src/com/studiofortress/sf/graphics/display/DisplayControls.java
(revision 4)
@@ -228,6 +228,12 @@
}
@Override
+ public boolean isKeyDown(int keyCode)
+ {
+ return isKeyDown( KeyEvent.getKeyText(keyCode) );
+ }
+
+ @Override
public boolean isAnyKeyDown()
{
return keys.size() > 0;
@@ -310,7 +316,7 @@
* Updates all of the controls stored to the most recently recorded
state.
* Typically this is called directly before or after the main loop.
*/
- void update()
+ synchronized void update()
{
mouseDown = ArrayUtil.copyOf( cachedMouseDown );
keys = (HashSet<String>) cachedKeys.clone();
Index: SF/src/com/studiofortress/sf/graphics/GraphicsCanvas.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/GraphicsCanvas.java (revision 3)
+++ SF/src/com/studiofortress/sf/graphics/GraphicsCanvas.java (revision 4)
@@ -46,7 +46,7 @@
GLTexture.getTextureManager().initializeTextures();
GLDisplayList.uninitializeDisplayLists(gl);
}
-
+
@Override
public void init(GLAutoDrawable drawable)
{
@@ -54,11 +54,11 @@
initializeGL(gl);
initializeQueues(gl);
}
-
+
@Override
public void display(GLAutoDrawable drawable)
{
- initializeQueues(drawable.getGL());
+ initializeQueues( drawable.getGL() );
}
@Override
Index: SF/src/com/studiofortress/sf/graphics/GLTextureManager.java
===================================================================
--- SF/src/com/studiofortress/sf/graphics/GLTextureManager.java (revision 3)
+++ SF/src/com/studiofortress/sf/graphics/GLTextureManager.java (revision 4)
@@ -99,6 +99,7 @@
{
assert(index > 0);
assert(index < textures.length);
+
return textures[index];
}
@@ -288,7 +289,7 @@
if (path == null) {
throw new IllegalArgumentException("The given path is null.");
}
- final Integer index = textureNames.get(path);
+ final Integer index = textureNames.remove( path );
if (index == null) {
throw new IllegalArgumentException("The given path was not
found: " + path);
}
Index:
SF/src/com/studiofortress/sf/structure/intersection/EllipseIntersection.java
===================================================================
---
SF/src/com/studiofortress/sf/structure/intersection/EllipseIntersection.java
(revision 3)
+++
SF/src/com/studiofortress/sf/structure/intersection/EllipseIntersection.java
(revision 4)
@@ -1,6 +1,7 @@
package com.studiofortress.sf.structure.intersection;
import com.studiofortress.sf.structure.Actor;
+import com.studiofortress.sf.util.Angle;
import java.awt.geom.Ellipse2D;
/**
@@ -98,12 +99,12 @@
return xDiff*xDiff + yDiff*yDiff <= hypot*hypot;
// it's somewhere in between and it's an ellipse, lets do some
expensive maths
} else {
- double angle = Math.atan2(yDiff, xDiff);
- double hypotSqr = xDiff*xDiff + yDiff*yDiff;
+ float angle = Angle.atan2(yDiff, xDiff);
+ float hypotSqr = xDiff*xDiff + yDiff*yDiff;
- double collideX = (thisHalfWidth +
otherHalfWidth)*Math.cos(angle);
- double collideY = (thisHalfHeight +
otherHalfHeight)*Math.sin(angle);
- double collideHypotSqr = collideX*collideX +
collideY*collideY;
+ float collideX = (thisHalfWidth +
otherHalfWidth)*Angle.cos(angle);
+ float collideY = (thisHalfHeight +
otherHalfHeight)*Angle.sin(angle);
+ float collideHypotSqr = collideX*collideX +
collideY*collideY;
return collideHypotSqr >= hypotSqr;
}
Index: SF/src/com/studiofortress/sf/structure/World.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/World.java (revision 3)
+++ SF/src/com/studiofortress/sf/structure/World.java (revision 4)
@@ -6,12 +6,12 @@
import com.studiofortress.sf.graphics.GraphicsGL;
import com.studiofortress.sf.structure.collisions.GridCollisions;
import com.studiofortress.sf.util.collections.CachingHashMap;
+import com.studiofortress.sf.util.collections.CallbackIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* The width and height of the World corresponds to the drawing area. It will
@@ -59,10 +59,29 @@
private float scrollX;
private float scrollY;
- private WorldControls controls;
+ private WorldControls<A> controls;
private MainLoop mainLoop;
+ // these are teh callbacks to use instead of iterators
+ private final CallbackIterator<A> removeCallback = new
CallbackIterator<A>() {
+ public void iterate(A actor)
+ {
+ removeActor( actor );
+ }
+ };
+
+ private final CallbackIterator<A> actActorsCallback = new
CallbackIterator<A>() {
+ public void iterate(final A actor)
+ {
+ if (actor.isAct() && !actor.isAwaitingRemoval()) {
+ actor.act();
+ }
+ }
+ };
+
+ private final PaintCallback paintActorsCallback = new PaintCallback();
+
/**
* Creates a new world which has the given width and height.
* By default the World is placed at width/2, height/2 to ensure it is
@@ -84,7 +103,7 @@
* @param x The location along the x axis of this world within it's
World.
* @param y The location along the y axis of this world within it's
World.
*/
- public World(int width, int height, int x, int y)
+ public World(final int width, final int height, final int x, final int y)
{
super(x, y, width, height);
@@ -113,10 +132,10 @@
* For getting the World specific controls object.
* @return A WorldControls associated with this World.
*/
- public WorldControls getControls()
+ public WorldControls<A> getControls()
{
if (controls == null) {
- controls = new WorldControlsInner(this);
+ controls = new WorldControlsInner<A>(this);
}
return controls;
}
@@ -130,7 +149,8 @@
public MainLoop getMainLoop()
{
if (mainLoop == null) {
- World superWorld = getWorld();
+ final World superWorld = getWorld();
+
if (superWorld != null) {
return superWorld.getMainLoop();
} else {
@@ -150,7 +170,7 @@
* moving a World between MainLoops.
* @param container The new MainLoop that this World is within.
*/
- void setMainLoop(MainLoop container)
+ void setMainLoop(final MainLoop container)
{
if (this.mainLoop != container) {
this.controls = null;
@@ -174,35 +194,38 @@
* are all removed from that handler and added to the new one.
* @param collisions A new collision handler for this World, cannot be
null.
*/
- public void setCollisions(CollisionHandler<A> collisions)
+ public void setCollisions(final CollisionHandler<A> collisions)
{
if (collisions == null) {
throw new IllegalArgumentException("Collisions cannot be null.");
}
- for (Collection<A> actorLayer : actActors.getActorLayers()) {
- for (A actor : actorLayer) {
- this.collisions.remove(actor);
- collisions.add(actor);
- }
- }
+ actActors.iterate(
+ new CallbackIterator<A>() {
+ public void iterate(final A actor)
+ {
+ World.this.collisions.remove( actor );
+ collisions.add( actor );
+ }
+ }
+ );
this.collisions = collisions;
}
-
+
/**
* Gets all Actors in this world.
* @return A list of all the contained Actors in this World.
*/
public List<A> getAllActors()
{
- List<A> returnActors = new ArrayList<A>( getActorCount() );
+ final List<A> returnActors = new ArrayList<A>( getActorCount() );
for (Collection<A> actors : actActors.getActorLayers()) {
- returnActors.addAll(actors);
+ returnActors.addAll( actors );
}
return returnActors;
}
-
+
/**
* The number of Actors in this world.
* @return The number of actors currently in the world itself.
@@ -230,12 +253,12 @@
{
for (Collection<A> actors : actActors.getActorLayers()) {
for (A actor : actors) {
- if (klass.isInstance(actor)) {
+ if ( klass.isInstance(actor) ) {
return (B) actor;
}
}
}
-
+
return null;
}
@@ -249,30 +272,35 @@
* @param filters The filters that the Actors must conform too, or null
to return all actors.
* @return A list of all the Actors that match the given filter.
*/
- public List<A> getActors(Filter<A> ... filters)
+ public List<A> getActors(final Filter<A> ... filters)
{
if (filters == null || filters.length == 0) {
return getAllActors();
} else {
- List<A> returnActors = new LinkedList<A>();
+ final List<A> returnActors = new LinkedList<A>();
+ final int filtersSize = filters.length;
- for (Collection<A> actors : actActors.getActorLayers()) {
- for (A actor : actors) {
- boolean match = true;
+ actActors.iterate(
+ new CallbackIterator<A>() {
+ public void iterate(final A actor)
+ {
+ boolean match = true;
+
+ for (int i = 0; i < filtersSize; ++i) {
+ final Filter filter = filters[i];
+ if (filter == null || !filter.accept(actor))
{
+ match = false;
+ break;
+ }
+ }
- for (Filter filter : filters) {
- if (filter == null || !filter.accept(actor)) {
- match = false;
- break;
+ if (match) {
+ returnActors.add(actor);
+ }
}
}
-
- if (match) {
- returnActors.add(actor);
- }
- }
- }
-
+ );
+
return returnActors;
}
}
@@ -283,19 +311,24 @@
* there are filters given which don't accept it.
* @param filters ActionFilters to perform to all the actors.
*/
- public void applyToActors(ActionFilter<A> ... filters)
+ public void applyToActors(final ActionFilter<A> ... filters)
{
+ final int filtersSize = filters.length;
+
if (filters != null && filters.length > 0) {
- for (Collection<A> actors : actActors.getActorLayers()) {
- for (A actor : actors) {
- for (int i = 0; i < filters.length; i++) {
- ActionFilter filter = filters[i];
- if (filter != null && filter.accept(actor)) {
- filter.action( actor );
+ actActors.iterate(
+ new CallbackIterator<A>() {
+ public void iterate(final A actor)
+ {
+ for (int i = 0; i < filtersSize; ++i) {
+ final ActionFilter filter = filters[i];
+ if ( filter != null && filter.accept(actor)
) {
+ filter.action( actor );
+ }
+ }
}
}
- }
- }
+ );
}
}
@@ -323,32 +356,37 @@
* @param klasses
* @return
*/
- public <B, C> List<B> getActors(Class<B> returnType, Class<C> ...
klasses)
+ public <B, C> List<B> getActors(final Class<B> returnType, final
Class<C> ... klasses)
{
if (returnType == null) {
throw new IllegalArgumentException("The returnType cannot be
null.");
}
-
- List<B> returnActors = new LinkedList<B>();
-
- for (Collection<A> actors : actActors.getActorLayers()) {
- for (A actor : actors) {
- if (returnType.isInstance(actor)) {
- boolean match = true;
-
- for (Class<C> klass : klasses) {
- if (!klass.isInstance(actor)) {
- match = false;
- break;
+
+ final int klassesSize = klasses.length;
+ final List<B> returnActors = new LinkedList<B>();
+
+ actActors.iterate(
+ new CallbackIterator<A>() {
+ public void iterate(A actor)
+ {
+ if ( returnType.isInstance(actor) ) {
+ boolean match = true;
+
+ for (int i = 0; i < klassesSize; ++i) {
+ final Class<C> klass = klasses[i];
+ if ( !klass.isInstance(actor) ) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match) {
+ returnActors.add( (B) actor );
+ }
}
}
-
- if (match) {
- returnActors.add((B) actor);
- }
}
- }
- }
+ );
return returnActors;
}
@@ -363,6 +401,18 @@
{
return collisions;
}
+
+ /**
+ * Adds the actor and sets it's paint order. This is essentially a helper
+ * function for doing this yourself.
+ * @param actor The actor to add to this world, cannot be null.
+ * @param paintOrder The paint order for the actor being painted.
+ */
+ public void addActor(A actor, int paintOrder)
+ {
+ addActor( actor );
+ setPaintOrder( actor, paintOrder );
+ }
/**
* This is a helper method that is the equivalent of calling
addActor(actor)
@@ -465,11 +515,7 @@
*/
public void removeAllActors()
{
- for (Collection<A> actors : actActors.getActorLayers()) {
- for (A actor : actors) {
- removeActor(actor);
- }
- }
+ actActors.iterate( removeCallback );
}
/**
@@ -587,7 +633,7 @@
* @param moveScrollX The amount to scroll in the X direction.
* @param moveScrollY The amount to scroll in the Y direction.
*/
- public void scroll(float moveScrollX, float moveScrollY)
+ public void scroll(final float moveScrollX, final float moveScrollY)
{
setScroll(getScrollX() + moveScrollX, getScrollY() + moveScrollY);
}
@@ -598,10 +644,10 @@
* @param scrollX The new amount that this is scrolled along the X axis.
* @param scrollY The new amount that this is scrolled along the Y axis.
*/
- public void setScroll(float scrollX, float scrollY)
+ public void setScroll(final float scrollX, final float scrollY)
{
- setScrollX(scrollX);
- setScrollY(scrollY);
+ setScrollX( scrollX );
+ setScrollY( scrollY );
}
/**
@@ -617,7 +663,7 @@
* Sets the amount to scroll this World by, along the X-axis, when it is
drawn.
* @param scrollX The new amount that this is scrolled along the X axis.
*/
- public void setScrollX(float scrollX)
+ public void setScrollX(final float scrollX)
{
this.scrollX = scrollX;
}
@@ -636,7 +682,7 @@
* Sets how far to scroll this World by along the Y-axis, when painting.
* @param scrollY The new amount that this is scrolled along the Y axis.
*/
- public void setScrollY(float scrollY)
+ public void setScrollY(final float scrollY)
{
this.scrollY = scrollY;
}
@@ -650,7 +696,7 @@
{
actActors();
}
-
+
/**
* Updates all of the Actors currently in this world by calling their
* act method. This is performed in the order of their actLayer value.
@@ -658,15 +704,7 @@
public void actActors()
{
addRemoveActors();
-
- for (Set<A> actors : actActors.getActorLayers()) {
- for (A actor : actors) {
- if (actor.isAct() && !actor.isAwaitingRemoval()) {
- actor.act();
- }
- }
- }
-
+ actActors.iterate( actActorsCallback );
addRemoveActors();
}
@@ -678,18 +716,11 @@
public void paintActors(G g)
{
addRemoveActors();
- for (Set<A> actors : paintActors.getActorLayers()) {
- for (A actor : actors) {
- if (!actor.isAwaitingRemoval()) {
- // needs to be set for each actor incase it removes it
-// g.setClip(0, 0, getWidth(), getHeight());
- actor.realPaint(g);
- }
- }
- }
+ paintActorsCallback.g = g;
+ paintActors.iterate( paintActorsCallback );
addRemoveActors();
}
-
+
/**
* This updates the internal list of actors, performing all the cached
add
* and removal of them. It's normally called automatically in the
actActors
@@ -700,24 +731,24 @@
{
// swap the temp and current lists
if (addRemoveActors.size() > 0) {
- List<A> temp = tempAddRemoveActors;
+ final List<A> temp = tempAddRemoveActors;
tempAddRemoveActors = addRemoveActors;
addRemoveActors = temp;
-
+
// swap the temp and current stack
- BooleanStack tempStack = tempAddRemoveActorsIsAdd;
+ final BooleanStack tempStack = tempAddRemoveActorsIsAdd;
tempAddRemoveActorsIsAdd = addRemoveActorsIsAdd;
addRemoveActorsIsAdd = tempStack;
-
+
for (int i = 0; i < tempAddRemoveActors.size(); i++) {
- A actor = tempAddRemoveActors.get(i);
- if (tempAddRemoveActorsIsAdd.peek(i)) {
- addActorInner(actor);
+ final A actor = tempAddRemoveActors.get(i);
+ if ( tempAddRemoveActorsIsAdd.peek(i) ) {
+ addActorInner( actor );
} else {
removeActorInner(actor);
}
}
-
+
// cleared for when we swap them on the next iteration
// also to ensure we don't hang onto Actor references when we
don't need to
tempAddRemoveActors.clear();
@@ -731,15 +762,15 @@
* @param g The GraphcsGL object to paint too.
*/
@Override
- void realPaint(G g)
+ void realPaint(final G g)
{
if (isPaintEnabled()) {
- float topLeftX = (getX() - getWidth()/2);
- float topLeftY = (getY() - getHeight()/2);
+ final float topLeftX = (getX() - getWidth()/2) - getScrollX();
+ final float topLeftY = (getY() - getHeight()/2) - getScrollY();
- g.translate(topLeftX, topLeftY);
- paint(g);
- g.translate(-topLeftX, -topLeftY);
+ g.translate( topLeftX , topLeftY );
+ paint( g );
+ g.translate( -topLeftX, -topLeftY );
}
}
@@ -751,7 +782,7 @@
* @param g The Graphics2D to paint this World too.
*/
@Override
- public void paint(G g)
+ public void paint(final G g)
{
paintActors( g );
}
@@ -806,4 +837,21 @@
{
return collisions.applyToIntersectingActor( actor, action,
collisionKlasses );
}
+
+ /**
+ * The PaintCallback class is the callback iterator for when painting all
+ * of the actors in the paintActors class.
+ */
+ private class PaintCallback implements CallbackIterator<A> {
+ private G g;
+
+ public void iterate(final A actor)
+ {
+ if (!actor.isAwaitingRemoval()) {
+ // needs to be set for each actor incase it removes it
+// g.setClip(0, 0, getWidth(), getHeight());
+ actor.realPaint( g );
+ }
+ }
+ };
}
Index: SF/src/com/studiofortress/sf/structure/WorldControlsInner.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/WorldControlsInner.java
(revision 3)
+++ SF/src/com/studiofortress/sf/structure/WorldControlsInner.java
(revision 4)
@@ -1,6 +1,7 @@
package com.studiofortress.sf.structure;
+import com.studiofortress.sf.graphics.GraphicsGL;
import com.studiofortress.sf.graphics.display.Controls;
import com.studiofortress.sf.graphics.display.GraphicsDisplay;
import com.studiofortress.sf.util.SmallPoint;
@@ -10,7 +11,7 @@
*
* @author Joseph Lenton
*/
-class WorldControlsInner implements WorldControls
+final class WorldControlsInner<A extends Actor<? extends GraphicsGL>>
implements WorldControls
{
private final World world;
private Controls controls;
@@ -52,9 +53,9 @@
// go through each world above getWorld() (including the getWorld
world)
// and add all the total offsets up.
- for (World wrld = getWorld(); wrld != null; wrld = wrld.getWorld()) {
- offsetX += wrld.getX() - wrld.getWidth()/2;
- offsetY += wrld.getY() - wrld.getHeight()/2;
+ for (World world = getWorld(); world != null; world =
world.getWorld()) {
+ offsetX += world.getX() - world.getWidth()/2 -
world.getScrollX();
+ offsetY += world.getY() - world.getHeight()/2 -
world.getScrollY();
}
return new SmallPoint(offsetX, offsetY);
@@ -123,8 +124,33 @@
}
@Override
+ public boolean isKeyDown(int keyCode)
+ {
+ return getControls().isKeyDown( keyCode );
+ }
+
+ @Override
public boolean isAnyKeyDown()
{
return getControls().isAnyKeyDown();
}
+
+ public boolean isActorClicked(Actor actor, int mouseButton)
+ {
+ if ( isMouseDown(mouseButton) ) {
+ final float mx = getWorldMouseX();
+ final float my = getWorldMouseY();
+
+ final float x = actor.getX();
+ final float y = actor.getY();
+
+ final int w = actor.getWidth()/2;
+ final int h = actor.getHeight()/2;
+
+ return ( (x-w) <= mx && mx <= (x+w) ) &&
+ ( (y-h) <= my && my <= (y+h) );
+ } else {
+ return false;
+ }
+ }
}
Index: SF/src/com/studiofortress/sf/structure/WorldControls.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/WorldControls.java (revision 3)
+++ SF/src/com/studiofortress/sf/structure/WorldControls.java (revision 4)
@@ -1,6 +1,7 @@
package com.studiofortress.sf.structure;
+import com.studiofortress.sf.graphics.GraphicsGL;
import com.studiofortress.sf.graphics.display.Controls;
/**
@@ -19,7 +20,7 @@
*
* @author Joseph Lenton
*/
-public interface WorldControls extends Controls
+public interface WorldControls<A extends Actor<? extends GraphicsGL>>
extends Controls
{
/**
* @return The World object this WorldControls is for.
@@ -37,4 +38,13 @@
* @return The location of the mouse inside of this world.
*/
public abstract int getWorldMouseY();
+
+ /**
+ * Checks if the curremt position of the mouse in the World this controls
+ * comes from is within the given Actor's bounds. The result is returned.
+ * @param actor The Actor to check, cannot be null.
+ * @param mouseButton The button to check for. i.e. Controls.LEFT_MOUSE
or Controls.RIGHT_MOUSE.
+ * @return True if the mouse pointer is currently over the actor given,
otherwise false.
+ */
+ public abstract boolean isActorClicked( A actor, int mouseButton );
}
Index: SF/src/com/studiofortress/sf/structure/SortedActors.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/SortedActors.java (revision 3)
+++ SF/src/com/studiofortress/sf/structure/SortedActors.java (revision 4)
@@ -2,6 +2,9 @@
package com.studiofortress.sf.structure;
import com.studiofortress.sf.util.collections.CachingHashSet;
+import com.studiofortress.sf.util.collections.CallbackIterable;
+import com.studiofortress.sf.util.collections.CallbackIterator;
+import com.studiofortress.sf.util.collections.CallbackPartialIterator;
import java.util.Collection;
import java.util.Set;
import java.util.SortedMap;
@@ -13,34 +16,67 @@
*
* @author Joseph Lenton
*/
-class SortedActors<A extends Actor>
+class SortedActors<A extends Actor> implements CallbackIterable<A>
{
- private SortedMap<Integer, Set<A>> actors;
+ private final SortedMap<Integer, CachingHashSet<A>> actors;
/**
* Trivial constructor.
*/
SortedActors()
{
- actors = new TreeMap<Integer, Set<A>>();
+ actors = new TreeMap<Integer, CachingHashSet<A>>();
}
/**
+ * Iterates over all of the actors in this SortedActors in order, from
the
+ * actors at the bottom to those at the top.
+ * @param callback The callback object to use for iterating, cannot be
null.
+ */
+ public void iterate(final CallbackIterator<A> callback)
+ {
+ if ( callback == null ) {
+ throw new IllegalArgumentException("The given callback cannot be
null.");
+ }
+
+ for ( CachingHashSet<A> set : actors.values() ) {
+ set.iterate( callback );
+ }
+ }
+
+ public void iteratePartial(final CallbackPartialIterator<A> callback)
+ {
+ if ( callback == null ) {
+ throw new IllegalArgumentException("The given callback cannot be
null.");
+ }
+
+ callback.startIteration();
+ for ( CachingHashSet<A> set : actors.values() ) {
+ if ( callback.isIterating() ) {
+ set.iteratePartial( callback );
+ } else {
+ return;
+ }
+ }
+ }
+
+ /**
* Adds this Actor to be stored at the given orderNum position.
* If the Actor is already stored at a different orderNum then it will be
* added twice.
* @param actor The Actor to store.
* @param orderNum The order which the Actor is stored at.
*/
- void add(A actor, int orderNum)
+ void add(final A actor, final int orderNum)
{
- Set<A> actorSet = actors.get(orderNum);
+ CachingHashSet<A> actorSet = actors.get( orderNum );
+
if (actorSet == null) {
actorSet = new CachingHashSet<A>();
- actors.put(orderNum, actorSet);
+ actors.put( orderNum, actorSet );
}
- actorSet.add(actor);
+ actorSet.add( actor );
}
/**
@@ -50,12 +86,14 @@
* @param orderNum Where to try to remove it from.
* @return True if the Actor was found and removed, otherwise false.
*/
- boolean remove(A actor, int orderNum)
+ boolean remove(final A actor, final int orderNum)
{
- Set<A> actorSet = actors.get(orderNum);
- if (actorSet != null) {
- return actorSet.remove(actor);
+ final Set<A> actorSet = actors.get( orderNum );
+
+ if ( actorSet != null ) {
+ return actorSet.remove( actor );
}
+
return false;
}
@@ -70,7 +108,7 @@
/**
* @return A collection containing each layer of actors in the order
they are stored in this collection.
*/
- Collection<Set<A>> getActorLayers()
+ Collection<CachingHashSet<A>> getActorLayers()
{
return actors.values();
}
Index: SF/src/com/studiofortress/sf/structure/MainLoop.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/MainLoop.java (revision 3)
+++ SF/src/com/studiofortress/sf/structure/MainLoop.java (revision 4)
@@ -184,7 +184,7 @@
World currentWorld = getWorld();
if (currentWorld != null) {
// If we are still painting the previous frame, we wait till
it's done.
- while (painter.isPainting()) {
+ while ( painter.isPainting() ) {
Thread.yield();
}
@@ -312,6 +312,8 @@
private World world;
+ private GraphicsGL graphics;
+
/**
* Sets a World to be painted. This is automatically done on the next
* time that the display method is called.
@@ -341,9 +343,10 @@
@Override
public void init(GLAutoDrawable drawable)
{
- GL g = drawable.getGL();
- g.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- g.glShadeModel(GL.GL_FLAT);
+ GL gl = drawable.getGL();
+ gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.glShadeModel(GL.GL_FLAT);
+ graphics = createGraphics( gl );
}
@Override
@@ -358,15 +361,14 @@
gl.glLoadIdentity();
// paint the current world
- final GraphicsGL draw = createGraphics( gl );
- world.realPaint(draw);
+ world.realPaint( graphics );
/* This must be done _before_ we call flush, cos from this
point
* on it doesn't matter if we start updating logic. However
* flush will take a while if we are waiting on the vsync. */
world = null;
// done drawing
- draw.flush();
+ graphics.flush();
flipWait = false;
}
}
Index: SF/src/com/studiofortress/sf/structure/collisions/GridCollisions.java
===================================================================
--- SF/src/com/studiofortress/sf/structure/collisions/GridCollisions.java
(revision 3)
+++ SF/src/com/studiofortress/sf/structure/collisions/GridCollisions.java
(revision 4)
@@ -5,7 +5,9 @@
import com.studiofortress.sf.structure.Actor;
import com.studiofortress.sf.util.collections.CachingHashMap;
import com.studiofortress.sf.util.collections.CachingHashSet;
+import com.studiofortress.sf.util.collections.CallbackIterator;
import com.studiofortress.sf.util.collections.ClassInheritenceMap;
+import com.studiofortress.sf.util.collections.ObjectStack;
import com.studiofortress.sf.util.collections.Resizable2DArray;
import java.util.ArrayList;
import java.util.HashSet;
@@ -29,16 +31,18 @@
* this can dramatically reduce object creation, which dramatically improves
* garbage collection pause times.
*
- * Points are represented by a 2 elements int array where the index at 0 is X
- * and the index at 1 is always Y. When you see 'point[0], point[1]' it means
- * 'x, y'.
+ * Rectangles are represented by 4 elements in an int array where
+ * arr[0] = minX
+ * arr[1] = maxX
+ * arr[2] = minY
+ * arr[3] = maxY
+ * These positions are inclusive.
*/
public class GridCollisions<A extends Actor> implements CollisionHandler<A>
{
// all collission points are cached so they can be used by multiple
actors
- private static final Resizable2DArray<int[]> POINTS =
- new Resizable2DArray<int[]>();
-
+ private static final ObjectStack<int[]> ARRAYS = new
ObjectStack<int[]>();
+
/**
* This will return a int[] that represents the given X and Y
* location. This point may or may not be a new point.
@@ -46,14 +50,20 @@
* @param y The y-location of the point.
* @return A int[] that represents the given location.
*/
- private static int[] getPoint(int x, int y)
+ private static final int[] newRectangle(final int minX, final int maxX,
final int minY, final int maxY)
{
- int[] point = POINTS.get(x, y);
- if (point == null) {
- point = new int[] {x, y};
- POINTS.set(x, y, point);
+ if ( ARRAYS.size() > 0 ) {
+ final int[] arr = ARRAYS.pop();
+
+ arr[0] = minX;
+ arr[1] = maxX;
+ arr[2] = minY;
+ arr[3] = maxY;
+
+ return arr;
+ } else {
+ return new int[] { minX, maxX, minY, maxY };
}
- return point;
}
private static final int DEFAULT_SIZE = 100;
@@ -61,15 +71,30 @@
// the width and height of each cell in the grid
private final int gridWidth;
private final int gridHeight;
+
+ /* This contains a list of all of the actors in each location in the
grid. */
+ private final ClassInheritenceMap<A,
Resizable2DArray<CachingHashSet<A>>> grid;
+
+ /* This map of actors to a rectangle describing them is needed because it
+ * matches the locations we know about in the grid.
+ * If an actor changes size or location then we can use this data to work
+ * out which parts of the grid they are no longer in, and should be
removed
+ * from. */
+ private final CachingHashMap<A, int[]> actorGridPoints;
- private final ClassInheritenceMap<A, Resizable2DArray<Set<A>>> grid;
- private final CachingHashMap<A, int[][]> actorGridPoints;
-
// Actors are cached in this set before being updated.
// This allows them to be updated multiple times but their grid points
are
// only calculated when an intersection occurres.
- private final Set<A> lazyUpdateActors;
+
+ private final IntersectingActorsAction getIntersectingActorsAction =
+ new IntersectingActorsAction();
+
+ private final CachingHashSet<A> lazyUpdateActors;
+ private final CollisionCallback collisionCallback = new
CollisionCallback();
+ private final UpdateCallback updateCallback = new
UpdateCallback();
+ private final GridCallback gridCallback = new GridCallback();
+
/**
* Creates a new CollisionGrid with the default grid width and height of
100.
*/
@@ -104,8 +129,8 @@
this.gridWidth = gridWidth;
this.gridHeight = gridHeight;
- grid = new ClassInheritenceMap<A, Resizable2DArray<Set<A>>>();
- actorGridPoints = new CachingHashMap<A, int[][]>();
+ grid = new ClassInheritenceMap<A,
Resizable2DArray<CachingHashSet<A>>>();
+ actorGridPoints = new CachingHashMap<A, int[]>();
lazyUpdateActors = new CachingHashSet<A>();
}
@@ -136,84 +161,40 @@
if (actor == null) {
throw new IllegalArgumentException("The given actor cannot be
null.");
}
-
- final int[][] points = calculatePoints(actor);
- final Class<? extends A> actorClass = (Class<? extends A>)
actor.getClass();
-
- // add actor to the grid
- for (int i = 0; i < points.length; i++) {
- final int[] point = points[i];
- final int x = point[0];
- final int y = point[1];
- Resizable2DArray<Set<A>> classGrid = grid.get((Class<? extends
A>) actorClass);
- Set<A> actors;
- if (classGrid == null) {
- classGrid = new Resizable2DArray<Set<A>>();
- actors = new CachingHashSet<A>();
-
- classGrid.set( x, y, actors );
- grid.put((Class<? extends A>) actorClass, classGrid);
- } else {
- actors = classGrid.get( x, y );
- if (actors == null) {
- actors = new CachingHashSet<A>();
- classGrid.set( x, y, actors );
- }
- }
-
- actors.add(actor);
- }
-
- // store the points associated with the actor
- actorGridPoints.put(actor, points);
- }
-
- /**
- * Retrieves a list of grid points for the given Actor. It is not
guaranteed
- * that the returned points are also stored in this CollisionGrid.
- * @param actor The Actor to find points for, cannot be null.
- * @return A list of Points for all the grid spaces the given Actor is
contained within.
- */
- private int[][] getPoints(final A actor)
- {
- assert(actor != null);
- final int[][] points = actorGridPoints.get( actor );
- if (points == null) {
- return calculatePoints(actor);
- }
- return points;
- }
-
- /**
- * Calculates all the grid squares for the given Actor and returns the
- * location of those cells as a list of Points.
- * @param actor The Actor to find all the grid cells it is within.
- * @return A list of Points which the Actor resides within.
- */
- private int[][] calculatePoints(final A actor)
- {
- assert(actor != null);
-
final int halfWidth = actor.getWidth()/2;
final int minX = (int)Math.floor((actor.getX() - halfWidth) /
(float)gridWidth);
final int maxX = (int)Math.ceil( (actor.getX() + halfWidth) /
(float)gridWidth);
-
+
final int halfHeight = actor.getHeight()/2;
final int minY = (int)Math.floor((actor.getY() - halfHeight) /
(float)gridHeight);
final int maxY = (int)Math.ceil( (actor.getY() + halfHeight) /
(float)gridHeight);
+ final Class<? extends A> actorClass = (Class<? extends A>)
actor.getClass();
- final int numPoints = ((maxX-minX)+1) * ((maxY-minY)+1);
- final int[][] points = new int[numPoints][];
+ // add actor to the grid
+ for (int x = minX; x <= maxX; ++x) {
+ for (int y = minY; y <= maxY; ++y) {
+ Resizable2DArray<CachingHashSet<A>> classGrid =
grid.get((Class<? extends A>) actorClass);
+ CachingHashSet<A> actors;
+ if (classGrid == null) {
+ classGrid = new Resizable2DArray<CachingHashSet<A>>();
+ actors = new CachingHashSet<A>();
- int index = 0;
- for (int x = minX; x <= maxX; x++) {
- for (int y = minY; y <= maxY; y++) {
- points[index++] = getPoint(x, y);
+ classGrid.set( x, y, actors );
+ grid.put((Class<? extends A>) actorClass, classGrid);
+ } else {
+ actors = classGrid.get( x, y );
+ if (actors == null) {
+ actors = new CachingHashSet<A>();
+ classGrid.set( x, y, actors );
+ }
+ }
+
+ actors.add( actor );
}
}
-
- return points;
+
+ actorGridPoints.put( actor, newRectangle(minX, maxX, minY, maxY) );
}
/**
@@ -223,18 +204,34 @@
@Override
public void remove(final A actor)
{
- final Resizable2DArray<Set<A>> actorGrid = grid.get((Class<? extends
A>) actor.getClass());
+ lazyUpdateActors.remove( actor );
+ final int[] points = actorGridPoints.remove( actor );
+ ARRAYS.push( points );
+
+ final Resizable2DArray<CachingHashSet<A>> actorGrid =
grid.get((Class<? extends A>) actor.getClass());
// you should presume that if the Actor has actorGridPoints then it
is
// also in the actorGrid, so no checks are needed
- final int[][] points = actorGridPoints.remove(actor);
- for (int i = 0; i < points.length; i++) {
- final int[] point = points[i];
- actorGrid.get( point[0], point[1] ).remove(actor);
+
+ final int minX = points[0];
+ final int maxX = points[1];
+ final int minY = points[2];
+ final int maxY = points[3];
+
+// final int halfWidth = actor.getWidth()/2;
+// final int minX = (int)Math.floor((actor.getX() - halfWidth) /
(float)gridWidth);
+// final int maxX = (int)Math.ceil( (actor.getX() + halfWidth) /
(float)gridWidth);
+//
+// final int halfHeight = actor.getHeight()/2;
+// final int minY = (int)Math.floor((actor.getY() - halfHeight) /
(float)gridHeight);
+// final int maxY = (int)Math.ceil( (actor.getY() + halfHeight) /
(float)gridHeight);
+
+ for (int x = minX; x <= maxX; x++) {
+ for (int y = minY; y <= maxY; y++) {
+ actorGrid.get( x, y ).remove( actor );
+ }
}
-
- lazyUpdateActors.remove( actor );
}
-
+
/**
* Updates the given actors details in the grid collissions. It should
* already have been added to this CollisionHandler.
@@ -257,37 +254,7 @@
*/
private void lazyUpdate()
{
- for (final A actor : lazyUpdateActors) {
- final int[][] points = actorGridPoints.remove(actor);
- final int[][] newPoints = calculatePoints(actor);
-
- // if we got a new array of points back
- final Resizable2DArray<Set<A>> classGrid = grid.get((Class<?
extends A>) actor.getClass());
-
- for (int i = 0; i < points.length; i++) {
- final int[] point = points[i];
- final Set<A> actors = classGrid.get( point[0], point[1] );
-
- assert(actor != null);
-
- actors.remove(actor);
- }
-
- for (int i = 0; i < newPoints.length; i++) {
- final int[] point = newPoints[i];
- Set<A> actors = classGrid.get( point[0], point[1] );
-
- if (actors == null) {
- actors = new CachingHashSet<A>();
- classGrid.set( point[0], point[1], actors);
- }
-
- actors.add(actor);
- }
-
- actorGridPoints.put(actor, newPoints);
- }
-
+ lazyUpdateActors.iterate( updateCallback );
lazyUpdateActors.clear();
}
@@ -306,42 +273,11 @@
throw new IllegalArgumentException("The given actor cannot be
null.");
}
- lazyUpdate();
-
- // this needs to be a set so that there are no duplicates in the
returned list
- final Set<A> intersections = new HashSet<A>();
- final int[][] actorPoints = getPoints(actor);
- final int collisionClassesSize = collisionClasses.length;
-
- for (int i = 0; i < collisionClassesSize; ++i) {
- final Class<? extends A> collisionClass = collisionClasses[i];
- final ArrayList<Resizable2DArray<Set<A>>> classPointsList =
grid.getSubKeys( collisionClass );
- final int classPointsListSize = classPointsList.size();
-
- for (int j = 0; j < classPointsListSize; ++j) {
- final Resizable2DArray<Set<A>> classPoints =
classPointsList.get(j);
-
- if (classPoints != null) {
- for (int k = 0; k < actorPoints.length; k++) {
- final int[] gridPoint = actorPoints[k];
- final Set<A> otherActorPoints = classPoints.get(
gridPoint[0], gridPoint[1] );
-
- if (otherActorPoints != null) {
- for (final A otherActor : otherActorPoints) {
- // the actor v actor specific check
- if (actor != otherActor &&
actor.intersects(otherActor)) {
- intersections.add(otherActor);
- }
- }
- }
- }
- }
- }
- }
-
- return intersections;
+ applyToIntersectingActors(
+ actor, getIntersectingActorsAction.initialize(),
collisionClasses );
+ return getIntersectingActorsAction.intersections;
}
-
+
/**
* Essentially the same as getIntersectingActors, only this returns the
* first actor found. If there are multiple actors that intersect the
given
@@ -359,27 +295,35 @@
lazyUpdate();
- final int[][] actorPoints = getPoints(actor);
+ final int halfWidth = actor.getWidth()/2;
+ final int minX = (int)Math.floor((actor.getX() - halfWidth) /
(float)gridWidth);
+ final int maxX = (int)Math.ceil( (actor.getX() + halfWidth) /
(float)gridWidth);
+
+ final int halfHeight = actor.getHeight()/2;
+ final int minY = (int)Math.floor((actor.getY() - halfHeight) /
(float)gridHeight);
+ final int maxY = (int)Math.ceil( (actor.getY() + halfHeight) /
(float)gridHeight);
+
final int collisionClassesSize = collisionClasses.length;
-
+
for (int i = 0; i < collisionClassesSize; ++i) {
final Class<? extends A> collisionClass = collisionClasses[i];
- final ArrayList<Resizable2DArray<Set<A>>> classPointsList =
grid.getSubKeys( collisionClass );
+ final ArrayList<Resizable2DArray<CachingHashSet<A>>>
classPointsList = grid.getSubKeys( collisionClass );
final int classPointsListSize = classPointsList.size();
for (int j = 0; j < classPointsListSize; ++j) {
- final Resizable2DArray<Set<A>> classPoints =
classPointsList.get(j);
+ final Resizable2DArray<CachingHash
[truncated due to length]
|
[sf-library~sf:4] Added callback iterators, minor API aditions, bug fixes and performance i |
StudioFortress | 01/28/2010 |





