Sunday, October 10, 2010

More animation

The previous entry demonstrated an easy way to animate a sprite in JA2DAPI by extending a Sprite2D class and overriding the updateState() method. This approach is a great way to bind animation to a sprite: by encapsulating the sprite behavior in a single class. In  some cases, however, a more global approach might be more useful. For these cases, we can have our primary class implement the Paintable interface and override it's methods update() and paintObject(). For this example, we only need to add code to the update() override. If you read the previous blog entry, this code should seem a bit familiar:

import java.awt.Graphics;
import twodapi.core.*;

public class AnimationTest implements Paintable
{
    private Sprite2D ship = null;

    public AnimationTest()
    {
        Frame2D gameFrame = new Frame2D(Frame2D.REG_PAINTER,1024,768,false);
        GamePainter painter = (GamePainter)gameFrame.getPainter();

        ship = new Sprite2D("/images/ship.gif");
        ship.setLocation(500,400);
        painter.addToPaintList(ship);

        painter.addToPaintList(this);
    }

    public void update(float interpolation)
    {
        ship.rotate(Math.PI/16);
    }
    public void paintObject(Graphics g){}

    public static void main(String[] args)
    {
        new AnimationTest();
    }

}

So, here, instead of doing everything in main(), most of the action is in the constructor. We create a frame and a ship sprite and move the ship to the center. Now, since the AnimationTest class has implemented Paintable, we can add it (this) to the paint list. As a result, we can do game state updates in this class's update() method, as long as the ship was declared as a class member like above.

The final way to do animation is using anonymous class method overrides. If you're a Java veteran, I'm sure you can pull this off without an example. If you're not, there's probably no need to worry about it. Anonymous class code is not often the cleanest, anyways, and you have two simpler methods described above.

Animation With Keyboard Input

Okay, so this blog is boring me, so I'll add a little more beyond a simple animation example: I'll show you how to rotate the ship with keyboard input.

Using JA2DAPI, getting keyboard input is simple. We just need to create a KeyControls instance and register the desired input keys using set():

        KeyControls keyControls = new KeyControls(painter.getComponent());
        keyControls.set(KeyEvent.VK_LEFT);
        keyControls.set(KeyEvent.VK_RIGHT);


So, here we made a KeyControls and told it we want to listen for left and right arrow key presses (Notice that KeyControls uses the java.awt.event.KeyEvent constants. I'm working on moving away from that in the future so that JA2API can have its own constants). Then, we just need to check for these keys being pressed in the update() override:

    public void update(float interpolation)
    {
        if (keyControls.isPressed(KeyEvent.VK_LEFT)) ship.rotate(-Math.PI/16);
        else if (keyControls.isPressed(KeyEvent.VK_RIGHT)) ship.rotate(Math.PI/16);
    }


This code makes it so holding down the left arrow key will rotate the ship counter-clockwise and holding down the right arrow will rotate it clockwise. Note that isPressed() is not exhaustive. So, if a key is held down, isPressed() will continuously be true on all update() calls until the key is no longer pressed. isTapped() is an exhaustive alternative that is only called once per key press. This method is more appropriate for things such as firing a gun or making a character jump.

Here's the whole .java source for this example:

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import twodapi.core.*;

public class AnimationTest implements Paintable
{
    private Sprite2D ship = null;

    private KeyControls keyControls = null;

    public AnimationTest()
    {
        Frame2D gameFrame = new Frame2D(Frame2D.REG_PAINTER,1024,768,false);
        GamePainter painter = (GamePainter)gameFrame.getPainter();
        painter.setFrameRate(30);
    
        keyControls = new KeyControls(painter.getComponent());
        keyControls.set(KeyEvent.VK_LEFT);
        keyControls.set(KeyEvent.VK_RIGHT);

        ship = new Sprite2D("/images/ship.gif");
        ship.setLocation(500,400);
        painter.addToPaintList(ship);

        painter.addToPaintList(this);

    }

    public void update(float interpolation)
    {
        if (keyControls.isPressed(KeyEvent.VK_LEFT)) ship.rotate(-Math.PI/16);
        else if (keyControls.isPressed(KeyEvent.VK_RIGHT)) ship.rotate(Math.PI/16);
    }
    public void paintObject(Graphics g){}

    public static void main(String[] args)
    {
        new AnimationTest();
    }

}

Let me know what you think. Talk to you soon!

Thursday, October 7, 2010

Get Started!

Intro

Hello, first of all. This is the first official JA2DAPI blog entry. We'll go ahead and jump into some basic things about the API...

Okay, so to start things off, there's a kick-off class called Frame2D that is a simple way to create a window (or full screen display), as well as an animation and render environment.  To create the Frame2D, you specify the size of the window, whether it is to be full screen or not, and the type of Painter you want. The Painter is what handles the rendering and animation of things. There's currently two Painters that are available: The GamePainter is designed for applications that have a lot of continuous animation (most games) and EventDrivenPainter is designed for applications where updates (and render calls) are driven by specific, typically user input-driven, events.

Here's a way to create a Frame2D that is a 1024X768 window with a GamePainter:

import twodapi.core.*;
import java.awt.Graphics;

public class StarterTest
{
    public static void main(String[] args)
    {
        Frame2D gameFrame = new Frame2D (Frame2D.REG_PAINTER, 1024, 768, false);
        GamePainter painter = (GamePainter)gameFrame.getPainter();
    }
}
 

Notice that we immediately have a GamePainter ready to go. The GamePainter is what we use to add objects to the window. To demonstrate, we add this code to main():

        Sprite2D ship= new Sprite2D("/images/ship.gif");
        painter.addToPaintList(ship);
        ship.setLocation(500, 400);

Here we created a Sprite2D object based on the "ship.gif" image and added it to the GamePainter's paint list. Then, we moved the ship sprite to be closer to the center of the window.

Animation

So the animation framework I've adopted is a typical "update and render" loop. Under the hood, there's an AnimationThread running hard at work to maintain the frame rate you have specified. FYI, all sprite objects (Sprite2D, FlipbookSprite, and MouseSprite) automatically receive updates from the Painter after they are added to the paint list. We can access these updates by extending a sprite class and override updateState(float interpolation). See below:

class ShipSprite extends Sprite2D
{
    public ShipSprite()
    {
        super("/images/ship.gif");
    }

    public void updateState(float interpolation)
    {
        rotate(Math.PI/16);
    }
}


In the constructor (public ShipSprite()), we are merely calling the Sprite2D constructor and passing in the filename for the ship image as we did above. What's new is the override of the method updateState(). This method is being called by the GamePainter every frame update (50 frame per second, by default), and here we are rotating the ship Pi/16 radians per update.


Well, that's it for now! There are a couple of other ways to animate in JA2DAPI, and I will explore those in the next blog. Stay tuned!