The first thing I noticed after creating the animated sprite is that I had the need to allow a single sprite to have multiple animations. This was apparent when I wanted to have a player controlled sprite move around the screen in two dimensions. Instead of creating a new rendering component as I initially used, I chose to create an animated sprite and use the same rendering component. This means that the user can once again extend this animated class to do whatever they require.
There are many corner cases that need to be analyzed later to determine how to make the animation transitions seamless.
Above is a small video of the character moving around the screen. I show some movement while holding the arrow keys down, as well as showing some intermittent key presses that make the sprite look like it's in slow motion.
Below is the controlling application example.
#include "precomp.hpp"
#include "Engine.hpp"
#include "Animation.hpp"
#include "AnimatedSprite.hpp"
#include <stdlib.h>
#include <iostream>
Engine* engine;
AnimatedSprite* link;
std::string forward("f");
std::string back("b");
std::string left("l");
std::string right("r");
ge::Key lastKey = ge::Unknown;
int deltaMove = 10;
void doKeyRelease(int key)
{
static bool fs = false;
switch(key)
{
case ge::Escape:
engine->close();
break;
case ge::Return:
engine->setFullScreen(!fs);
fs = !fs;
break;
case ge::Left:
case ge::Right:
case ge::Down:
case ge::Up:
link->pause();
default:
break;
}
};
void doKeyPress(int key)
{
switch(key)
{
case ge::Left:
if(lastKey != ge::Left)
{
lastKey = ge::Left;
link->setAnimation(left);
link->goToFirstFrame();
}
else
{
link->play();
}
link->move(deltaMove * -1,0);
break;
case ge::Right:
if(lastKey != ge::Right)
{
lastKey = ge::Right;
link->setAnimation(right);
link->goToFirstFrame();
}
else
{
link->play();
}
link->move(deltaMove,0);
break;
case ge::Up:
if(lastKey != ge::Up)
{
lastKey = ge::Up;
link->setAnimation(back);
link->goToFirstFrame();
}
else
{
link->play();
}
link->move(0,deltaMove * -1);
break;
case ge::Down:
if(lastKey != ge::Down)
{
lastKey = ge::Down;
link->setAnimation(forward);
link->goToFirstFrame();
}
else
{
link->play();
}
link->move(0,deltaMove);
break;
default:
break;
}
};
int main(int aargc, const char* argv[])
{
// Setup the window
engine = new Engine("Game Engine Sprite Test", 800,600);
engine->setFrameRate(60);
engine->registerKeyPressedCallback(doKeyPress);
engine->registerKeyReleasedCallback(doKeyRelease);
// Load a texture
int t0 = engine->addTexture("link.png");
// Create collision area
std::vector<ge::fVertex> square;
square.push_back(ge::fVertex(0.0f,0.0f));
square.push_back(ge::fVertex(64.0f,0.0f));
square.push_back(ge::fVertex(64.0f,64.0f));
square.push_back(ge::fVertex(0.0f,64.0f));
// Create a collider sprite
link = new AnimatedSprite();
link->setScale(.5f,.5f);
link->setTexture(t0);
link->setSpeed(100);
// Set link as a collider
link->setCollision(&square, ge::Collision_SOLID);
Animation* linkForward = new Animation();
Animation* linkBack = new Animation();
Animation* linkLeft = new Animation();
Animation* linkRight = new Animation();
// StartX, StartY, Width, Height
// create link forward movement
linkForward->addFrame(0,0,120,130);
linkForward->addFrame(0,520,120,130);
linkForward->addFrame(120,520,120,130);
linkForward->addFrame(240,520,120,130);
linkForward->addFrame(360,520,120,130);
linkForward->addFrame(480,520,120,130);
linkForward->addFrame(600,520,120,130);
linkForward->addFrame(720,520,120,130);
linkForward->addFrame(840,520,120,130);
linkForward->addFrame(960,520,120,130);
linkForward->addFrame(1080,520,120,130);
// create link left movement
linkLeft->addFrame(0,130,120,130);
linkLeft->addFrame(0,650,120,130);
linkLeft->addFrame(120,650,120,130);
linkLeft->addFrame(240,650,120,130);
linkLeft->addFrame(360,650,120,130);
linkLeft->addFrame(480,650,120,130);
linkLeft->addFrame(600,650,120,130);
linkLeft->addFrame(720,650,120,130);
linkLeft->addFrame(840,650,120,130);
linkLeft->addFrame(960,650,120,130);
linkLeft->addFrame(1080,650,120,130);
// create link back movement
linkBack->addFrame(0,260,120,130);
linkBack->addFrame(0,780,120,130);
linkBack->addFrame(120,780,120,130);
linkBack->addFrame(240,780,120,130);
linkBack->addFrame(360,780,120,130);
linkBack->addFrame(480,780,120,130);
linkBack->addFrame(600,780,120,130);
linkBack->addFrame(720,780,120,130);
linkBack->addFrame(840,780,120,130);
linkBack->addFrame(960,780,120,130);
linkBack->addFrame(1080,780,120,130);
// create link right movement
linkRight->addFrame(0,390,120,130);
linkRight->addFrame(0,910,120,130);
linkRight->addFrame(120,910,120,130);
linkRight->addFrame(240,910,120,130);
linkRight->addFrame(360,910,120,130);
linkRight->addFrame(480,910,120,130);
linkRight->addFrame(600,910,120,130);
linkRight->addFrame(720,910,120,130);
linkRight->addFrame(840,910,120,130);
linkRight->addFrame(960,910,120,130);
linkRight->addFrame(1080,910,120,130);
// Add the animation to the sprite
link->addAnimation(forward, linkForward);
link->addAnimation(back, linkBack);
link->addAnimation(left, linkLeft);
link->addAnimation(right, linkRight);
// initialize the link sprite
link->setAnimation(forward);
link->pause(); // we don't want him moving
link->goToFirstFrame(); // not strictly neccessary
// Add our link as a sprite
engine->addSprite(link);
//std::vector<Entity*>::iterator it;
while(engine->isRunning())
{
engine->run();
}
delete engine;
engine = NULL;
}