forgot to commit, lighting and animations
This commit is contained in:
12
TODO
12
TODO
@@ -4,12 +4,12 @@
|
||||
|
||||
# Today
|
||||
|
||||
[-] Lighting (and torches)
|
||||
[ ] Lighting flicker (fire)
|
||||
[ ] NO TIME raytraced lighting
|
||||
[ ] Fix collision
|
||||
[ ] Better player spritesheet
|
||||
[ ] Animation system
|
||||
[x] Lighting (and torches)
|
||||
[x] Lighting flicker (fire)
|
||||
[d] Raytraced lighting
|
||||
[d] Fix collision
|
||||
[x] Better player spritesheet
|
||||
[x] Animation system
|
||||
[ ] Enemies / AI
|
||||
[ ] Dungeon fixed entity spawning
|
||||
[ ] Enemy AI
|
||||
|
||||
@@ -22,7 +22,7 @@ class Camera
|
||||
Entity* _Track = nullptr;
|
||||
|
||||
olc::vi2d _DesiredCoords;
|
||||
float _SmoothSpeed = 0.025f;
|
||||
float _SmoothSpeed = 0.015f;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
bool EntityCollide(Entity* entity, std::vector<Tile*>& nearby, int tileSize, CollisionInfo* info, olc::PixelGameEngine* engine)
|
||||
{
|
||||
static bool ShowCollisionDebug = false;
|
||||
if (engine->GetKey(olc::P).bPressed)
|
||||
ShowCollisionDebug = !ShowCollisionDebug;
|
||||
|
||||
if (!entity->HitBox) return false;
|
||||
|
||||
static Logger& _Logger = Logger::getInstance();
|
||||
@@ -16,19 +20,21 @@ bool EntityCollide(Entity* entity, std::vector<Tile*>& nearby, int tileSize, Col
|
||||
|
||||
float entityX = static_cast<float>(entity->Coords.x - entity->TrackingCamera->Coords.x);
|
||||
float entityY = static_cast<float>(entity->Coords.y - entity->TrackingCamera->Coords.y);
|
||||
float entityW = static_cast<float>(tileSize / 3.0f) * 2.0f;
|
||||
float entityH = static_cast<float>(tileSize / 3.0f) * 2.0f;
|
||||
float entityW = static_cast<float>(entity->HitBox->w);
|
||||
float entityH = static_cast<float>(entity->HitBox->h);
|
||||
|
||||
int entityLeft = static_cast<int>(entityX);
|
||||
int entityRight = static_cast<int>(entityX + entityW);
|
||||
int entityTop = static_cast<int>(entityY);
|
||||
int entityBottom = static_cast<int>(entityY + entityH);
|
||||
|
||||
//engine->DrawRect({(entity->HitBox->x + (int)entity->Coords.x) - (int)entity->TrackingCamera->Coords.x, (entity->HitBox->y + (int)entity->Coords.y) - (int)entity->TrackingCamera->Coords.y}, {entity->HitBox->w, entity->HitBox->h}, olc::RED);
|
||||
if (ShowDebug)
|
||||
engine->DrawRect(entityX, entityY, entityW, entityH, olc::RED);
|
||||
|
||||
for (auto tile : nearby)
|
||||
{
|
||||
//engine->DrawRect({ static_cast<int>(static_cast<float>((tile->Coords.x * tileSize) - entity->TrackingCamera->Coords.x)), static_cast<int>(static_cast<float>((tile->Coords.y * tileSize) - entity->TrackingCamera->Coords.y)) }, {tileSize, tileSize}, olc::BLUE);
|
||||
if (ShowDebug)
|
||||
engine->DrawRect({ static_cast<int>(static_cast<float>((tile->Coords.x * tileSize) - entity->TrackingCamera->Coords.x)), static_cast<int>(static_cast<float>((tile->Coords.y * tileSize) - entity->TrackingCamera->Coords.y)) }, {tileSize, tileSize}, olc::BLUE);
|
||||
|
||||
// return if not collidable
|
||||
if (!tile->IsSolid) continue;
|
||||
@@ -45,7 +51,8 @@ bool EntityCollide(Entity* entity, std::vector<Tile*>& nearby, int tileSize, Col
|
||||
|
||||
bool collision = xOverlaps && yOverlaps;
|
||||
|
||||
//engine->FillRect({static_cast<int>(static_cast<float>((tile->Coords.x * tileSize) - entity->TrackingCamera->Coords.x)), static_cast<int>(static_cast<float>((tile->Coords.y * tileSize) - entity->TrackingCamera->Coords.y))}, {tileSize, tileSize}, collision ? olc::RED : olc::BLUE);
|
||||
if (ShowDebug)
|
||||
engine->FillRect({static_cast<int>(static_cast<float>((tile->Coords.x * tileSize) - entity->TrackingCamera->Coords.x)), static_cast<int>(static_cast<float>((tile->Coords.y * tileSize) - entity->TrackingCamera->Coords.y))}, {tileSize, tileSize}, collision ? olc::RED : olc::BLUE);
|
||||
|
||||
if (!collision) continue;
|
||||
|
||||
@@ -59,6 +66,5 @@ bool EntityCollide(Entity* entity, std::vector<Tile*>& nearby, int tileSize, Col
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,73 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "olcPixelGameEngine.hpp"
|
||||
#include "olcPGEX_AnimatedSprite.hpp"
|
||||
|
||||
#include "Collisions.hpp"
|
||||
#include "Things.hpp"
|
||||
#include "Camera.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
|
||||
void PerlinNoise1D(int nCount, float *fSeed, int nOctaves, float fBias, float *fOutput)
|
||||
{
|
||||
// Used 1D Perlin Noise
|
||||
for (int x = 0; x < nCount; x++)
|
||||
{
|
||||
float fNoise = 0.0f;
|
||||
float fScaleAcc = 0.0f;
|
||||
float fScale = 1.0f / fBias;
|
||||
|
||||
for (int o = 0; o < nOctaves; o++)
|
||||
{
|
||||
int nPitch = nCount >> o;
|
||||
int nSample1 = (x / nPitch) * nPitch;
|
||||
int nSample2 = (nSample1 + nPitch) % nCount;
|
||||
|
||||
float fBlend = (float)(x - nSample1) / (float)nPitch;
|
||||
|
||||
float fSample = (1.0f - fBlend) * fSeed[nSample1] + fBlend * fSeed[nSample2];
|
||||
|
||||
fScaleAcc += fScale;
|
||||
fNoise += fSample * fScale;
|
||||
// fScale = fScale / fBias;
|
||||
}
|
||||
|
||||
// Scale to seed range
|
||||
fOutput[x] = fNoise / fScaleAcc;
|
||||
}
|
||||
}
|
||||
|
||||
static int perlinSize = 10000;
|
||||
static float* perlinSeed;
|
||||
static float* perlinOutput;
|
||||
|
||||
void SetupPerlin()
|
||||
{
|
||||
perlinSeed = (float*)malloc(sizeof(float) * perlinSize);
|
||||
perlinOutput = (float*)malloc(sizeof(float) * perlinSize);
|
||||
for (int i = 0; i < perlinSize; i++)
|
||||
perlinSeed[i] = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
|
||||
|
||||
PerlinNoise1D(perlinSize, perlinSeed, 8, 2.0f, perlinOutput);
|
||||
}
|
||||
|
||||
float GetNextPerlin()
|
||||
{
|
||||
static int i = 0;
|
||||
i++;
|
||||
if (i > perlinSize)
|
||||
i = 0;
|
||||
return perlinOutput[i];
|
||||
}
|
||||
|
||||
|
||||
Dungeon::Dungeon()
|
||||
: _Logger(Logger::getInstance())
|
||||
{
|
||||
SetupPerlin();
|
||||
|
||||
ActiveCamera = new Camera();
|
||||
ActiveCamera->Coords = { 0, 0 };
|
||||
ActiveCamera->ViewPort = { 1280, 720 };
|
||||
@@ -21,7 +80,45 @@ Dungeon::Dungeon()
|
||||
Player->Type = EEntity::Type::Player;
|
||||
// Relative to player TL corner
|
||||
// not really used ? lol
|
||||
Player->HitBox = new Collider{ 0, 0, static_cast<int>((static_cast<float>(TileSize) / 3.0f) * 2.0f), static_cast<int>((static_cast<float>(TileSize) / 3.0f) * 2.0f) } ;
|
||||
Player->HitBox = new Collider{ 0, 0, 28, 36 } ;
|
||||
|
||||
Player->Renderable = new olc::Renderable();
|
||||
Player->Renderable->Load("res/player.png");
|
||||
Player->Animator = new olc::AnimatedSprite();
|
||||
Player->Animator->mode = olc::AnimatedSprite::SPRITE_MODE::SINGLE;
|
||||
Player->Animator->type = olc::AnimatedSprite::SPRITE_TYPE::DECAL;
|
||||
Player->Animator->spriteSheet = Player->Renderable;
|
||||
Player->Animator->SetSpriteSize({28, 36});
|
||||
|
||||
Player->Animator->AddState("idle", std::vector<olc::vi2d>{
|
||||
{28, 0}
|
||||
});
|
||||
|
||||
Player->Animator->AddState("north", std::vector<olc::vi2d>{
|
||||
{0, 110},
|
||||
{28, 110},
|
||||
{56, 110},
|
||||
{84, 110}
|
||||
});
|
||||
Player->Animator->AddState("east", std::vector<olc::vi2d>{
|
||||
{0, 36},
|
||||
{28, 36},
|
||||
{56, 36},
|
||||
{84, 36}
|
||||
});
|
||||
Player->Animator->AddState("south", std::vector<olc::vi2d>{
|
||||
{0, 0},
|
||||
{28, 0},
|
||||
{56, 0},
|
||||
{84, 0}
|
||||
});
|
||||
Player->Animator->AddState("west", std::vector<olc::vi2d>{
|
||||
{0, 72},
|
||||
{28, 72},
|
||||
{56, 72},
|
||||
{84, 72}
|
||||
});
|
||||
Player->Animator->SetState("idle");
|
||||
|
||||
ActiveCamera->TrackEntity(Player);
|
||||
ActiveCamera->Update(0.0f);
|
||||
@@ -193,38 +290,76 @@ void Dungeon::SpawnEntity(Entity* entity)
|
||||
|
||||
void Dungeon::Input(olc::PixelGameEngine* engine, float fTime)
|
||||
{
|
||||
|
||||
olc::vf2d oldCoords = Player->Coords;
|
||||
|
||||
static std::string state = "idle";
|
||||
static std::string lastState = "idle";
|
||||
|
||||
if (engine->GetKey(olc::W).bHeld)
|
||||
{
|
||||
Player->Coords.y -= static_cast<float>(TileSize) * (fTime * Player->Speed);
|
||||
if (state != "north")
|
||||
state = "north";
|
||||
}
|
||||
if (engine->GetKey(olc::A).bHeld)
|
||||
{
|
||||
Player->Coords.x -= static_cast<float>(TileSize) * (fTime * Player->Speed);
|
||||
if (state != "west")
|
||||
state = "west";
|
||||
}
|
||||
if (engine->GetKey(olc::S).bHeld)
|
||||
{
|
||||
Player->Coords.y += static_cast<float>(TileSize) * (fTime * Player->Speed);
|
||||
if (state != "south")
|
||||
state = "south";
|
||||
}
|
||||
if (engine->GetKey(olc::D).bHeld)
|
||||
{
|
||||
Player->Coords.x += static_cast<float>(TileSize) * (fTime * Player->Speed);
|
||||
if (state != "east")
|
||||
state = "east";
|
||||
}
|
||||
|
||||
if (engine->GetKey(olc::W).bHeld && engine->GetKey(olc::A).bHeld)
|
||||
{
|
||||
Player->Coords.y += static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
Player->Coords.x += static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
if (state != "west")
|
||||
state = "west";
|
||||
|
||||
}
|
||||
if (engine->GetKey(olc::W).bHeld && engine->GetKey(olc::D).bHeld)
|
||||
{
|
||||
Player->Coords.y += static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
Player->Coords.x -= static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
if (state != "east")
|
||||
state = "east";
|
||||
|
||||
}
|
||||
if (engine->GetKey(olc::S).bHeld && engine->GetKey(olc::D).bHeld)
|
||||
{
|
||||
Player->Coords.y -= static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
Player->Coords.x -= static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
if (state != "east")
|
||||
state = "east";
|
||||
}
|
||||
if (engine->GetKey(olc::S).bHeld && engine->GetKey(olc::A).bHeld)
|
||||
{
|
||||
Player->Coords.y -= static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
Player->Coords.x += static_cast<float>(TileSize) * (fTime * (Player->Speed / 3.0f));
|
||||
if (state != "west")
|
||||
state = "west";
|
||||
}
|
||||
|
||||
if (oldCoords == Player->Coords)
|
||||
state = "idle";
|
||||
if (state != lastState)
|
||||
Player->Animator->SetState(state);
|
||||
lastState = state;
|
||||
|
||||
|
||||
|
||||
// Map collisions
|
||||
olc::vi2d currentTile = { static_cast<int>(Player->Coords.x / TileSize), static_cast<int>(Player->Coords.y / TileSize) };
|
||||
|
||||
@@ -304,7 +439,7 @@ olc::Pixel pixelMultiply(const int x, const int y, const olc::Pixel& pSource, co
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Dungeon::Draw(olc::PixelGameEngine* engine)
|
||||
void Dungeon::Draw(olc::PixelGameEngine* engine, float fTime)
|
||||
{
|
||||
// Maps not gonna be big enough for me to care about optimistaion
|
||||
// maybe i should care? i don't
|
||||
@@ -312,57 +447,65 @@ void Dungeon::Draw(olc::PixelGameEngine* engine)
|
||||
// Entities are always (tilesize / 3) * 2
|
||||
|
||||
// Dungeon Layer
|
||||
engine->SetDrawTarget(4);
|
||||
engine->SetDrawTarget(3);
|
||||
engine->Clear({38, 36, 40});
|
||||
|
||||
engine->SetPixelMode(olc::Pixel::ALPHA);
|
||||
for (std::pair<olc::vi2d, Tile*> tile : DungeonTiles)
|
||||
{
|
||||
// if (tile.second->Type == ETile::Type::Void) continue;
|
||||
|
||||
engine->DrawPartialDecal({ static_cast<float>((tile.first.x * TileSize) - ActiveCamera->Coords.x), static_cast<float>((tile.first.y * TileSize) - ActiveCamera->Coords.y) },
|
||||
{ static_cast<float>(TileSize), static_cast<float>(TileSize) }, TileSet->Decal(), TileSetDictionary->Dictionary[tile.second->Type], { 16, 16 });
|
||||
}
|
||||
|
||||
// engine->SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
// Entity Layer
|
||||
engine->SetDrawTarget(3);
|
||||
engine->SetDrawTarget(2);
|
||||
engine->Clear(olc::BLANK);
|
||||
|
||||
// Draw character
|
||||
engine->DrawPartialDecal({ static_cast<float>(Player->Coords.x - ActiveCamera->Coords.x), static_cast<float>(Player->Coords.y - ActiveCamera->Coords.y) },
|
||||
{ (static_cast<float>(TileSize) / 3.0f) * 2.0f, (static_cast<float>(TileSize) / 3.0f) * 2.0f }, TileSet->Decal(), { 143, 130 }, { 16, 16 });
|
||||
Player->Animator->Draw(fTime, {Player->Coords.x - ActiveCamera->Coords.x, Player->Coords.y - ActiveCamera->Coords.y});
|
||||
|
||||
// Lighting layers
|
||||
engine->SetDrawTarget(2);
|
||||
engine->SetDrawTarget(1);
|
||||
engine->Clear(olc::BLANK);
|
||||
|
||||
static std::function<olc::Pixel(const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest)> fPixelMultiply = pixelMultiply;
|
||||
|
||||
float lightX = static_cast<float>(Player->Coords.x - ActiveCamera->Coords.x) - (FireOverlay->Sprite()->width / 2.0f);
|
||||
float lightY = static_cast<float>(Player->Coords.y - ActiveCamera->Coords.y) - (FireOverlay->Sprite()->height / 2.0f);
|
||||
// loads to make it more chaotic
|
||||
float lightScale = 1.4f + GetNextPerlin(); GetNextPerlin(); GetNextPerlin(); GetNextPerlin(); GetNextPerlin();
|
||||
|
||||
float lightLeft = lightX;
|
||||
float lightRight = lightX + FireOverlay->Sprite()->width;
|
||||
float lightTop = lightY;
|
||||
float lightBottom = lightY + FireOverlay->Sprite()->height;
|
||||
float lightX = static_cast<float>(Player->Coords.x - ActiveCamera->Coords.x) - ((FireOverlay->Sprite()->width * lightScale) / 2.0f);
|
||||
float lightY = static_cast<float>(Player->Coords.y - ActiveCamera->Coords.y) - ((FireOverlay->Sprite()->height * lightScale) / 2.0f);
|
||||
|
||||
float lightLeft = lightX + 1.0f;
|
||||
float lightRight = lightX + FireOverlay->Sprite()->width * lightScale - 1.0f;
|
||||
float lightTop = lightY + 1.0f;
|
||||
float lightBottom = lightY + FireOverlay->Sprite()->height * lightScale - 1.0f;
|
||||
|
||||
// orange tint
|
||||
engine->FillRectDecal({0.0f, 0.0f}, {static_cast<float>(engine->ScreenWidth()), static_cast<float>(engine->ScreenHeight())}, olc::Pixel(255, 123, 0, 30));
|
||||
|
||||
engine->SetPixelMode(fPixelMultiply);
|
||||
engine->DrawDecal({ lightX, lightY }, FireOverlay->Decal());
|
||||
|
||||
engine->SetDrawTarget(1);
|
||||
engine->Clear(olc::BLANK);
|
||||
// top
|
||||
|
||||
engine->FillRect({0, static_cast<int>(lightTop)}, {engine->ScreenWidth(), engine->ScreenHeight()}, olc::BLACK);
|
||||
engine->DrawDecal({ lightX, lightY }, FireOverlay->Decal(), {lightScale, lightScale}, olc::RED);
|
||||
engine->SetPixelMode(olc::Pixel::ALPHA);
|
||||
|
||||
// top
|
||||
engine->FillRectDecal({0.0f, 0.0f}, {static_cast<float>(engine->ScreenWidth()), lightTop}, olc::BLACK);
|
||||
// right
|
||||
engine->FillRectDecal({lightRight, 0.0f}, {static_cast<float>(engine->ScreenWidth()) - lightRight, static_cast<float>(engine->ScreenHeight())}, olc::BLACK);
|
||||
// bottom
|
||||
engine->FillRectDecal({0.0f, lightBottom}, {static_cast<float>(engine->ScreenWidth()), static_cast<float>(engine->ScreenHeight()) - lightBottom}, olc::BLACK);
|
||||
// left
|
||||
engine->FillRectDecal({0.0f, 0.0f}, {lightLeft, static_cast<float>(engine->ScreenHeight())}, olc::BLACK);
|
||||
|
||||
}
|
||||
|
||||
Dungeon::~Dungeon()
|
||||
{
|
||||
delete Player->HitBox;
|
||||
delete Player->Renderable;
|
||||
delete Player->Animator;
|
||||
delete Player;
|
||||
|
||||
delete ActiveCamera;
|
||||
delete TileSetDictionary;
|
||||
delete TileSet;
|
||||
@@ -372,4 +515,7 @@ Dungeon::~Dungeon()
|
||||
delete entity.second;
|
||||
for (std::pair<olc::vi2d, FixedItem*> entity : FixedItems)
|
||||
delete entity.second;
|
||||
|
||||
free(perlinSeed);
|
||||
free(perlinOutput);
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ class Dungeon
|
||||
|
||||
void Input(olc::PixelGameEngine* engine, float fTime);
|
||||
void Update(olc::PixelGameEngine* engine, float fTime);
|
||||
void Draw(olc::PixelGameEngine* engine);
|
||||
void Draw(olc::PixelGameEngine* engine, float fTime);
|
||||
|
||||
Playable* Player;
|
||||
Playable* Player;
|
||||
Camera* ActiveCamera;
|
||||
|
||||
int TileSize = 64;
|
||||
@@ -41,7 +41,6 @@ class Dungeon
|
||||
|
||||
TileDictionary* TileSetDictionary;
|
||||
olc::Renderable* TileSet;
|
||||
|
||||
olc::Renderable* FireOverlay;
|
||||
|
||||
~Dungeon();
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
<ClInclude Include="Collisions.hpp" />
|
||||
<ClInclude Include="Dungeon.hpp" />
|
||||
<ClInclude Include="Logger.hpp" />
|
||||
<ClInclude Include="olcPGEX_AnimatedSprite.hpp" />
|
||||
<ClInclude Include="olcPixelGameEngine.hpp" />
|
||||
<ClInclude Include="Things.hpp" />
|
||||
<ClInclude Include="UI.hpp" />
|
||||
|
||||
@@ -59,5 +59,8 @@
|
||||
<ClInclude Include="UI.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="olcPGEX_AnimatedSprite.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <array>
|
||||
|
||||
#include "olcPixelGameEngine.hpp"
|
||||
#include "olcPGEX_AnimatedSprite.hpp"
|
||||
|
||||
class Camera;
|
||||
|
||||
@@ -101,9 +102,10 @@ class Entity
|
||||
olc::vf2d Coords;
|
||||
EEntity::Type Type;
|
||||
Collider* HitBox;
|
||||
// Does not own
|
||||
Camera* TrackingCamera;
|
||||
olc::vf2d SpriteTextureMask;
|
||||
olc::Renderable* SpriteMap;
|
||||
olc::Renderable* Renderable;
|
||||
olc::AnimatedSprite* Animator;
|
||||
};
|
||||
|
||||
class Item : public Entity
|
||||
@@ -122,7 +124,7 @@ class FixedItem : public Entity
|
||||
class Playable : public Entity
|
||||
{
|
||||
public:
|
||||
float Speed = 10.0f;
|
||||
float Speed = 4.0f;
|
||||
int SelectedInventoryItem = 0;
|
||||
std::array<Item*, 6> Inventory;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.hpp"
|
||||
#define OLC_PGEX_ANIMSPR
|
||||
#include "olcPGEX_AnimatedSprite.hpp"
|
||||
|
||||
#include "Dungeon.hpp"
|
||||
|
||||
@@ -60,7 +62,7 @@ class Game : public olc::PixelGameEngine
|
||||
|
||||
_Dungeon->Update(this, fTime);
|
||||
|
||||
_Dungeon->Draw(this);
|
||||
_Dungeon->Draw(this, fTime);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
EnableLayer(i, true);
|
||||
|
||||
354
The Great Machine/olcPGEX_AnimatedSprite.hpp
Normal file
354
The Great Machine/olcPGEX_AnimatedSprite.hpp
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
olcPGEX_AnimatedSprite.h
|
||||
|
||||
+-------------------------------------------------------------+
|
||||
| OneLoneCoder Pixel Game Engine Extension |
|
||||
| AnimatedSprites - v2.0.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
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
0xnicholasc - https://github.com/0xnicholasc
|
||||
Moros1138 - https://github.com/Moros1138
|
||||
*/
|
||||
|
||||
#ifndef OLC_PGEX_ANIMATEDSPRITE
|
||||
#define OLC_PGEX_ANIMATEDSPRITE
|
||||
|
||||
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 and playMode
|
||||
void AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector<std::string> 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<olc::vi2d> spriteLocations);
|
||||
// Add state for sprite in SPRITE_MODE::MULTI using the default frameDuration and playMode
|
||||
void AddState(std::string stateName, std::vector<std::string> imagePaths);
|
||||
// Add state for sprite in SPRITE_MODE::SINGLE using the default frameDuration and playMode
|
||||
void AddState(std::string stateName, std::vector<olc::vi2d> spriteLocations);
|
||||
// Set size of sprite
|
||||
void SetSpriteSize(olc::vi2d size);
|
||||
// Get size of sprite
|
||||
olc::vi2d GetSpriteSize();
|
||||
// Set sprite scale factor
|
||||
void SetSpriteScale(float scale);
|
||||
|
||||
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
|
||||
SPRITE_MODE mode = SPRITE_MODE::MULTI;
|
||||
SPRITE_TYPE type = SPRITE_TYPE::SPRITE;
|
||||
Renderable* spriteSheet;
|
||||
|
||||
protected:
|
||||
std::string state;
|
||||
std::map<std::string, std::vector<olc::Sprite*>> multiFrames;
|
||||
std::map<std::string, std::vector<olc::vi2d>> singleFrames;
|
||||
std::map<std::string, std::vector<Renderable*>> multiRenderables;
|
||||
std::map<std::string, float> frameDurations;
|
||||
std::map<std::string, PLAY_MODE> playModes;
|
||||
float frameTimer = 0.0f, spriteScale = 1.0f;
|
||||
int currentFrame;
|
||||
olc::vi2d spriteSize;
|
||||
olc::Sprite* placeholder = nullptr;
|
||||
bool playForward = true;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef OLC_PGEX_ANIMSPR
|
||||
#undef OLC_PGEX_ANIMSPR
|
||||
|
||||
namespace olc
|
||||
{
|
||||
olc::Sprite* AnimatedSprite::GetMultiFrame(float fElapsedTime)
|
||||
{
|
||||
frameTimer += fElapsedTime;
|
||||
|
||||
if (frameTimer >= frameDurations[state]) {
|
||||
frameTimer = 0.0f;
|
||||
|
||||
if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) {
|
||||
currentFrame--;
|
||||
} else {
|
||||
currentFrame++;
|
||||
}
|
||||
|
||||
if (currentFrame >= multiFrames[state].size()) {
|
||||
currentFrame = playModes[state] == PLAY_MODE::LOOP
|
||||
? 0
|
||||
: multiFrames[state].size() - 2;
|
||||
playForward = false;
|
||||
} else if (currentFrame <= 0) {
|
||||
playForward = true;
|
||||
}
|
||||
}
|
||||
|
||||
return multiFrames[state][currentFrame];
|
||||
}
|
||||
|
||||
olc::Decal* AnimatedSprite::GetMultiRenderable(float fElapsedTime)
|
||||
{
|
||||
frameTimer += fElapsedTime;
|
||||
|
||||
if (frameTimer >= frameDurations[state]) {
|
||||
frameTimer = 0.0f;
|
||||
|
||||
if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) {
|
||||
currentFrame--;
|
||||
} else {
|
||||
currentFrame++;
|
||||
}
|
||||
|
||||
if (currentFrame >= multiRenderables[state].size()) {
|
||||
currentFrame = playModes[state] == PLAY_MODE::LOOP
|
||||
? 0
|
||||
: multiRenderables[state].size() - 2;
|
||||
playForward = false;
|
||||
} else if (currentFrame <= 0) {
|
||||
playForward = true;
|
||||
}
|
||||
}
|
||||
|
||||
return multiRenderables[state][currentFrame]->Decal();
|
||||
}
|
||||
|
||||
olc::vi2d AnimatedSprite::GetSingleFrame(float fElapsedTime)
|
||||
{
|
||||
frameTimer += fElapsedTime;
|
||||
|
||||
if (frameTimer >= frameDurations[state]) {
|
||||
frameTimer = 0.0f;
|
||||
|
||||
if (playModes[state] == PLAY_MODE::PING_PONG && !playForward) {
|
||||
currentFrame--;
|
||||
} else {
|
||||
currentFrame++;
|
||||
}
|
||||
|
||||
if (currentFrame >= singleFrames[state].size()) {
|
||||
currentFrame = playModes[state] == PLAY_MODE::LOOP
|
||||
? 0
|
||||
: singleFrames[state].size() - 2;
|
||||
playForward = false;
|
||||
} else if (currentFrame <= 0) {
|
||||
playForward = true;
|
||||
}
|
||||
}
|
||||
|
||||
return singleFrames[state][currentFrame];
|
||||
}
|
||||
|
||||
void AnimatedSprite::SetState(std::string newState)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
AnimatedSprite::AddState(stateName, defaultFrameDuration, PLAY_MODE::LOOP, imgPaths);
|
||||
}
|
||||
|
||||
void AnimatedSprite::AddState(std::string stateName, std::vector<olc::vi2d> spriteLocations)
|
||||
{
|
||||
AnimatedSprite::AddState(stateName, defaultFrameDuration, PLAY_MODE::LOOP, spriteLocations);
|
||||
}
|
||||
|
||||
void AnimatedSprite::AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector<std::string> imgPaths)
|
||||
{
|
||||
for (std::string& path : imgPaths) {
|
||||
if (type == SPRITE_TYPE::SPRITE) {
|
||||
multiFrames[stateName].push_back(new olc::Sprite(path));
|
||||
} else {
|
||||
multiRenderables[stateName].push_back(new Renderable());
|
||||
multiRenderables[stateName].back()->Load(path);
|
||||
}
|
||||
}
|
||||
|
||||
frameDurations[stateName] = frameDuration;
|
||||
playModes[stateName] = mode;
|
||||
}
|
||||
|
||||
void AnimatedSprite::AddState(std::string stateName, float frameDuration, PLAY_MODE mode, std::vector<olc::vi2d> spriteLocations)
|
||||
{
|
||||
for (olc::vi2d& location : spriteLocations) {
|
||||
singleFrames[stateName].push_back(location);
|
||||
}
|
||||
|
||||
frameDurations[stateName] = frameDuration;
|
||||
playModes[stateName] = mode;
|
||||
}
|
||||
|
||||
void AnimatedSprite::SetSpriteSize(olc::vi2d size)
|
||||
{
|
||||
spriteSize = size;
|
||||
if (placeholder != nullptr) {
|
||||
delete placeholder;
|
||||
}
|
||||
placeholder = new olc::Sprite(size.x, size.y);
|
||||
}
|
||||
|
||||
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, 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), 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), tint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
BIN
The Great Machine/res/player.png
Normal file
BIN
The Great Machine/res/player.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
res/player.png
Normal file
BIN
res/player.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Reference in New Issue
Block a user