-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial Release of olcPGEX_AnimatedSprite
- Loading branch information
1 parent
19ea022
commit 725ad3e
Showing
2 changed files
with
341 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,111 @@ | ||
# olcPGEX_AnimatedSprite | ||
Easily use animated sprites in the OLC Pixel Game Engine | ||
|
||
This extension is designed for use with the [olcPixelGameEngine](https://github.com/OneLoneCoder/olcPixelGameEngine) by [Javidx9](https://github.com/OneLoneCoder). It allows you to easily use animated sprites that utilise either single-file spritesheets or multiple image files for each frame. | ||
|
||
--- | ||
|
||
## Requirements | ||
|
||
The extension requires the [olcPGEX_Graphics2D](https://github.com/OneLoneCoder/olcPixelGameEngine/blob/master/Extensions/olcPGEX_Graphics2D.h) extension to work, but should require no additional libraries beyond that and the olcPixelGameEngine itself. | ||
|
||
--- | ||
|
||
## Usage | ||
|
||
To use the olcPGEX_AnimatedSprite extension, it needs to be included in your application. This is done like so: | ||
|
||
```cpp | ||
#define OLC_PGEX_ANIMSPR | ||
#include "olcPGEX_AnimatedSprite.h" | ||
``` | ||
|
||
### Single Spritesheet | ||
|
||
```cpp | ||
// define sprite in your PGE program | ||
olc::AnimatedSprite sprite; | ||
|
||
bool OnUserCreate() | ||
{ | ||
// configure the sprite: | ||
sprite.mode = olc::AnimatedSprite::SPRITE_MODE::SINGLE; // set sprite to use a single spritesheet | ||
sprite.spriteSheet = new olc::Sprite("spritesheet.png"); // define image to use for the spritesheet | ||
sprite.SetSpriteSize({50, 50}); // define size of each sprite with an olc::vi2d | ||
sprite.SetSpriteScale(2.0f); // define scale of sprite; 1.0f is original size. Must be above 0 and defaults to 1.0f | ||
|
||
// define states - state name and vector of olc::vi2d to define the top-left position of each frame in the spritesheet | ||
sprite.AddState("idle", { | ||
// let's assume a sprite sheet with 8 rows and columns, using the 50x50 sprite size defined above | ||
{0, 0}, // row 1, column 1 (top left of entire image) | ||
{0, 50}, // row 1, column 2 | ||
{400, 200}, // row 8, column 4 | ||
}); | ||
|
||
sprite.AddState("walking", { | ||
{50, 0}, | ||
{50, 50}, | ||
{50, 100}, | ||
}); | ||
|
||
// set initial state | ||
sprite.SetState("idle") | ||
|
||
return true; | ||
} | ||
|
||
bool OnUserUpdate(float fElapsedTime) | ||
{ | ||
sprite.Draw(felapsedTime, {20.0f, 20.0f}); // draws the sprite at location x:20, y:20 and animates it | ||
|
||
return true; | ||
} | ||
``` | ||
### Multiple Sprite Files | ||
```cpp | ||
// define sprite in your PGE program | ||
olc::AnimatedSprite sprite; | ||
bool OnUserCreate() | ||
{ | ||
// configure the sprite | ||
sprite.mode = olc::AnimatedSprite::SPRITE_MODE::MULTI; | ||
sprite.SetSpriteSize({50.0f, 50.0f); | ||
sprite.SetSpriteScale(2.0f); | ||
// define states - state name and a vector of std::strings that define the location of each image file | ||
sprite.AddState("idle", { | ||
"frame1.png", | ||
"frame2.png", | ||
"frame3.png", | ||
"frame4.png", | ||
}); | ||
// set default state | ||
sprite.SetState("idle"); | ||
return true; | ||
} | ||
bool OnUserUpdate(float fElapsedTime) | ||
{ | ||
sprite.Draw(fElapsedTime, {20.0f, 20.0f}); | ||
} | ||
``` | ||
|
||
### Flipping Sprites | ||
|
||
You may want to flip a sprite vertically or horizontally - for example, if your spritesheet only has right-facing images. This can be achieved by changing the flip mode, like so: | ||
|
||
```cpp | ||
sprite.flip = olc::AnimatedSprite::FLIP_MODE::HORIZONTAL; // flip horizontally (e.g. make right-facing image face the left) | ||
sprite.flip = olc::AnimatedSprite::FLIP_MODE::VERTICAL; // flip vertically (e.g. make image upside down) | ||
sprite.flip = olc::AnimatedSprite::FLIP_MODE::NONE; // display original image | ||
``` | ||
|
||
--- | ||
|
||
## Contributions | ||
|
||
Contributions are more than welcome. They can be in the form of reporting bugs and making feature requests (use GitHub issues for both of these), or PRs for changes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
/* | ||
olcPGEX_AnimatedSprite.h | ||
+-------------------------------------------------------------+ | ||
| OneLoneCoder Pixel Game Engine Extension | | ||
| AnimatedSprites - v1.0 | | ||
+-------------------------------------------------------------+ | ||
What is this? | ||
~~~~~~~~~~~~~ | ||
This is an extension to the olcPixelGameEngine, which provides | ||
the ability to easily animate sprites with either a single | ||
spritesheets or individual image files for each frame. | ||
Use of this extension requires the olcPGEX_Graphics2D extension. | ||
License (OLC-3) | ||
~~~~~~~~~~~~~~~ | ||
Copyright 2018 - 2019 OneLoneCoder.com | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions | ||
are met: | ||
1. Redistributions or derivations of source code must retain the above | ||
copyright notice, this list of conditions and the following disclaimer. | ||
2. Redistributions or derivative works in binary form must reproduce | ||
the above copyright notice. This list of conditions and the following | ||
disclaimer must be reproduced in the documentation and/or other | ||
materials provided with the distribution. | ||
3. Neither the name of the copyright holder nor the names of its | ||
contributors may be used to endorse or promote products derived | ||
from this software without specific prior written permission. | ||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
Links | ||
~~~~~ | ||
Homepage: https://matthewhayward.co.uk | ||
Author | ||
~~~~~~ | ||
Matt Hayward aka SaladinAkara | ||
*/ | ||
|
||
#include "olcPGEX_Graphics2D.h" | ||
|
||
#ifndef OLC_PGEX_ANIMATEDSPRITE | ||
#define OLC_PGEX_ANIMATEDSPRITE | ||
|
||
namespace olc | ||
{ | ||
class AnimatedSprite : public olc::PGEX | ||
{ | ||
public: | ||
void SetState(std::string newState); | ||
std::string GetState(); | ||
void Draw(float fElapsedTime, olc::vf2d position); | ||
void AddState(std::string stateName, std::vector<std::string> imagePaths); | ||
void AddState(std::string stateName, std::vector<olc::vi2d> spriteLocations); | ||
void SetSpriteSize(olc::vi2d size); | ||
olc::vi2d GetSpriteSize(); | ||
void SetSpriteScale(float scale); | ||
|
||
protected: | ||
olc::Sprite* GetMultiFrame(float fElapsedTime); | ||
olc::vi2d GetSingleFrame(float fElapsedTime); | ||
|
||
public: | ||
bool flipped = false; | ||
enum class FLIP_MODE { | ||
NONE = 0, | ||
HORIZONTAL = 1, | ||
VERTICAL = 2 | ||
}; | ||
enum class SPRITE_MODE { | ||
MULTI = 0, | ||
SINGLE = 1 | ||
}; | ||
FLIP_MODE flip = FLIP_MODE::NONE; | ||
SPRITE_MODE mode = SPRITE_MODE::MULTI; | ||
olc::Sprite* spriteSheet = nullptr; | ||
|
||
protected: | ||
std::string state; | ||
std::map<std::string, std::vector<olc::Sprite*>> multiFrames; | ||
std::map<std::string, std::vector<olc::vi2d>> singleFrames; | ||
float frameTimer = 0.0f; | ||
float frameDuration = 0.1f; | ||
unsigned int currentFrame; | ||
olc::vi2d spriteSize; | ||
float spriteScale = 1.0f; | ||
}; | ||
} | ||
|
||
#ifdef OLC_PGEX_ANIMSPR | ||
#undef OLC_PGEX_ANIMSPR | ||
|
||
namespace olc | ||
{ | ||
olc::Sprite* AnimatedSprite::GetMultiFrame(float fElapsedTime) | ||
{ | ||
frameTimer += fElapsedTime; | ||
|
||
if (frameTimer >= frameDuration) { | ||
currentFrame++; | ||
frameTimer = 0.0f; | ||
|
||
if (currentFrame >= multiFrames[state].size()) { | ||
currentFrame = 0; | ||
} | ||
} | ||
|
||
return multiFrames[state][currentFrame]; | ||
} | ||
|
||
olc::vi2d AnimatedSprite::GetSingleFrame(float fElapsedTime) | ||
{ | ||
frameTimer += fElapsedTime; | ||
|
||
if (frameTimer >= frameDuration) { | ||
currentFrame++; | ||
frameTimer = 0.0f; | ||
|
||
if (currentFrame >= singleFrames[state].size()) { | ||
currentFrame = 0; | ||
} | ||
} | ||
|
||
return singleFrames[state][currentFrame]; | ||
} | ||
|
||
void AnimatedSprite::SetState(std::string newState) | ||
{ | ||
if ((mode == SPRITE_MODE::MULTI && multiFrames.find(newState) == multiFrames.end()) | ||
|| (mode == SPRITE_MODE::SINGLE && singleFrames.find(newState) == singleFrames.end())) { | ||
|
||
std::cout << "Error: State " << newState << " does not exist." << std::endl; | ||
return; | ||
} | ||
|
||
if (newState != state) { | ||
state = newState; | ||
currentFrame = 0; | ||
} | ||
} | ||
|
||
std::string AnimatedSprite::GetState() | ||
{ | ||
return state; | ||
} | ||
|
||
void AnimatedSprite::AddState(std::string stateName, std::vector<std::string> imgPaths) | ||
{ | ||
for (std::string& path : imgPaths) { | ||
multiFrames[stateName].push_back(new olc::Sprite(path)); | ||
} | ||
} | ||
|
||
void AnimatedSprite::AddState(std::string stateName, std::vector<olc::vi2d> spriteLocations) | ||
{ | ||
for (olc::vi2d& location : spriteLocations) { | ||
singleFrames[stateName].push_back(location); | ||
} | ||
} | ||
|
||
void AnimatedSprite::SetSpriteSize(olc::vi2d size) | ||
{ | ||
spriteSize = size; | ||
} | ||
|
||
olc::vi2d AnimatedSprite::GetSpriteSize() | ||
{ | ||
return spriteSize; | ||
} | ||
|
||
void AnimatedSprite::SetSpriteScale(float scale) | ||
{ | ||
if (scale <= 0.0f) { | ||
spriteScale = 1.0f; | ||
} else { | ||
spriteScale = scale; | ||
} | ||
} | ||
|
||
void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position) | ||
{ | ||
olc::GFX2D::Transform2D t; | ||
|
||
if (flip == FLIP_MODE::HORIZONTAL) { | ||
t.Translate(-((spriteSize.x / 2) * spriteScale), 0); | ||
t.Scale(-spriteScale, spriteScale); | ||
} else if (flip == FLIP_MODE::VERTICAL) { | ||
t.Translate(0, -((spriteSize.y / 2) * spriteScale)); | ||
t.Scale(spriteScale, -spriteScale); | ||
} | ||
else { | ||
t.Scale(spriteScale, spriteScale); | ||
} | ||
|
||
t.Translate(position.x, position.y); | ||
|
||
if (mode == SPRITE_MODE::MULTI) { | ||
olc::GFX2D::DrawSprite(GetMultiFrame(fElapsedTime), t); | ||
} | ||
else { | ||
olc::Sprite* sprite = new olc::Sprite(spriteSize.x, spriteSize.y); | ||
pge->SetDrawTarget(sprite); | ||
pge->DrawPartialSprite({ 0, 0 }, spriteSheet, GetSingleFrame(fElapsedTime), spriteSize); | ||
pge->SetDrawTarget(nullptr); | ||
olc::GFX2D::DrawSprite(sprite, t); | ||
delete sprite; | ||
} | ||
} | ||
} | ||
|
||
#endif | ||
#endif |