Didn’t you say we were focussing on getting awesome stuff, rather than adding one engine file after another that doesn’t bring any direct results! True, true. Hang on, one or two more to go. You will see that we have created quite an engine already, making future work so much easier.
We load (atlas) images into our game. We can find them by their idName – which is just the filename, which means YOU MUST USE UNIQUE FILENAMES in this tiny engine. But, the “EnEntitySprite” class we started with, still doesn’t know what to draw. We have to couple the Sprite with this Image, and pick a "Region" within the atlas.
But hold on. We can take the quick route here, but you'll get stuck again later once we want to animate our sprites. That means, playing multiple frames, like a cartoon. Or having multiple moves (walk, run, stand, poop, die, ...). So I wanted to anticipate on that. Looking in my crystal ball, I’d say we need a “SpriteAnimations” class... Abra kazam.
Sprite Attributes
Just like multiple entities can pick the same image, so they can use the same set of animations. But what exactly is an “animation” to begin with? We can describe it as;
· IdName Stand, Walk, run, punch, die01, die02, dieHard
· FrameCount How many frames will be played in a row?
· Duration How many seconds does the total animation take?
· Next Start playing another animation, replay itself (loop), or stick at the last frame
We may want to go even deeper, by adding a list of “Frames”. The data above assumes every frame takes stays in the picture for an equal amount of time. Ie, if “duration is 2 seconds”, and frameCount is 8#, then each frame will show for 2/8 = 0.25 seconds. If you want a finer control, you could make a FrameList instead, and give each its own time setting.
Another thing you can do with individual frames, is playing with the sprite origin (point of rotation/center), and size, in case it grows or something. In the"Punch" animation above, the right image is wider than the first one. That means you have to adjust the scale, otherwise Abobo (yes, that is his name) will shrink into a thinner version of hiimself at the second frame.
And what I did 16 years ago (-gosh time flies-) in a fighting game, was giving attributes. Some frames were “dangerous” while others weren’t. So in that punch animation above, the fist area in frame #2 would be marked as "dangerous"; if it overlaps another sprite, it would mean it got smacked. The first frame on the other hand is still safe to touch.
For now I don’t think we’ll need individual frames though (but I programmed it into the code below anyway). Two properties are still missing though:
· GxImage The (atlas) texture being used, that contains all the frames we need
· TextureRegion[] For each frame, we need to know the Atlas subregion
Notice that I did not use the built-in LibGDX animation class. Why not? Don’t know, I just didn’t.
public class GxAnimation {
public class GxAnimationFrame {
public TextureRegion region;
public float duration;
public GxAnimationFrame nextFrame;
public GxAnimationFrame( float duration, String regionName, GxImage image )
{ // get coordinates from the Atlas texture
this.region = image.findRegion( regionName );
this.duration = duration;
this.nextFrame = null;
} // create
} // GxAnimationFrame
private class GxAnimationNext
{
GxAnimation next;
float chancePercent;
public GxAnimationNext( GxAnimation next, float chancePercent )
{
this.next = next;
this.chancePercent = chancePercent;
}
} // GxAnimationNext
//**********************************************
String idName;
int frameCount;
float durationSecs;
GxImage image;
GxAnimationFrame[] frames; // Atlas region coordinates for each frame + other props
int nextCount; // Amount of next animations, to play after this one is done
GxAnimationNext[] next; // Play one of these after this animation is done
public GxAnimation( String idName, int frameCount, float durationSecs, int nextCount, GxImage image )
{
this.idName = idName;
this.frameCount = frameCount;
this.durationSecs = durationSecs;
this.next = null;
this.image = image;
// Prepare region array, then find each frame
if ( frameCount = this.currentFrame.duration ) {
this.frameDelta = 0.f;
nextFrame = this.currentFrame.nextFrame;
if ( nextFrame == null ) {
// Image done, pick another (if any)
GxAnimation nextAnimation = this.currentAnimation.getNext();
if ( nextAnimation != null ) {
this.setAnimation( nextAnimation, true );
}
}
}
// Frame changed
if ( nextFrame != this.currentFrame && nextFrame != null ) {
this.frameDelta = 0.f;
this.currentFrame = nextFrame;
this.sprite.setRegion( nextFrame.region );
}
}
} // update
@Override
public void render( Batch batch )
{
if ( this.currentFrame == null ) return;
this.sprite.draw( batch );
} // render
...
} // EnEntitySprite
So the "setAnimation" will reset the timer (unless the same animation was already playing), and fetch the first frame. The update function will keep a "frameDelta", a timer that increases until it passes the frame duration, then resets and pushes the next frame. When out of frames, we'll ask for a Next Animation -which could be a random one. If there is no next animation, we just freeze. waiting until somebody will call the setAnimation() function again.
Weiterlesen...