- Create a Position component.
- Create an ImageRenderable component with corresponding ImageRenderSystem.
import org.newdawn.slick.Image;
public class ImageRenderable implements Component {
private Image image;
public Image image() {
return image;
}
public ImageRenderable image(Image image) {
this.image = image;
return this;
}
}
Easy enough, as long as you don't mind my Smalltalk-esque style — using the same method name for both an accessor and mutator, and returning this from the mutator.
This conceptually-simple unit test just checks that if we set an image, that the property accessor returns that image:
@Test
public void testImageAccessorAndMutator() {
final String RESOURCE_LOC = "images/white-1x1.png";
try {
new AppGameContainer(new BasicGame("Test") {
@Override
public void render(GameContainer container, Graphics g)
throws SlickException {
final Image image = new Image(RESOURCE_LOC);
ImageRenderable ir = new ImageRenderable().image(image);
assertEquals(image, ir.image());
container.exit();
}
@Override
public void update(GameContainer container, int delta)
throws SlickException {
}
@Override
public void init(GameContainer container) throws SlickException {
}
}).start();
} catch (SlickException e) {
fail("Failed to create game: " + e);
}
}
Here's a breakdown:
- The game needs a container in order to run, so we create an AppGameContainer.
This is the class used when launching games as applications, in contrast with
AppletGameContainer.
- The inner class overrides the three methods required, but only render is interesting to this test, so it's the only one that matters.
- The
imagevariable references the actual Slick image object, which is then referenced byir. We don't actually need anyEntityobjects here: we're just testing the component.
assertEqualsensures that the image we put into the component is the one we get out.
- After the test, we call the container's
exitmethod to gracefully shut down Slick.
- The start() call on the game container actually starts the test game.
Unit tests for accessors and mutators are nigh unnecessary, but this set-up allows us to do something more interesting with the system that processes these components. Here's a simple implementation of ImageRenderSystem, which assumes that its Entity arguments have both Position and ImageRenderable components.
import java.util.List;
import org.newdawn.slick.Graphics;
public class ImageRenderSystem {
public void render(Graphics g, List entities) {
for (Entity e : entities)
render(g, e);
}
public void render(Graphics g, Entity e) {
Position p = e.as(Position.class);
ImageRenderable i = e.as(ImageRenderable.class);
g.drawImage(i.image(), p.x(), p.y());
}
}
Simple. Here's the corresponding unit test (which was written first, natch).
@Test
public void testImageRendering() throws Exception {
new AppGameContainer(new BasicGame("Test") {
private Entity e;
@Override
public void render(GameContainer container, Graphics g)
throws SlickException {
ImageRenderSystem sys = new ImageRenderSystem();
sys.render(g, e);
assertEquals(Color.white, g.getPixel(0, 0));
container.exit();
}
@Override
public void update(GameContainer container, int delta)
throws SlickException {
}
@Override
public void init(GameContainer container) throws SlickException {
BasicEntityManager mgr = new BasicEntityManager();
e = mgr.createEntity();
e.add(new Position().x(0).y(0));
e.add(new ImageRenderable().image(new Image(
"assets/white-1x1.png")));
}
}).start();
}
This has the same structure as the previous one. I am using the init method to set up the test. Technically, this could be done in render as in the previous example, but it seems that init is a good place to do initialization. The render method calls out to the ImageRenderSystem render method, and then we check that the pixel in the upper-left corner is indeed a white one. To finish the test, we should check that the rest are black, but that's left as an exercise for the reader.
This shows how to set up rendering-related unit tests in Slick. The real moral of the story, though, is: make sure you know what you're doing before you show up in class. This was supposed to take about fifteen minutes, and it took me over an hour to puzzle through all the parts. It's always easier the second time.
Thanks to David Craft for the post explaining how to set up SyntaxHighlighter in blogger.
No comments:
Post a Comment