From bdc80e4e118cf039278b7f5df5f8bd63a60e2c40 Mon Sep 17 00:00:00 2001 From: Matt Hayward Date: Mon, 25 May 2020 00:32:08 +0100 Subject: [PATCH 1/6] Remove 2D Graphics PGEX Dependency - Leverage PGE2's `Sprite::Flip` instead of using 2D Graphics PGEX to simplify sprite flipping - Move responsibility from PGEX to user to define when to flip the sprite by adding `olc::Sprite::Flip` as a parameter to the `Draw()` method --- olcPGEX_AnimatedSprite.h | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index fd7f4b1..41fdd2f 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -60,8 +60,6 @@ 0xnicholasc - https://github.com/0xnicholasc */ -#include "olcPGEX_Graphics2D.h" - #ifndef OLC_PGEX_ANIMATEDSPRITE #define OLC_PGEX_ANIMATEDSPRITE @@ -75,7 +73,7 @@ namespace olc // Get current sprite state std::string GetState(); // Draw sprite - void Draw(float fElapsedTime, olc::vf2d position); + void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE); // Add state for sprite in SPRITE_MODE::MULTI with a specified frameDuration void AddState(std::string stateName, float frameDuration, std::vector imagePaths); // Add state for sprite in SPRITE_MODE::SINGLE with a specified frameDuration @@ -96,18 +94,11 @@ namespace olc olc::vi2d GetSingleFrame(float fElapsedTime); public: - bool flipped = false; float defaultFrameDuration = 0.1f; // Frame duration to be used if one is not specified otherwise - 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; @@ -234,36 +225,13 @@ namespace olc } } - void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position) + void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip) { - olc::GFX2D::Transform2D t; - - if (flip == FLIP_MODE::HORIZONTAL) { - t.Translate(-spriteSize.x, 0); - t.Scale(-spriteScale, spriteScale); - } else if (flip == FLIP_MODE::VERTICAL) { - t.Translate(0, -spriteSize.y); - 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); + pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); } else { - olc::Pixel::Mode currentPixelMode = pge->GetPixelMode(); - olc::Sprite* currentDrawTarget = pge->GetDrawTarget(); - - pge->SetDrawTarget(placeholder); - pge->Clear(olc::BLANK); - pge->SetPixelMode(olc::Pixel::NORMAL); - pge->DrawPartialSprite({ 0, 0 }, spriteSheet, GetSingleFrame(fElapsedTime), spriteSize); - pge->SetDrawTarget(currentDrawTarget); - pge->SetPixelMode(currentPixelMode); - olc::GFX2D::DrawSprite(placeholder, t); + pge->DrawPartialSprite(position, spriteSheet, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); } } } From 2dfadb09927869f91335765aff426759c6b4f570 Mon Sep 17 00:00:00 2001 From: Matt Hayward Date: Mon, 25 May 2020 03:22:10 +0100 Subject: [PATCH 2/6] Add Decal Support - Allow Decals to be used instead of sprites - Allow flipped Decals and ensure positioning is maintained - Add flag to determine 'type' - i.e. Sprite or Decal --- olcPGEX_AnimatedSprite.h | 101 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index 41fdd2f..77dcd51 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -65,6 +65,24 @@ namespace olc { + class Renderable + { + public: + Renderable() = default; + Renderable(std::string spriteLocation) { + sprite = new Sprite(spriteLocation); + decal = new Decal(sprite); + } + ~Renderable() { + delete decal; + delete sprite; + } + + public: + olc::Sprite* sprite = nullptr; + olc::Decal* decal = nullptr; + }; + class AnimatedSprite : public olc::PGEX { public: @@ -91,7 +109,10 @@ namespace olc protected: olc::Sprite* GetMultiFrame(float fElapsedTime); + olc::Decal* GetMultiRenderable(float fElapsedTime); olc::vi2d GetSingleFrame(float fElapsedTime); + olc::vf2d GetDecalScale(uint8_t flip); + olc::vf2d GetDecalPosition(olc::vf2d position, uint8_t flip); public: float defaultFrameDuration = 0.1f; // Frame duration to be used if one is not specified otherwise @@ -99,13 +120,19 @@ namespace olc MULTI = 0, SINGLE = 1 }; + enum class SPRITE_TYPE { + SPRITE, + DECAL + }; SPRITE_MODE mode = SPRITE_MODE::MULTI; - olc::Sprite* spriteSheet = nullptr; + SPRITE_TYPE type = SPRITE_TYPE::SPRITE; + Renderable* spriteSheet; protected: std::string state; std::map> multiFrames; std::map> singleFrames; + std::map> multiRenderables; std::map frameDurations; float frameTimer = 0.0f; unsigned int currentFrame; @@ -136,6 +163,22 @@ namespace olc return multiFrames[state][currentFrame]; } + olc::Decal* AnimatedSprite::GetMultiRenderable(float fElapsedTime) + { + frameTimer += fElapsedTime; + + if (frameTimer >= frameDurations[state]) { + currentFrame++; + frameTimer = 0.0f; + + if (currentFrame >= multiRenderables[state].size()) { + currentFrame = 0; + } + } + + return multiRenderables[state][currentFrame]->decal; + } + olc::vi2d AnimatedSprite::GetSingleFrame(float fElapsedTime) { frameTimer += fElapsedTime; @@ -154,7 +197,15 @@ namespace olc void AnimatedSprite::SetState(std::string newState) { - if ((mode == SPRITE_MODE::MULTI && multiFrames.find(newState) == multiFrames.end()) + bool stateFound = false; + if (type == SPRITE_TYPE::SPRITE) { + 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; + } + } else if ((mode == SPRITE_MODE::MULTI && multiRenderables.find(newState) == multiRenderables.end()) || (mode == SPRITE_MODE::SINGLE && singleFrames.find(newState) == singleFrames.end())) { std::cout << "Error: State " << newState << " does not exist." << std::endl; @@ -186,7 +237,11 @@ namespace olc void AnimatedSprite::AddState(std::string stateName, float frameDuration, std::vector imgPaths) { for (std::string& path : imgPaths) { - multiFrames[stateName].push_back(new olc::Sprite(path)); + if (type == SPRITE_TYPE::SPRITE) { + multiFrames[stateName].push_back(new olc::Sprite(path)); + } else { + multiRenderables[stateName].push_back(new Renderable(path)); + } } frameDurations[stateName] = frameDuration; @@ -228,11 +283,47 @@ namespace olc void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip) { if (mode == SPRITE_MODE::MULTI) { - pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); + if (type == SPRITE_TYPE::SPRITE) { + pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); + } else { + pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip)); + } } else { - pge->DrawPartialSprite(position, spriteSheet, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); + if (type == SPRITE_TYPE::SPRITE) { + pge->DrawPartialSprite(position, spriteSheet->sprite, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); + } else { + pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip)); + } + } + } + + olc::vf2d AnimatedSprite::GetDecalScale(uint8_t flip) + { + olc::vf2d scale = { (float)spriteScale, (float)spriteScale }; + + if (flip == olc::Sprite::Flip::HORIZ) { + return { -(scale.x), scale.y }; + } + + if (flip == olc::Sprite::Flip::VERT) { + return { scale.x, -scale.y }; + } + + return scale; + } + + olc::vf2d AnimatedSprite::GetDecalPosition(olc::vf2d position, uint8_t flip) + { + if (flip == olc::Sprite::Flip::HORIZ) { + return { position.x + (spriteSize.x * spriteScale), position.y }; } + + if (flip == olc::Sprite::Flip::VERT) { + return { position.x, position.y + (spriteSize.y * spriteScale) }; + } + + return position; } } From 8076f40be7d267b0d72e4104f6fd9af7beeacee2 Mon Sep 17 00:00:00 2001 From: Moros Smith Date: Sun, 24 May 2020 23:31:17 -0400 Subject: [PATCH 3/6] The stuff! (#19) * add resource pack functionality * added tinting to decal rendering * fix code style --- olcPGEX_AnimatedSprite.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index 77dcd51..7767844 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -73,6 +73,13 @@ namespace olc sprite = new Sprite(spriteLocation); decal = new Decal(sprite); } + + Renderable(std::string spriteLocation, olc::ResourcePack* pack) + { + sprite = new Sprite(spriteLocation, pack); + decal = new Decal(sprite); + } + ~Renderable() { delete decal; delete sprite; @@ -91,7 +98,7 @@ namespace olc // Get current sprite state std::string GetState(); // Draw sprite - void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE); + void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE, olc::Pixel tint = olc::WHITE); // Add state for sprite in SPRITE_MODE::MULTI with a specified frameDuration void AddState(std::string stateName, float frameDuration, std::vector imagePaths); // Add state for sprite in SPRITE_MODE::SINGLE with a specified frameDuration @@ -280,20 +287,20 @@ namespace olc } } - void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip) + void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip, olc::Pixel tint) { if (mode == SPRITE_MODE::MULTI) { if (type == SPRITE_TYPE::SPRITE) { pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); } else { - pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip)); + pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip), tint); } } else { if (type == SPRITE_TYPE::SPRITE) { pge->DrawPartialSprite(position, spriteSheet->sprite, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); } else { - pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip)); + pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip), tint); } } } From c8a0a9505a2a8888b51ee451cf114d6ba3706b61 Mon Sep 17 00:00:00 2001 From: Matt Hayward Date: Wed, 27 May 2020 20:07:53 +0100 Subject: [PATCH 4/6] Add Ping Pong Animation Mode - Move enums to top of class so they're accessible to methods - Add enum for play mode - Update `AddState` methods to allow animation mode to be specified - Update 'get current frame' logic to integrate ping pong mode --- olcPGEX_AnimatedSprite.h | 112 ++++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index 7767844..443e12f 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -73,13 +73,6 @@ namespace olc sprite = new Sprite(spriteLocation); decal = new Decal(sprite); } - - Renderable(std::string spriteLocation, olc::ResourcePack* pack) - { - sprite = new Sprite(spriteLocation, pack); - decal = new Decal(sprite); - } - ~Renderable() { delete decal; delete sprite; @@ -92,20 +85,34 @@ namespace olc class AnimatedSprite : public olc::PGEX { + public: + enum class SPRITE_MODE { + MULTI, + SINGLE + }; + enum class SPRITE_TYPE { + SPRITE, + DECAL + }; + enum class PLAY_MODE { + LOOP, + PING_PONG + }; + public: // Set current state of sprite void SetState(std::string newState); // Get current sprite state std::string GetState(); // Draw sprite - void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE, olc::Pixel tint = olc::WHITE); - // Add state for sprite in SPRITE_MODE::MULTI with a specified frameDuration - void AddState(std::string stateName, float frameDuration, std::vector imagePaths); - // Add state for sprite in SPRITE_MODE::SINGLE with a specified frameDuration - void AddState(std::string stateName, float frameDuration, std::vector spriteLocations); - // Add state for sprite in SPRITE_MODE::MULTI using the default frameDuration + void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE); + // Add state for sprite in SPRITE_MODE::MULTI with a specified frameDuration and playMode + void AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector imagePaths); + // Add state for sprite in SPRITE_MODE::SINGLE with a specified frameDuration and playMode + void AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector spriteLocations); + // Add state for sprite in SPRITE_MODE::MULTI using the default frameDuration and playMode void AddState(std::string stateName, std::vector imagePaths); - // Add state for sprite in SPRITE_MODE::SINGLE using the default frameDuration + // Add state for sprite in SPRITE_MODE::SINGLE using the default frameDuration and playMode void AddState(std::string stateName, std::vector spriteLocations); // Set size of sprite void SetSpriteSize(olc::vi2d size); @@ -123,14 +130,6 @@ namespace olc public: float defaultFrameDuration = 0.1f; // Frame duration to be used if one is not specified otherwise - enum class SPRITE_MODE { - MULTI = 0, - SINGLE = 1 - }; - enum class SPRITE_TYPE { - SPRITE, - DECAL - }; SPRITE_MODE mode = SPRITE_MODE::MULTI; SPRITE_TYPE type = SPRITE_TYPE::SPRITE; Renderable* spriteSheet; @@ -141,11 +140,12 @@ namespace olc std::map> singleFrames; std::map> multiRenderables; std::map frameDurations; - float frameTimer = 0.0f; - unsigned int currentFrame; + std::map playModes; + float frameTimer = 0.0f, spriteScale = 1.0f; + int currentFrame; olc::vi2d spriteSize; - float spriteScale = 1.0f; olc::Sprite* placeholder = nullptr; + bool playForward = true; }; } @@ -159,11 +159,21 @@ namespace olc frameTimer += fElapsedTime; if (frameTimer >= frameDurations[state]) { - currentFrame++; frameTimer = 0.0f; + if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) { + currentFrame--; + } else { + currentFrame++; + } + if (currentFrame >= multiFrames[state].size()) { - currentFrame = 0; + currentFrame = playModes[state] == PLAY_MODE::LOOP + ? 0 + : multiFrames[state].size() - 2; + playForward = false; + } else if (currentFrame <= 0) { + playForward = true; } } @@ -175,11 +185,23 @@ namespace olc frameTimer += fElapsedTime; if (frameTimer >= frameDurations[state]) { - currentFrame++; frameTimer = 0.0f; + if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) { + currentFrame--; + } + else { + currentFrame++; + } + if (currentFrame >= multiRenderables[state].size()) { - currentFrame = 0; + currentFrame = playModes[state] == PLAY_MODE::LOOP + ? 0 + : multiRenderables[state].size() - 2; + playForward = false; + } + else if (currentFrame <= 0) { + playForward = true; } } @@ -191,11 +213,23 @@ namespace olc frameTimer += fElapsedTime; if (frameTimer >= frameDurations[state]) { - currentFrame++; frameTimer = 0.0f; + if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) { + currentFrame--; + } + else { + currentFrame++; + } + if (currentFrame >= singleFrames[state].size()) { - currentFrame = 0; + currentFrame = playModes[state] == PLAY_MODE::LOOP + ? 0 + : singleFrames[state].size() - 2; + playForward = false; + } + else if (currentFrame <= 0) { + playForward = true; } } @@ -233,15 +267,15 @@ namespace olc void AnimatedSprite::AddState(std::string stateName, std::vector imgPaths) { - AnimatedSprite::AddState(stateName, defaultFrameDuration, imgPaths); + AnimatedSprite::AddState(stateName, defaultFrameDuration, PLAY_MODE::LOOP, imgPaths); } void AnimatedSprite::AddState(std::string stateName, std::vector spriteLocations) { - AnimatedSprite::AddState(stateName, defaultFrameDuration, spriteLocations); + AnimatedSprite::AddState(stateName, defaultFrameDuration, PLAY_MODE::LOOP, spriteLocations); } - void AnimatedSprite::AddState(std::string stateName, float frameDuration, std::vector imgPaths) + void AnimatedSprite::AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector imgPaths) { for (std::string& path : imgPaths) { if (type == SPRITE_TYPE::SPRITE) { @@ -252,15 +286,17 @@ namespace olc } frameDurations[stateName] = frameDuration; + playModes[stateName] = mode; } - void AnimatedSprite::AddState(std::string stateName, float frameDuration, std::vector spriteLocations) + void AnimatedSprite::AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector spriteLocations) { for (olc::vi2d& location : spriteLocations) { singleFrames[stateName].push_back(location); } frameDurations[stateName] = frameDuration; + playModes[stateName] = mode; } void AnimatedSprite::SetSpriteSize(olc::vi2d size) @@ -287,20 +323,20 @@ namespace olc } } - void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip, olc::Pixel tint) + void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip) { if (mode == SPRITE_MODE::MULTI) { if (type == SPRITE_TYPE::SPRITE) { pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); } else { - pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip), tint); + pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip)); } } else { if (type == SPRITE_TYPE::SPRITE) { pge->DrawPartialSprite(position, spriteSheet->sprite, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); } else { - pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip), tint); + pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip)); } } } From a6cfdcb8ffbbca208f5188434e0e62bee56d7667 Mon Sep 17 00:00:00 2001 From: Matt Hayward Date: Thu, 28 May 2020 06:29:46 +0100 Subject: [PATCH 5/6] Move Renderable Implementation - Move constructor and destructor of `Renderable` into implementation section of header --- olcPGEX_AnimatedSprite.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index 443e12f..0c03fab 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -69,14 +69,8 @@ namespace olc { public: Renderable() = default; - Renderable(std::string spriteLocation) { - sprite = new Sprite(spriteLocation); - decal = new Decal(sprite); - } - ~Renderable() { - delete decal; - delete sprite; - } + Renderable(std::string spriteLocation); + ~Renderable(); public: olc::Sprite* sprite = nullptr; @@ -154,6 +148,16 @@ namespace olc namespace olc { + Renderable::Renderable(std::string spriteLocation) { + sprite = new Sprite(spriteLocation); + decal = new Decal(sprite); + } + + Renderable::~Renderable() { + delete decal; + delete sprite; + } + olc::Sprite* AnimatedSprite::GetMultiFrame(float fElapsedTime) { frameTimer += fElapsedTime; @@ -189,8 +193,7 @@ namespace olc if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) { currentFrame--; - } - else { + } else { currentFrame++; } @@ -199,8 +202,7 @@ namespace olc ? 0 : multiRenderables[state].size() - 2; playForward = false; - } - else if (currentFrame <= 0) { + } else if (currentFrame <= 0) { playForward = true; } } @@ -217,8 +219,7 @@ namespace olc if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) { currentFrame--; - } - else { + } else { currentFrame++; } @@ -227,8 +228,7 @@ namespace olc ? 0 : singleFrames[state].size() - 2; playForward = false; - } - else if (currentFrame <= 0) { + } else if (currentFrame <= 0) { playForward = true; } } From 42bfdb9fe30da098e7451641c1d3b7c3c8172623 Mon Sep 17 00:00:00 2001 From: Matt Hayward Date: Sun, 31 May 2020 14:30:23 +0100 Subject: [PATCH 6/6] v2.0.0 Preparation - Update README.md to include new features - Update CONTRIBUTING.md - Re-add decal tinting --- CONTRIBUTING.md | 5 +++- README.md | 56 ++++++++++++++++++++++++++++++++-------- olcPGEX_AnimatedSprite.h | 11 ++++---- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4712fab..f2114ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,6 +23,9 @@ The following code style guidelines should be adhered to: - Variables should use `camelCase` - Variable names used in both the OLC Pixel Game Engine and the AnimatedSprite extension (and for the same purpose) should match, including the use of Hungarian Notation. For example, `fElapsedTime` +- **Pointers:** + - Pointers should be declared as `type* name` + - **Braces:** - Opening braces for methods should be placed on a new line - Opening braces for control structures should be placed on the same line @@ -39,4 +42,4 @@ The following code style guidelines should be adhered to: // } } - ``` + ``` \ No newline at end of file diff --git a/README.md b/README.md index fa44bd7..1e4c320 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,6 @@ This extension is designed for use with the [olcPixelGameEngine](https://github. --- -## 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: @@ -29,7 +23,7 @@ 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.spriteSheet = new olc::Renderable("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 @@ -94,14 +88,54 @@ bool OnUserUpdate(float fElapsedTime) } ``` +### Customising Animations + +The Animated Sprite PGEX supports two animation modes: loop and 'ping-pong'. + +In loop mode, when an animation reaches its final frame, it starts again from the first. This gives it the pattern of 123123123... + +In 'ping-pong' mode, when an animation reaches its final frame, it starts backwards until it reaches the first frame again, then goes back. This gives it the pattern of 12321232123... + +It is also possible to define the frame length of each animation. This determines the amount of time in seconds, a frame is displayed on screen before the next one is shown. + +Animation mode and frame duration are defined on a per-state basis, when the `AddState` method is called: + +```cpp +sprite.AddState("foo", 2.0f, olc::AnimatedSprite::PLAY_MODE::LOOP, foo); // set each frame to display for two seconds, with the default - loop - play mode +sprite.AddState("bar", 0.1f, olc::AnimatedSprite::PLAY_MODE::PING_PONG, bar); // set play mode to ping pong with default frame duration of 0.1 seconds +``` + ### 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: +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 passing in an `olc::Pixel::Flip` when drawing: + +```cpp +sprite.Draw(fElapsedTime, {10.0f, 10.0f}, olc::Sprite::Flip::NONE); // no flip - default +sprite.Draw(fElapsedTime, {10.0f, 10.0f}, olc::Sprite::Flip::HORIZ); // flip sprite horizontally +sprite.Draw(fElapsedTime, {10.0f, 10.0f}, olc::Sprite::Flip::VERT); // flip sprite vertically +``` + +### Using Decals + +You can draw Decals rather than Sprites by setting the sprite type for your animated sprite: + +```cpp +olc::AnimatedSprite sprite; + +sprite.type = olc::AnimatedSprite::SPRITE_TYPE::SPRITE; // set animated sprite to draw sprites, the default behaviour +sprite.type = olc::AnimatedSprite::SPRITE_TYPE::DECAL; // set animated sprite to draw decals +``` + +**NOTE:** If using decals, you must define the states after the Pixel Game Engine has fully loaded to ensure that the decals are correctly initialised. As such, you should do this in the `OnUserCreate` method of your PGE-derived class. + +### Tinting Decals + +The `olc::AnimatedSprite::Draw()` method accepts an optional `olc::Pixel` parameter which will tint the sprite in the specified colour. **Note:** This only works for decals. ```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 +// assuming sprite is using decals... +sprite.Draw(fElapsedTime, {10.0f, 10.0f}, olc::Sprite::Flip::NONE, olc::WHITE); // draw sprite with default white tinting (no tinting) +sprite.Draw(fElapsedTime, {10.0f, 10.0f}, olc::Sprite::Flip::NONE, olc::CYAN); // draw sprite with cyan tinting ``` --- diff --git a/olcPGEX_AnimatedSprite.h b/olcPGEX_AnimatedSprite.h index 0c03fab..5c65587 100644 --- a/olcPGEX_AnimatedSprite.h +++ b/olcPGEX_AnimatedSprite.h @@ -3,7 +3,7 @@ +-------------------------------------------------------------+ | OneLoneCoder Pixel Game Engine Extension | - | AnimatedSprites - v1.1.0 | + | AnimatedSprites - v2.0.0 | +-------------------------------------------------------------+ What is this? @@ -58,6 +58,7 @@ Contributors ~~~~~~~~~~~~ 0xnicholasc - https://github.com/0xnicholasc + Moros1138 - https://github.com/Moros1138 */ #ifndef OLC_PGEX_ANIMATEDSPRITE @@ -99,7 +100,7 @@ namespace olc // Get current sprite state std::string GetState(); // Draw sprite - void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE); + void Draw(float fElapsedTime, olc::vf2d position, uint8_t flip = olc::Sprite::Flip::NONE, olc::Pixel tint = olc::WHITE); // Add state for sprite in SPRITE_MODE::MULTI with a specified frameDuration and playMode void AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector imagePaths); // Add state for sprite in SPRITE_MODE::SINGLE with a specified frameDuration and playMode @@ -323,20 +324,20 @@ namespace olc } } - void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip) + void AnimatedSprite::Draw(float fElapsedTime, olc::vf2d position, uint8_t flip, olc::Pixel tint) { if (mode == SPRITE_MODE::MULTI) { if (type == SPRITE_TYPE::SPRITE) { pge->DrawSprite(position, GetMultiFrame(fElapsedTime), spriteScale, flip); } else { - pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip)); + pge->DrawDecal(GetDecalPosition(position, flip), GetMultiRenderable(fElapsedTime), GetDecalScale(flip), tint); } } else { if (type == SPRITE_TYPE::SPRITE) { pge->DrawPartialSprite(position, spriteSheet->sprite, GetSingleFrame(fElapsedTime), spriteSize, spriteScale, flip); } else { - pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip)); + pge->DrawPartialDecal(GetDecalPosition(position, flip), spriteSheet->decal, GetSingleFrame(fElapsedTime), spriteSize, GetDecalScale(flip), tint); } } }