Revamped animation system
Smoother reloading Added idle atlas for player
This commit is contained in:
parent
90a843946a
commit
846f85f1f6
28 changed files with 836 additions and 302 deletions
6
Resources/animations/bubble_anim.xml
Normal file
6
Resources/animations/bubble_anim.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<animations>
|
||||
<animation name="bubble_idle_anim" type="idle">
|
||||
<FPS>2</FPS>
|
||||
<sprite path="sprites/bubbleoAtlas64.png" frameSize="64.0"/>
|
||||
</animation>
|
||||
</animations>
|
||||
10
Resources/animations/machine_gun_anim.xml
Normal file
10
Resources/animations/machine_gun_anim.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<animations>
|
||||
<animation name="machine_gun_idle_anim" type="idle">
|
||||
<FPS>4</FPS>
|
||||
<sprite path="sprites/machineGunAtlas256.png" frameSize="256.0"/>
|
||||
</animation>
|
||||
<animation name="machine_gun_reload_anim" type="reload">
|
||||
<FPS>2</FPS>
|
||||
<sprite path="sprites/pistolAtlas256.png" frameSize="256.0"/>
|
||||
</animation>
|
||||
</animations>
|
||||
6
Resources/animations/pistol_anim.xml
Normal file
6
Resources/animations/pistol_anim.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<animations>
|
||||
<animation name="pistol_idle_anim" type="idle">
|
||||
<FPS>4</FPS>
|
||||
<sprite path="sprites/pistolAtlas256.png" frameSize="256.0"/>
|
||||
</animation>
|
||||
</animations>
|
||||
11
Resources/animations/player_anim.xml
Normal file
11
Resources/animations/player_anim.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<animations directional="true">
|
||||
<animation name="player_move_anim" type="move">
|
||||
<FPS>7</FPS>
|
||||
<sprite path="sprites/player3AtlasMove64.png" frameSize="64.0"/>
|
||||
</animation>
|
||||
|
||||
<animation name="player_idle_anim" type="idle">
|
||||
<FPS>5</FPS>
|
||||
<sprite path="sprites/player3AtlasIdle64.png" frameSize="64.0"/>
|
||||
</animation>
|
||||
</animations>
|
||||
6
Resources/animations/tmp_enemy_anim.xml
Normal file
6
Resources/animations/tmp_enemy_anim.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<animations>
|
||||
<animation name="tmp_enemy_move_anim" type="move">
|
||||
<FPS>7</FPS>
|
||||
<sprite path="sprites/player2Atlas.png" frameSize="128.0"/>
|
||||
</animation>
|
||||
</animations>
|
||||
|
|
@ -35,18 +35,18 @@
|
|||
</map>
|
||||
<entities>
|
||||
<player x="7" y="5" weapon="shotGun">
|
||||
<sprite file="sprites/player3Atlas.png" framesize="64.0" directional="true"/>
|
||||
<animation name="player_anim"/>
|
||||
</player>
|
||||
<entity x="10" y="3" weapon="pistolGun">
|
||||
<sprite file="sprites/player3Atlas.png" frameSize="64.0" directional="true"/>
|
||||
<animation name="player_anim"/>
|
||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
||||
</entity>
|
||||
<entity x="6" y="3" weapon="pistolGun">
|
||||
<sprite file="sprites/player2Atlas.png" frameSize="128.0"/>
|
||||
<animation name="tmp_enemy_anim"/>
|
||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
||||
</entity>
|
||||
<entity x="5" y="3" weapon="pistolGun">
|
||||
<sprite file="sprites/player2Atlas.png" frameSize="128.0"/>
|
||||
<animation name="tmp_enemy_anim"/>
|
||||
<script file="scripts/ai/grunt_behaviour.lua"/>
|
||||
</entity>
|
||||
</entities>
|
||||
|
|
|
|||
BIN
Resources/sprites/player3AtlasIdle64.png
Normal file
BIN
Resources/sprites/player3AtlasIdle64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
Resources/sprites/player3AtlasMove64.png
Normal file
BIN
Resources/sprites/player3AtlasMove64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<weapons>
|
||||
<weapon name="bubbleGun" fireSpeed="100.0">
|
||||
<bullet sprite="sprites/bubbleoAtlas64.png" animated="true" frameSize="64.0">
|
||||
<weapon name="bubbleGun" fireSpeed="100.0" maxAmmo="40000" clipSize="1000">
|
||||
<bullet anim="bubble_anim">
|
||||
<spread>60</spread>
|
||||
<speed>20.0</speed>
|
||||
<drop>250.0</drop>
|
||||
|
|
@ -11,13 +11,13 @@
|
|||
</bullet>
|
||||
</weapon>
|
||||
|
||||
<weapon name="shotGun" fireSpeed="750.0">
|
||||
<weapon name="shotGun" fireSpeed="750.0" maxAmmo="64" clipSize="4">
|
||||
<script file="scripts/weapons/shotgun_script.lua"/>
|
||||
<sprite file="sprites/machineGunAtlas256.png" animated="true" frameSize="256.0">
|
||||
<animation name="machine_gun_anim">
|
||||
<size x="55.0" y="55.0"/>
|
||||
<offset x="-30.0" y="0.0"/>
|
||||
</sprite>
|
||||
<bullet sprite="sprites/bullet.png" animated="false" frameSize="64.0">
|
||||
</animation>
|
||||
<bullet sprite="sprites/bullet.png">
|
||||
<spread>50</spread>
|
||||
<speed>60.0</speed>
|
||||
<drop>550.0</drop>
|
||||
|
|
@ -26,12 +26,12 @@
|
|||
</bullet>
|
||||
</weapon>
|
||||
|
||||
<weapon name="machineGun" fireSpeed="50.0">
|
||||
<sprite file="sprites/machineGunAtlas256.png" animated="true" frameSize="256.0">
|
||||
<weapon name="machineGun" fireSpeed="50.0" maxAmmo="512" clipSize="64">
|
||||
<animation name="machine_gun_anim">
|
||||
<size x="55.0" y="55.0"/>
|
||||
<offset x="-30.0" y="0.0"/>
|
||||
</sprite>
|
||||
<bullet sprite="sprites/bullet.png" animated="false" frameSize="64.0">
|
||||
</animation>
|
||||
<bullet sprite="sprites/bullet.png">
|
||||
<spread>20</spread>
|
||||
<speed>60.0</speed>
|
||||
<drop>950.0</drop>
|
||||
|
|
@ -40,12 +40,12 @@
|
|||
</bullet>
|
||||
</weapon>
|
||||
|
||||
<weapon name="pistolGun" fireSpeed="750.0">
|
||||
<sprite file="sprites/pistolAtlas256.png" animated="true" frameSize="256.0">
|
||||
<weapon name="pistolGun" fireSpeed="750.0" maxAmmo="512" clipSize="21">
|
||||
<animation name="pistol_anim">
|
||||
<size x="30.0" y="30.0"/>
|
||||
<offset x="0.0" y="0.0"/>
|
||||
</sprite>
|
||||
<bullet sprite="sprites/bullet.png" animated="false" frameSize="64.0">
|
||||
</animation>
|
||||
<bullet sprite="sprites/bullet.png">
|
||||
<spread>5.0</spread>
|
||||
<speed>50.0</speed>
|
||||
<drop>500.0</drop>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ add_executable (YuppleMayham
|
|||
"include/utility/raycaster.h"
|
||||
"include/utility/ftfont.h"
|
||||
"include/utility/direction.h"
|
||||
)
|
||||
"include/graphics/animation.h" "src/graphics/animation.cpp")
|
||||
|
||||
add_custom_command(TARGET YuppleMayham PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Resources/ $<TARGET_FILE_DIR:YuppleMayham>)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <SDL_timer.h>
|
||||
|
||||
#include "graphics/shader.h"
|
||||
|
||||
|
|
@ -19,7 +20,9 @@ public:
|
|||
position(glm::vec3(0.0f)),
|
||||
scale(glm::vec3(1.0f)),
|
||||
rotation(0.0f),
|
||||
speed(20.0f) {};
|
||||
speed(20.0f),
|
||||
entityid(SDL_GetTicks())
|
||||
{};
|
||||
virtual ~Entity() {};
|
||||
|
||||
void setPosition(const glm::vec3& position);
|
||||
|
|
@ -39,6 +42,7 @@ public:
|
|||
const glm::vec2 getFacingDir() const { return glm::vec2(cos(glm::radians(rotation)), sin(glm::radians(rotation))); }
|
||||
const glm::vec3 getCenter() const { return glm::vec3(position.x + (0.5f * scale.x), position.y + (0.5f * scale.y), 0.0f); }
|
||||
const bool getIsMoving() const { return isMoving; }
|
||||
const int getEntityID() const { return entityid; }
|
||||
const std::shared_ptr<PhysicsComponent> getPhysicsComponent() const { return physics; }
|
||||
|
||||
// TODO: right now there is no default behavior, but eventually the Entity class will be expanded to handle physics
|
||||
|
|
@ -53,9 +57,12 @@ protected:
|
|||
float rotation;
|
||||
float speed;
|
||||
|
||||
int entityid;
|
||||
|
||||
std::shared_ptr<PhysicsComponent> physics;
|
||||
|
||||
bool isMoving = false;
|
||||
bool wasMoving = false;
|
||||
bool isRotatable = true;
|
||||
bool flipped = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class EventManager;
|
|||
class GameActor : public Entity
|
||||
{
|
||||
public:
|
||||
GameActor(const std::shared_ptr<Shader>& shader) : Entity(shader) { actorid = SDL_GetTicks(); }
|
||||
GameActor(const std::shared_ptr<Shader>& shader) : Entity(shader) {}
|
||||
~GameActor();
|
||||
|
||||
void addComponent(std::shared_ptr<Component> component);
|
||||
|
|
@ -28,8 +28,7 @@ public:
|
|||
void update(float deltaTime) override;
|
||||
void render(const std::shared_ptr<Camera>& camera) override;
|
||||
|
||||
const std::optional<std::shared_ptr<Weapon>>& getHeldWeapon() const;
|
||||
const int getActorID() const { return actorid; }
|
||||
const std::optional<std::shared_ptr<Weapon>> getHeldWeapon() const;
|
||||
|
||||
void setRotation(const float& rotation) override;
|
||||
|
||||
|
|
@ -52,7 +51,6 @@ private:
|
|||
using component_vector_t = std::vector<std::shared_ptr<Component>>;
|
||||
using weapon_vector_t = std::vector<std::shared_ptr<Weapon>>;
|
||||
|
||||
int actorid;
|
||||
component_vector_t components;
|
||||
weapon_vector_t weapons;
|
||||
size_t currentWeaponIndex = 0;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
class Component;
|
||||
class AnimationSet;
|
||||
class Camera;
|
||||
|
||||
class Bullet : public Entity
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public:
|
|||
Weapon(const WeaponData* data, const std::shared_ptr<Shader>& weaponShader, const std::shared_ptr<Shader>& bulletShader, ResourceManager* resourceManager);
|
||||
|
||||
void setWielder(const std::shared_ptr<GameActor>& wielder) { this->wielder = wielder; }
|
||||
void toggleInfiniteAmmo() { infiniteAmmo = !infiniteAmmo; }
|
||||
void wield() { wielded = true; }
|
||||
void putaway() { wielded = false; }
|
||||
|
||||
|
|
@ -37,16 +38,17 @@ public:
|
|||
void attachScript(const std::shared_ptr<WeaponScript>& script);
|
||||
void hookEventManager(const std::shared_ptr<EventManager>& eventManager);
|
||||
void shoot();
|
||||
void reload();
|
||||
void update(float deltaTime);
|
||||
void render(const std::shared_ptr<Camera>& camera);
|
||||
|
||||
struct BulletData {
|
||||
glm::vec3 origin;
|
||||
glm::vec2 direction;
|
||||
float mass;
|
||||
float sizeMod;
|
||||
float speedMod;
|
||||
float dropMod;
|
||||
float mass = 1.f;
|
||||
float sizeMod = 1.f;
|
||||
float speedMod = 1.f;
|
||||
float dropMod = 1.f;
|
||||
};
|
||||
void onHitCallback(std::shared_ptr<GameActor> target, std::shared_ptr<PhysicsComponent> bullet, const glm::vec2& normal);
|
||||
|
||||
|
|
@ -66,6 +68,12 @@ private:
|
|||
|
||||
glm::vec2 weaponSize;
|
||||
glm::vec2 weaponOffset;
|
||||
// TODO: Add reloading
|
||||
// weaponMag will be unused for now, but we will do a reload animation and reload the weapon eventually
|
||||
Uint16 weaponMag, weaponMagSize, weaponAmmo;
|
||||
bool reloading = false;
|
||||
bool wasReloading = false;
|
||||
bool infiniteAmmo = false;
|
||||
|
||||
float bulletSpeed;
|
||||
float bulletDrop;
|
||||
|
|
|
|||
102
YuppleMayham/include/graphics/animation.h
Normal file
102
YuppleMayham/include/graphics/animation.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#ifndef _H_ANIMATION_H
|
||||
#define _H_ANIMATION_H
|
||||
|
||||
#include <memory>
|
||||
#include <SDL_timer.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "utility/direction.h"
|
||||
|
||||
class SpriteAtlas;
|
||||
class ResourceManager;
|
||||
class EventManager;
|
||||
|
||||
// Each entity will contain animation data,
|
||||
// this data will hold:
|
||||
// name of the animation,
|
||||
// type of animation ie. idle animation, directional, etc.
|
||||
// directory of the animation atlas containing the frames
|
||||
struct AnimationData;
|
||||
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
Animation(const std::shared_ptr<AnimationData>& animData, ResourceManager* resourceManager);
|
||||
|
||||
std::string getName() const { return animName; }
|
||||
std::string getType() const { return animType; }
|
||||
|
||||
void bind();
|
||||
void draw();
|
||||
void draw(Direction dir);
|
||||
|
||||
void play() { isPlaying = true; }
|
||||
void stop() { isPlaying = false; }
|
||||
|
||||
const bool getPlaying() const { return isPlaying; }
|
||||
const bool getDirectional() const { return isDirectional; }
|
||||
const int getCycles() const { return cycles; }
|
||||
|
||||
private:
|
||||
std::string animName;
|
||||
std::string animType;
|
||||
|
||||
std::shared_ptr<SpriteAtlas> spriteAtlas;
|
||||
|
||||
Uint32 elapsedTime = 0;
|
||||
Uint32 lastFrameTick = 0;
|
||||
float FPS;
|
||||
int currentFrame;
|
||||
int cycles;
|
||||
|
||||
bool isDirectional;
|
||||
bool isPlaying;
|
||||
|
||||
// this ticks our frame forward according to ticks passed
|
||||
void frameTick();
|
||||
|
||||
void singleDraw();
|
||||
void directionalDraw(Direction dir);
|
||||
};
|
||||
|
||||
// We will load our animation component with every loaded animation,
|
||||
// this will be the handler for every animation an entity uses
|
||||
class AnimationSet
|
||||
{
|
||||
public:
|
||||
AnimationSet(const int& entityid);
|
||||
AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<std::shared_ptr<AnimationData>> animSet);
|
||||
AnimationSet(const int& entityid, const std::unordered_map<std::string, std::shared_ptr<Animation>>& animations);
|
||||
|
||||
std::shared_ptr<Animation>& operator [](std::string animType) { return anims[animType]; }
|
||||
|
||||
void addAnimation(const std::shared_ptr<Animation> anim) { anims.try_emplace(anim->getType(), anim); }
|
||||
void setAnimation(const std::string& animType) { curAnim = anims[animType]; }
|
||||
|
||||
const int getEntityID() const { return entityid; }
|
||||
const bool getDirectional() const { return isDirectional; }
|
||||
|
||||
void bind();
|
||||
void draw();
|
||||
|
||||
void play() { curAnim->play(); }
|
||||
void stop() { curAnim->stop(); }
|
||||
|
||||
void setFacingDir(Direction& dir) { facing = dir; }
|
||||
|
||||
void attachEventManager(const std::shared_ptr<EventManager>& e);
|
||||
|
||||
private:
|
||||
int entityid;
|
||||
bool isDirectional;
|
||||
|
||||
Direction facing = Direction::Down;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<Animation>> anims;
|
||||
std::shared_ptr<Animation> curAnim;
|
||||
|
||||
std::shared_ptr<EventManager> eventManager;
|
||||
};
|
||||
|
||||
#endif // _H_ANIMATION_H
|
||||
|
|
@ -23,8 +23,6 @@ public:
|
|||
|
||||
void bind();
|
||||
virtual void draw() = 0;
|
||||
virtual void play() = 0;
|
||||
virtual void idle() = 0;
|
||||
|
||||
virtual std::shared_ptr<Sprite> clone() const = 0;
|
||||
protected:
|
||||
|
|
@ -42,8 +40,6 @@ public:
|
|||
~SpriteStatic();
|
||||
|
||||
void draw() override;
|
||||
void play() override { /*unused*/ }
|
||||
void idle() override { /*unused*/ }
|
||||
|
||||
std::shared_ptr<Sprite> clone() const override {
|
||||
return std::make_shared<SpriteStatic>(*this);
|
||||
|
|
@ -66,73 +62,54 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class SpriteAnimated : public Sprite
|
||||
class SpriteAtlas : public Sprite
|
||||
{
|
||||
public:
|
||||
// let's keep texture grids squares, saves everyone time...
|
||||
SpriteAnimated(const char* textureAtlasPath, float frameSize);
|
||||
~SpriteAnimated();
|
||||
|
||||
void draw() override;
|
||||
|
||||
void play() override;
|
||||
void idle() override;
|
||||
|
||||
std::shared_ptr<Sprite> clone() const override {
|
||||
return std::make_shared<SpriteAnimated>(*this);
|
||||
}
|
||||
|
||||
bool isPlaying = false;
|
||||
|
||||
private:
|
||||
void SetupAnimated(float frameSize);
|
||||
|
||||
struct VertexIDs {
|
||||
unsigned VAO, VBO;
|
||||
};
|
||||
unsigned EBO;
|
||||
|
||||
// Vertex array buffer IDs
|
||||
std::vector<VertexIDs> ids;
|
||||
|
||||
int currentFrame = 0;
|
||||
float FPS = 7.5f;
|
||||
Uint32 lastFrameTick = 0;
|
||||
};
|
||||
|
||||
class SpriteDirectionalAnimated : public Sprite
|
||||
{
|
||||
public:
|
||||
SpriteDirectionalAnimated(const char* textureAtlasPath, float frameSize);
|
||||
~SpriteDirectionalAnimated();
|
||||
// let's keep texture grids squares, saves everyone time...
|
||||
SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional = false);
|
||||
~SpriteAtlas();
|
||||
|
||||
void bindFrame(VertexIDs* f);
|
||||
// draw current frame
|
||||
void draw() override;
|
||||
|
||||
void play() override;
|
||||
void idle() override;
|
||||
|
||||
std::shared_ptr<Sprite> clone() const override {
|
||||
return std::make_shared<SpriteDirectionalAnimated>(*this);
|
||||
VertexIDs frame(int index, Direction dir = Direction::None) {
|
||||
if (dir == Direction::None) return singleFrame(index);
|
||||
return dirFrames(dir, index);
|
||||
}
|
||||
|
||||
Direction direction = Direction::Down;
|
||||
void setDirection(Direction& dir) { direction = dir; }
|
||||
bool isPlaying = false;
|
||||
size_t size() { return (isDirectional) ? directionalIDs.size() : singleIDs.size(); }
|
||||
|
||||
std::shared_ptr<Sprite> clone() const override {
|
||||
return std::make_shared<SpriteAtlas>(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
void Setup(float frameSize);
|
||||
void SetupDirectional(float frameSize);
|
||||
|
||||
struct VertexIDs {
|
||||
unsigned VAO, VBO;
|
||||
};
|
||||
unsigned EBO;
|
||||
bool isDirectional;
|
||||
|
||||
std::unordered_map<Direction, VertexIDs> idleIDs;
|
||||
std::unordered_map<Direction, std::vector<VertexIDs>> walkingIDs;
|
||||
VertexIDs* curFrame;
|
||||
|
||||
int currentFrame = 0;
|
||||
float FPS = 7.5f;
|
||||
Uint32 lastFrameTick = 0;
|
||||
VertexIDs singleFrame(int index) const {
|
||||
return (index < 0 || index >= singleIDs.size()) ? singleIDs[0] : singleIDs[index];
|
||||
}
|
||||
|
||||
// return the frame in the direction at the selected index
|
||||
VertexIDs dirFrames(Direction dir, int index) const {
|
||||
return (index < 0 || index >= directionalIDs.at(dir).size()) ? directionalIDs.at(dir)[0] : directionalIDs.at(dir)[index];
|
||||
}
|
||||
|
||||
// Vertex array buffer IDs, if the sprite atlas is non-directional
|
||||
std::vector<VertexIDs> singleIDs;
|
||||
|
||||
// Vertex ids if the sprite atlas is directional
|
||||
std::unordered_map<Direction, std::vector<VertexIDs>> directionalIDs;
|
||||
};
|
||||
|
||||
#endif // _H_SPRITE_H
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#include "graphics/mesh.h"
|
||||
#include "graphics/sprite.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/animation.h"
|
||||
#include "gameplay/ai.h"
|
||||
#include "events.h"
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ public:
|
|||
virtual void idle() = 0;
|
||||
|
||||
int ownerid = 0;
|
||||
private:
|
||||
std::shared_ptr<EventManager> eventManager;
|
||||
};
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ public:
|
|||
}
|
||||
void play() override { /*unused*/ }
|
||||
void idle() override { /*unused*/ }
|
||||
|
||||
|
||||
~MeshComponent() { mesh->~Mesh(); }
|
||||
|
||||
|
|
@ -48,33 +51,16 @@ class SpriteComponent : public Component
|
|||
{
|
||||
public:
|
||||
SpriteComponent(std::shared_ptr<Sprite> sprite) : sprite(sprite), Component(nullptr) {}
|
||||
SpriteComponent(std::shared_ptr<Sprite> sprite, const std::shared_ptr<EventManager>& eventManager) :
|
||||
Component(eventManager), sprite(sprite) {
|
||||
auto directionalSprite = std::dynamic_pointer_cast<SpriteDirectionalAnimated>(sprite);
|
||||
if (directionalSprite)
|
||||
{
|
||||
eventManager->subscribe("OnDirectionChange", [sprite, this](std::shared_ptr<Event> e) {
|
||||
auto directionEvent = std::static_pointer_cast<DirectionChangeEvent>(e);
|
||||
auto directionSprite = std::static_pointer_cast<SpriteDirectionalAnimated>(sprite);
|
||||
if (directionEvent->actorid == ownerid)
|
||||
directionSprite->setDirection(directionEvent->direction);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void bind() override {
|
||||
if (sprite) sprite->bind();
|
||||
}
|
||||
void update() override {}
|
||||
void update() override { /*unused*/ }
|
||||
void render() override {
|
||||
if (sprite) sprite->draw();
|
||||
}
|
||||
void play() override {
|
||||
if (sprite) sprite->play();
|
||||
}
|
||||
void idle() override {
|
||||
if (sprite) sprite->idle();
|
||||
}
|
||||
void play() override { /*unused*/ }
|
||||
void idle() override { /*unused*/ }
|
||||
|
||||
std::shared_ptr<Sprite>& getSprite() { return sprite; }
|
||||
|
||||
|
|
@ -84,6 +70,42 @@ private:
|
|||
std::shared_ptr<Sprite> sprite;
|
||||
};
|
||||
|
||||
class AnimationComponent : public Component
|
||||
{
|
||||
public:
|
||||
AnimationComponent(std::shared_ptr<AnimationSet> animSet) : animSet(animSet), Component(nullptr) {};
|
||||
AnimationComponent(std::shared_ptr<AnimationSet> animSet, const std::shared_ptr<EventManager>& eventManager) :
|
||||
animSet(animSet), Component(nullptr)
|
||||
{
|
||||
this->animSet->attachEventManager(eventManager);
|
||||
}
|
||||
|
||||
void bind() override {
|
||||
if (animSet)
|
||||
animSet->bind();
|
||||
}
|
||||
void update() override {/*unused*/}
|
||||
void render() override {
|
||||
if (animSet)
|
||||
animSet->draw();
|
||||
}
|
||||
void play() override {
|
||||
if (animSet)
|
||||
animSet->play();
|
||||
}
|
||||
void idle() override {
|
||||
if (animSet)
|
||||
animSet->stop();
|
||||
}
|
||||
|
||||
std::shared_ptr<AnimationSet>& getAnimationSet() { return animSet; }
|
||||
|
||||
~AnimationComponent() { }
|
||||
|
||||
private:
|
||||
std::shared_ptr<AnimationSet> animSet;
|
||||
};
|
||||
|
||||
class ShaderComponent : public Component
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
#include <cmath>
|
||||
|
||||
enum class Direction {
|
||||
|
||||
|
||||
None = 0,
|
||||
Down = 1,
|
||||
Right = 2,
|
||||
Left = 3,
|
||||
|
|
|
|||
|
|
@ -44,10 +44,46 @@ public:
|
|||
|
||||
class DirectionChangeEvent : public Event {
|
||||
public:
|
||||
DirectionChangeEvent(const int actorid, Direction direction) : actorid(actorid), direction(direction) {}
|
||||
DirectionChangeEvent(const int entityid, Direction direction) : entityid(entityid), direction(direction) {}
|
||||
std::string getType() const override { return "OnDirectionChange"; }
|
||||
Direction direction;
|
||||
int actorid;
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class EntityMoveEvent : public Event {
|
||||
public:
|
||||
EntityMoveEvent(const int entityid) : entityid(entityid) {}
|
||||
std::string getType() const override { return "OnEntityMove"; }
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class EntityStopEvent : public Event {
|
||||
public:
|
||||
EntityStopEvent(const int entityid) : entityid(entityid) {}
|
||||
std::string getType() const override { return "OnEntityStop"; }
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class EntityReloadEvent : public Event {
|
||||
public:
|
||||
EntityReloadEvent(const int entityid) : entityid(entityid) {}
|
||||
std::string getType() const override { return "OnEntityReload"; }
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class EntityFinishReloadEvent : public Event {
|
||||
public:
|
||||
EntityFinishReloadEvent(const int entityid) : entityid(entityid) {}
|
||||
std::string getType() const override { return "OnEntityFinishReload"; }
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class AnimationFinishedEvent : public Event {
|
||||
public:
|
||||
AnimationFinishedEvent(const int entityid, const std::string animType) : entityid(entityid), animType(animType) {}
|
||||
std::string getType() const override { return "OnAnimationFinished"; }
|
||||
std::string animType;
|
||||
int entityid;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,11 @@
|
|||
#include <cassert>
|
||||
|
||||
class Sprite;
|
||||
class SpriteAtlas;
|
||||
class Shader;
|
||||
class Weapon;
|
||||
class Script;
|
||||
class AnimationSet;
|
||||
class AIScript;
|
||||
class WeaponScript;
|
||||
class TileSet;
|
||||
|
|
@ -25,18 +27,19 @@ public:
|
|||
{
|
||||
xmlLoader->loadWeapons("weapons");
|
||||
xmlLoader->loadScenes("scenes");
|
||||
xmlLoader->loadAnimations("animations");
|
||||
};
|
||||
|
||||
std::shared_ptr<Sprite> loadSpriteAnimated (const std::string& path, float frameSize);
|
||||
std::shared_ptr<Sprite> loadSpriteDirAnimated (const std::string& path, float frameSize);
|
||||
std::shared_ptr<SpriteAtlas> loadSpriteAtlas (const std::string& path, float frameSize, bool isDirectional = false);
|
||||
std::shared_ptr<Sprite> loadSpriteStatic (const std::string& path);
|
||||
std::shared_ptr<AIScript> loadAIScript (const std::string& path);
|
||||
std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path);
|
||||
std::shared_ptr<TileSet> loadTileSet (const std::string& path, float frameSize);
|
||||
|
||||
std::shared_ptr<Shader> loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath);
|
||||
std::shared_ptr<Weapon> loadWeapon (const std::string& name, std::shared_ptr<Shader> weaponShader, std::shared_ptr<Shader> bulletShader);
|
||||
std::shared_ptr<SceneData> loadScene (const std::string& id);
|
||||
std::shared_ptr<Shader> loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath);
|
||||
std::shared_ptr<Weapon> loadWeapon (const std::string& name, std::shared_ptr<Shader> weaponShader, std::shared_ptr<Shader> bulletShader);
|
||||
std::shared_ptr<SceneData> loadScene (const std::string& id);
|
||||
std::shared_ptr<AnimationSet> loadAnimationSet(const std::string& name, int entityid = 0);
|
||||
|
||||
void clearResources();
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@ struct Tile;
|
|||
|
||||
struct EntityData {
|
||||
bool isPlayer;
|
||||
bool animated;
|
||||
int x = 0, y = 0;
|
||||
std::string sprite;
|
||||
float frameSize = 0.f;
|
||||
std::string graphic;
|
||||
std::string weapon = "pistolGun";
|
||||
std::string script;
|
||||
bool isDirectional = false;
|
||||
};
|
||||
|
||||
struct MapData {
|
||||
|
|
@ -37,26 +36,44 @@ struct SceneData {
|
|||
struct WeaponData {
|
||||
std::string name;
|
||||
float fireSpeed = 250.0f;
|
||||
int clipSize = 21;
|
||||
int maxAmmo = 512;
|
||||
std::string script = "";
|
||||
std::string sprite;
|
||||
std::string graphic;
|
||||
std::string animSet;
|
||||
bool animated = false;
|
||||
float frameSize;
|
||||
float sizeX = 50.f, sizeY = 50.f;
|
||||
float offsetX = 0.f, offsetY = 0.f;
|
||||
float bulletFrameSize;
|
||||
float bulletSizeX = 50.f, bulletSizeY = 50.f;
|
||||
std::string bulletSprite;
|
||||
std::string bulletGraphic;
|
||||
bool bulletAnimated = false;
|
||||
float bulletSpread = 1.0f, bulletSpeed = 3.0f, bulletDrop = 500.f;
|
||||
float modMin = 0.5f, modMax = 1.0f;
|
||||
};
|
||||
|
||||
struct AnimationData {
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::string spriteAtlas;
|
||||
// Each entity will have a set of animations,
|
||||
// this animation set is meant to keep each group
|
||||
// of animations within their set.
|
||||
// The actual set name is based on the file the animation
|
||||
// is held in.
|
||||
std::string animSet;
|
||||
bool directional = false;
|
||||
bool oneShot;
|
||||
float FPS = 1.f;
|
||||
float frameSize;
|
||||
};
|
||||
|
||||
class XMLLoader
|
||||
{
|
||||
public:
|
||||
XMLLoader() {}
|
||||
bool loadScenes(const char* sceneFolder);
|
||||
bool loadWeapons(const char* weaponFolder);
|
||||
bool loadAnimations(const char* animationFolder);
|
||||
|
||||
const std::shared_ptr<SceneData> getSceneData(const std::string& id) const {
|
||||
try {
|
||||
|
|
@ -66,15 +83,39 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<AnimationData> getAnimationData(const std::string& name) const {
|
||||
try {
|
||||
return animations.at(name);
|
||||
}
|
||||
catch (std::exception&) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// return a full set of animations, may need further optimization.
|
||||
// one idea is when loading animations we create a seperate map that holds each set by their reference, so we can just do a simple,
|
||||
// hash table lookup.
|
||||
std::vector<std::shared_ptr<AnimationData>> getAnimationSet(const std::string& set) const {
|
||||
std::vector<std::shared_ptr<AnimationData>> animSet;
|
||||
animSet.reserve(animations.size());
|
||||
for (const auto& [name, anim] : animations) {
|
||||
if (anim->animSet == set) animSet.push_back(anim);
|
||||
}
|
||||
animSet.shrink_to_fit();
|
||||
return animSet;
|
||||
}
|
||||
|
||||
const WeaponData* getWeaponDataByName(const char* name) const;
|
||||
|
||||
void clearData() { scenes.clear(); weaponData.clear(); }
|
||||
void clearData() { scenes.clear(); weaponData.clear(); animations.clear(); }
|
||||
protected:
|
||||
bool loadXmlScene(const char* xmlFile, SceneData* out);
|
||||
bool loadMap(const char* xmlFile, SceneData* out);
|
||||
bool loadEntityData(const char* xmlFile, SceneData* out);
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<SceneData>> scenes;
|
||||
std::unordered_map<std::string, std::shared_ptr<AnimationData>> animations;
|
||||
|
||||
std::vector<WeaponData> weaponData;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ GameActor::~GameActor() { }
|
|||
|
||||
void GameActor::addComponent(std::shared_ptr<Component> component)
|
||||
{
|
||||
component->ownerid = actorid;
|
||||
component->ownerid = entityid;
|
||||
components.push_back(component);
|
||||
}
|
||||
|
||||
const std::optional<std::shared_ptr<Weapon>>& GameActor::getHeldWeapon() const
|
||||
const std::optional<std::shared_ptr<Weapon>> GameActor::getHeldWeapon() const
|
||||
{
|
||||
return (weapons.empty() || currentWeaponIndex >= weapons.size()) ? std::nullopt : std::make_optional(weapons[currentWeaponIndex]);
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ void GameActor::pickupWeapon(std::shared_ptr<Weapon> weapon)
|
|||
{
|
||||
weapon->setWielder(std::shared_ptr<GameActor>(this));
|
||||
weapons.push_back(weapon);
|
||||
// wield the newly picked up weapon.
|
||||
getHeldWeapon().value()->putaway();
|
||||
currentWeaponIndex = weapons.size() - 1;
|
||||
getHeldWeapon().value()->wield();
|
||||
|
|
@ -40,7 +41,7 @@ void GameActor::setRotation(const float& rotation)
|
|||
if (!isRotatable && eventManager) {
|
||||
Direction newDir = getDirectionFromRotation(rotation);
|
||||
if (getDirectionFromRotation(this->rotation) != newDir)
|
||||
eventManager->notify(std::make_shared<DirectionChangeEvent>(actorid, newDir));
|
||||
eventManager->notify(std::make_shared<DirectionChangeEvent>(entityid, newDir));
|
||||
}
|
||||
this->rotation = rotation;
|
||||
updateModelMatrix();
|
||||
|
|
@ -54,24 +55,36 @@ void GameActor::update(float deltaTime)
|
|||
component->update();
|
||||
for (auto& weapon : weapons)
|
||||
weapon->update(deltaTime);
|
||||
|
||||
if (eventManager)
|
||||
{
|
||||
if (isMoving && !wasMoving)
|
||||
{
|
||||
eventManager->notify(std::make_shared<EntityMoveEvent>(entityid));
|
||||
wasMoving = true;
|
||||
}
|
||||
else if (!isMoving && wasMoving)
|
||||
{
|
||||
eventManager->notify(std::make_shared<EntityStopEvent>(entityid));
|
||||
wasMoving = false;
|
||||
}
|
||||
}
|
||||
isMoving = false;
|
||||
}
|
||||
|
||||
void GameActor::render(const std::shared_ptr<Camera>& camera)
|
||||
{
|
||||
Entity::render(camera);
|
||||
|
||||
// regular loop through components, but if the component returns true to kill, we erase it.
|
||||
// Components are always assumed to be smart pointers!
|
||||
for (auto& component : components)
|
||||
{
|
||||
if (isMoving)
|
||||
component->play();
|
||||
else
|
||||
component->idle();
|
||||
component->bind();
|
||||
component->render();
|
||||
}
|
||||
for (auto& weapon : weapons)
|
||||
weapon->render(camera);
|
||||
isMoving = false;
|
||||
}
|
||||
|
||||
void GameActor::moveUp() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f,-1.f, 0.f), 1500.25f); isMoving = true; }
|
||||
|
|
@ -108,7 +121,7 @@ void GameActor::followMouse(const MouseState& mouse_state)
|
|||
float newRotation = glm::degrees(glm::atan(direction.y, direction.x));
|
||||
if (getDirectionFromRotation(rotation) != getDirectionFromRotation(newRotation))
|
||||
if (eventManager)
|
||||
eventManager->notify(std::make_shared<DirectionChangeEvent>(actorid, getDirectionFromRotation(newRotation)));
|
||||
eventManager->notify(std::make_shared<DirectionChangeEvent>(entityid, getDirectionFromRotation(newRotation)));
|
||||
//setRotation(glm::degrees(glm::atan(direction.y, direction.x)));
|
||||
this->rotation = newRotation;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "graphics/tile.h"
|
||||
#include "graphics/sprite.h"
|
||||
#include "graphics/animation.h"
|
||||
|
||||
#include "utility/component.h"
|
||||
#include "utility/xmlloader.h"
|
||||
|
|
@ -57,22 +58,25 @@ void Scene::loadDebugShooterScene()
|
|||
for (EntityData entityData : sceneData->entities)
|
||||
{
|
||||
auto entity = std::make_shared<GameActor>(playerShader);
|
||||
std::shared_ptr<Sprite> entitySprite;
|
||||
// Directional is the kind of sprite sheet we are using, in this case for directional, I have the sprite sheet handle the rotations
|
||||
// instead of just rotating the object, this makes it look quite a bit better from the end user perspective.
|
||||
if (entityData.isDirectional)
|
||||
if (entityData.animated)
|
||||
{
|
||||
entitySprite = resourceManager->loadSpriteDirAnimated(entityData.sprite, entityData.frameSize);
|
||||
auto entityAnimation = resourceManager->loadAnimationSet(entityData.graphic, entity->getEntityID());
|
||||
// because we don't want to have the engine rotate the object based on the entities rotation,
|
||||
// we set the this value to false so we no longer rotate the object.
|
||||
entity->setRotatable(false);
|
||||
if (entityAnimation->getDirectional())
|
||||
entity->setRotatable(false);
|
||||
entity->addComponent(std::make_shared<AnimationComponent>(entityAnimation, eventManager));
|
||||
}
|
||||
else
|
||||
entitySprite = resourceManager->loadSpriteAnimated(entityData.sprite, entityData.frameSize);
|
||||
{
|
||||
auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic);
|
||||
entity->addComponent(std::make_shared<SpriteComponent>(entitySprite));
|
||||
}
|
||||
auto defaultWeapon = resourceManager->loadWeapon("pistolGun", weaponShader, bubbleShader);
|
||||
auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, weaponShader, bubbleShader);
|
||||
|
||||
entity->addComponent(std::make_shared<SpriteComponent>(entitySprite, eventManager));
|
||||
entity->pickupWeapon(defaultWeapon);
|
||||
entity->pickupWeapon(entityWeapon);
|
||||
entity->hookEventManager(eventManager);
|
||||
|
|
@ -80,7 +84,7 @@ void Scene::loadDebugShooterScene()
|
|||
entity->setScale(glm::vec3(mapData.tileSize, mapData.tileSize, 1.f));
|
||||
|
||||
entity->addPhysicsComponent(
|
||||
physicsEngine->createObject(entity->getActorID(),
|
||||
physicsEngine->createObject(entity->getEntityID(),
|
||||
entity->getPosition(),
|
||||
49.0,
|
||||
PhysicsComponent::Collider::Shape::Circle,
|
||||
|
|
@ -107,7 +111,7 @@ void Scene::loadDebugShooterScene()
|
|||
entity->addComponent(std::make_shared<AIComponent>(ai));
|
||||
}
|
||||
}
|
||||
entities.emplace(entity->getActorID(), entity);
|
||||
entities.emplace(entity->getEntityID(), entity);
|
||||
}
|
||||
|
||||
physicsEngine->loadCollisionMap(map->getCollisionMap(), sceneData->map.tileSize);
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
#include "utility/script.h"
|
||||
|
||||
// TODO: Regular clean up, make this mess readable!
|
||||
// TODO: Attach script to weapons, create custom shoot scripts, allowing the addition of shotguns and other whacky things
|
||||
// TODO: Finally just allow the XMLLoader to read the weaponscript supplied and load it into the weapon
|
||||
|
||||
Weapon::Weapon(const WeaponData* data, const std::shared_ptr<Shader>& weaponShader, const std::shared_ptr<Shader>& bulletShader, ResourceManager* resourceManager)
|
||||
:
|
||||
|
|
@ -21,25 +19,28 @@ Weapon::Weapon(const WeaponData* data, const std::shared_ptr<Shader>& weaponShad
|
|||
bulletShader (bulletShader),
|
||||
weaponSize (glm::vec2(data->sizeX, data->sizeY)),
|
||||
weaponOffset (glm::vec2(data->offsetX, data->offsetY)),
|
||||
weaponMagSize (data->clipSize),
|
||||
weaponMag (data->clipSize),
|
||||
weaponAmmo (data->maxAmmo),
|
||||
bulletDrop (data->bulletDrop),
|
||||
bulletSpeed (data->bulletSpeed),
|
||||
bulletSize (glm::vec2(data->bulletSizeX, data->bulletSizeY)),
|
||||
bulletSpread (std::make_shared<UTIL::RandomGenerator>(-data->bulletSpread, data->bulletSpread)),
|
||||
bulletModifer (std::make_shared<UTIL::RandomGenerator>(data->modMin, data->modMax)),
|
||||
fireSpeed (data->fireSpeed),
|
||||
bulletManager (std::make_shared<BulletManager>()),
|
||||
bulletSprite (data->bulletAnimated ?
|
||||
std::make_shared<SpriteComponent>(resourceManager->loadSpriteAnimated(data->bulletSprite, data->bulletFrameSize))
|
||||
: std::make_shared<SpriteComponent>(resourceManager->loadSpriteStatic(data->bulletSprite)))
|
||||
bulletManager (std::make_shared<BulletManager>())
|
||||
{
|
||||
if (data->bulletAnimated)
|
||||
bulletSprite = std::make_shared<AnimationComponent>(resourceManager->loadAnimationSet(data->bulletGraphic, entityid));
|
||||
else
|
||||
bulletSprite = std::make_shared<SpriteComponent>(resourceManager->loadSpriteStatic(data->bulletGraphic));
|
||||
|
||||
if (data->animated)
|
||||
{
|
||||
addComponent(std::make_shared<SpriteComponent>(resourceManager->loadSpriteAnimated(data->sprite, data->frameSize)));
|
||||
for (auto& c : components)
|
||||
c->play();
|
||||
addComponent(std::make_shared<AnimationComponent>(resourceManager->loadAnimationSet(data->graphic, entityid)));
|
||||
}
|
||||
else
|
||||
addComponent(std::make_shared<SpriteComponent>(resourceManager->loadSpriteStatic(data->sprite)));
|
||||
addComponent(std::make_shared<SpriteComponent>(resourceManager->loadSpriteStatic(data->graphic)));
|
||||
this->setScale(glm::vec3(weaponSize.x, weaponSize.y, 1.0f));
|
||||
};
|
||||
|
||||
|
|
@ -47,18 +48,38 @@ void Weapon::addComponent(const std::shared_ptr<Component>& comp) {
|
|||
components.push_back(comp);
|
||||
}
|
||||
|
||||
void Weapon::reload()
|
||||
{
|
||||
// TODO: Create reload event that will be captured by the gun animation set, to start the reloading animation
|
||||
if (eventManager)
|
||||
{
|
||||
eventManager->notify(std::make_shared<EntityReloadEvent>(entityid));
|
||||
reloading = true;
|
||||
if (weaponAmmo < weaponMagSize) {
|
||||
weaponMag = weaponAmmo;
|
||||
weaponAmmo = 0;
|
||||
}
|
||||
else {
|
||||
weaponMag = weaponMagSize;
|
||||
weaponAmmo -= weaponMagSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::shoot()
|
||||
{
|
||||
if (wielder)
|
||||
{
|
||||
Uint32 currentTime = SDL_GetTicks();
|
||||
if (currentTime - lastFireTime >= fireSpeed)
|
||||
if (weaponMag <= 0 && !reloading) reload();
|
||||
if (currentTime - lastFireTime >= fireSpeed && !reloading && weaponMag > 0)
|
||||
{
|
||||
if (!weaponScript || !weaponScript->lua["onShoot"].valid())
|
||||
{
|
||||
// create bullet using this generated data
|
||||
BulletData b = genBulletData();
|
||||
createBullet(b);
|
||||
weaponMag -= 1;
|
||||
}
|
||||
else {
|
||||
auto result = weaponScript->lua["onShoot"]();
|
||||
|
|
@ -67,6 +88,7 @@ void Weapon::shoot()
|
|||
sol::error err = result;
|
||||
std::cerr << "lua error: " << err.what() << std::endl;
|
||||
}
|
||||
weaponMag -= 1;
|
||||
}
|
||||
lastFireTime = currentTime;
|
||||
}
|
||||
|
|
@ -76,6 +98,28 @@ void Weapon::shoot()
|
|||
void Weapon::hookEventManager(const std::shared_ptr<EventManager>& eventManager)
|
||||
{
|
||||
this->eventManager = eventManager;
|
||||
|
||||
for (auto& component : components)
|
||||
{
|
||||
auto animComponent = std::dynamic_pointer_cast<AnimationComponent>(component);
|
||||
if (animComponent != nullptr)
|
||||
{
|
||||
animComponent->getAnimationSet()->attachEventManager(eventManager);
|
||||
}
|
||||
}
|
||||
|
||||
this->eventManager->subscribe("OnAnimationFinished", [&, this](std::shared_ptr<Event> e) {
|
||||
auto animFinished = std::static_pointer_cast<AnimationFinishedEvent>(e);
|
||||
if (animFinished->entityid == entityid && animFinished->animType == "reload")
|
||||
{
|
||||
if (reloading)
|
||||
{
|
||||
reloading = false;
|
||||
wasReloading = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bulletManager->hookEventManager(eventManager);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +154,11 @@ void Weapon::update(float deltaTime)
|
|||
|
||||
for (auto& component : components)
|
||||
component->update();
|
||||
if (eventManager && wasReloading)
|
||||
{
|
||||
wasReloading = false;
|
||||
eventManager->notify(std::make_shared<EntityFinishReloadEvent>(entityid));
|
||||
}
|
||||
}
|
||||
bulletManager->update(deltaTime);
|
||||
}
|
||||
|
|
@ -121,6 +170,7 @@ void Weapon::render(const std::shared_ptr<Camera>& camera)
|
|||
{
|
||||
for (auto& component : components)
|
||||
{
|
||||
component->play();
|
||||
component->bind();
|
||||
component->render();
|
||||
}
|
||||
|
|
@ -185,9 +235,9 @@ Weapon::BulletData Weapon::genBulletData()
|
|||
|
||||
void Weapon::createBullet(const Weapon::BulletData& data)
|
||||
{
|
||||
auto bullet = std::make_shared<Bullet>(wielder->getActorID(), bulletShader, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize);
|
||||
auto bullet = std::make_shared<Bullet>(wielder->getEntityID(), bulletShader, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize);
|
||||
bullet->addComponent(bulletSprite);
|
||||
bullet->addPhysicsComponent(std::make_shared<PhysicsComponent>(PhysicsComponentFactory::makeBullet(wielder->getActorID(), data.origin, data.mass, bulletSize.x / 2)));
|
||||
bullet->addPhysicsComponent(std::make_shared<PhysicsComponent>(PhysicsComponentFactory::makeBullet(wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2)));
|
||||
bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * glm::vec3(data.direction.x, data.direction.y, 0.f) / data.mass;
|
||||
|
||||
if (eventManager)
|
||||
|
|
@ -195,3 +245,22 @@ void Weapon::createBullet(const Weapon::BulletData& data)
|
|||
bulletManager->addBullet(bullet);
|
||||
}
|
||||
|
||||
/*
|
||||
!| SLATED FOR REMOVAL |!
|
||||
|
||||
// Swap the reload animation and the regular weapon animation
|
||||
void Weapon::swapSprites()
|
||||
{
|
||||
//std::swap(weaponSprites.first, weaponSprites.second);
|
||||
}
|
||||
|
||||
void Weapon::checkAndFinishReload()
|
||||
{
|
||||
if (weaponSprites.first->kill() && reloading) {
|
||||
weaponSprites.first->idle();
|
||||
weaponSprites.first->reset();
|
||||
std::swap(weaponSprites.first, weaponSprites.second);
|
||||
reloading = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
181
YuppleMayham/src/graphics/animation.cpp
Normal file
181
YuppleMayham/src/graphics/animation.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
#include "graphics/animation.h"
|
||||
#include "graphics/sprite.h"
|
||||
#include "utility/xmlloader.h"
|
||||
#include "utility/resourcemanager.h"
|
||||
#include "utility/events.h"
|
||||
|
||||
Animation::Animation(const std::shared_ptr<AnimationData>& animData, ResourceManager* resourceManager) :
|
||||
animName(animData->name),
|
||||
animType(animData->type),
|
||||
FPS(animData->FPS),
|
||||
currentFrame(0),
|
||||
cycles(0),
|
||||
isDirectional(animData->directional),
|
||||
isPlaying(isDirectional),
|
||||
spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional))
|
||||
{}
|
||||
|
||||
void Animation::bind()
|
||||
{
|
||||
spriteAtlas->bind();
|
||||
}
|
||||
|
||||
void Animation::draw()
|
||||
{
|
||||
singleDraw();
|
||||
}
|
||||
|
||||
void Animation::draw(Direction dir)
|
||||
{
|
||||
directionalDraw(dir);
|
||||
}
|
||||
|
||||
void Animation::singleDraw()
|
||||
{
|
||||
if (isPlaying)
|
||||
{
|
||||
frameTick();
|
||||
auto frame = spriteAtlas->frame(currentFrame);
|
||||
spriteAtlas->bindFrame(&frame);
|
||||
spriteAtlas->draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto frame = spriteAtlas->frame(0);
|
||||
spriteAtlas->bindFrame(&frame);
|
||||
spriteAtlas->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::directionalDraw(Direction dir)
|
||||
{
|
||||
if (isPlaying)
|
||||
{
|
||||
frameTick();
|
||||
}
|
||||
auto frame = spriteAtlas->frame(currentFrame, dir);
|
||||
spriteAtlas->bindFrame(&frame);
|
||||
spriteAtlas->draw();
|
||||
}
|
||||
|
||||
void Animation::frameTick()
|
||||
{
|
||||
Uint32 currentTime = SDL_GetTicks();
|
||||
elapsedTime = currentTime - lastFrameTick;
|
||||
if (elapsedTime >= 1000.0f / FPS)
|
||||
{
|
||||
if (++currentFrame > spriteAtlas->size() - 1)
|
||||
{
|
||||
currentFrame = 0;
|
||||
cycles += 1;
|
||||
}
|
||||
lastFrameTick = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationSet::AnimationSet(const int& entityid) : entityid(entityid), isDirectional(false) {};
|
||||
AnimationSet::AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<std::shared_ptr<AnimationData>> animSet) : entityid(entityid)
|
||||
{
|
||||
for (const auto& anim : animSet)
|
||||
{
|
||||
anims.try_emplace(anim->type, std::make_shared<Animation>(anim, resourceManager));
|
||||
if (anim->type == "idle")
|
||||
curAnim = anims[anim->type];
|
||||
}
|
||||
// if we don't have an idle animation, we are just gonna set the current animation to the top of the set
|
||||
if (curAnim == nullptr)
|
||||
curAnim = anims[animSet[0]->type];
|
||||
isDirectional = curAnim->getDirectional();
|
||||
}
|
||||
AnimationSet::AnimationSet(const int& entityid, const std::unordered_map<std::string, std::shared_ptr<Animation>>& animations) : entityid(entityid), anims(animations)
|
||||
{
|
||||
for (const auto& [type, anim] : animations)
|
||||
{
|
||||
curAnim = anim;
|
||||
if (type == "idle")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
isDirectional = curAnim->getDirectional();
|
||||
}
|
||||
|
||||
void AnimationSet::attachEventManager(const std::shared_ptr<EventManager>& e)
|
||||
{
|
||||
eventManager = e;
|
||||
|
||||
eventManager->subscribe("OnDirectionChange", [this](std::shared_ptr<Event> e) {
|
||||
auto directionEvent = std::static_pointer_cast<DirectionChangeEvent>(e);
|
||||
if (directionEvent->entityid == entityid)
|
||||
setFacingDir(directionEvent->direction);
|
||||
});
|
||||
|
||||
eventManager->subscribe("OnEntityMove", [this](std::shared_ptr<Event> e) {
|
||||
auto moveEvent = std::static_pointer_cast<EntityMoveEvent>(e);
|
||||
if (moveEvent->entityid == entityid)
|
||||
{
|
||||
if (isDirectional)
|
||||
{
|
||||
if (anims["move"] != NULL)
|
||||
curAnim = anims["move"];
|
||||
}
|
||||
else
|
||||
play();
|
||||
}
|
||||
});
|
||||
|
||||
eventManager->subscribe("OnEntityStop", [this](std::shared_ptr<Event> e) {
|
||||
auto stopEvent = std::static_pointer_cast<EntityStopEvent>(e);
|
||||
if (stopEvent->entityid == entityid)
|
||||
{
|
||||
if (isDirectional)
|
||||
{
|
||||
if (anims["idle"] != NULL)
|
||||
curAnim = anims["idle"];
|
||||
}
|
||||
else
|
||||
stop();
|
||||
}
|
||||
});
|
||||
|
||||
eventManager->subscribe("OnEntityReload", [this](std::shared_ptr<Event> e) {
|
||||
auto reloadEvent = std::static_pointer_cast<EntityReloadEvent>(e);
|
||||
if (reloadEvent->entityid == entityid)
|
||||
{
|
||||
if (anims["reload"] != NULL)
|
||||
curAnim = anims["reload"];
|
||||
}
|
||||
});
|
||||
|
||||
eventManager->subscribe("OnEntityFinishReload", [this](std::shared_ptr<Event> e) {
|
||||
auto reloadEvent = std::static_pointer_cast<EntityFinishReloadEvent>(e);
|
||||
if (reloadEvent->entityid == entityid)
|
||||
{
|
||||
if (anims["idle"] != NULL)
|
||||
curAnim = anims["idle"];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AnimationSet::bind()
|
||||
{
|
||||
curAnim->bind();
|
||||
}
|
||||
|
||||
void AnimationSet::draw()
|
||||
{
|
||||
int lastCycle = curAnim->getCycles();
|
||||
if (curAnim->getDirectional())
|
||||
curAnim->draw(facing);
|
||||
else
|
||||
curAnim->draw();
|
||||
|
||||
// Sending animation events
|
||||
if (eventManager)
|
||||
{
|
||||
// If the animation has cycled, we send this event after every cycle
|
||||
if ((curAnim->getCycles() - lastCycle) > 0)
|
||||
eventManager->notify(std::make_shared<AnimationFinishedEvent>(entityid, curAnim->getType()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,16 +59,21 @@ SpriteStatic::~SpriteStatic()
|
|||
glDeleteVertexArrays(1, &VAO);
|
||||
}
|
||||
|
||||
SpriteAnimated::SpriteAnimated(const char* textureAtlasPath, float frameSize)
|
||||
SpriteAtlas::SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional) : isDirectional(isDirectional), curFrame(nullptr)
|
||||
{
|
||||
EBO = 0;
|
||||
texture = new Texture();
|
||||
texture->loadTexture(textureAtlasPath);
|
||||
if (texture)
|
||||
SetupAnimated(frameSize);
|
||||
{
|
||||
if (!isDirectional)
|
||||
Setup(frameSize);
|
||||
else
|
||||
SetupDirectional(frameSize);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteAnimated::SetupAnimated(float frameSize)
|
||||
void SpriteAtlas::Setup(float frameSize)
|
||||
{
|
||||
int width = texture->getWidth();
|
||||
int height = texture->getHeight();
|
||||
|
|
@ -110,57 +115,44 @@ void SpriteAnimated::SetupAnimated(float frameSize)
|
|||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
ids.push_back({ VAO, VBO });
|
||||
singleIDs.push_back({ VAO, VBO });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteAnimated::draw()
|
||||
void SpriteAtlas::bindFrame(VertexIDs* f)
|
||||
{
|
||||
if (isPlaying)
|
||||
{
|
||||
Uint32 currentTime = SDL_GetTicks();
|
||||
if (currentTime - lastFrameTick >= 1000.f / FPS)
|
||||
{
|
||||
if (++currentFrame > ids.size() - 1)
|
||||
currentFrame = 0;
|
||||
lastFrameTick = currentTime;
|
||||
}
|
||||
glBindVertexArray(ids[currentFrame].VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindVertexArray(ids[0].VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
curFrame = f;
|
||||
}
|
||||
|
||||
void SpriteAnimated::play() { isPlaying = true; }
|
||||
void SpriteAnimated::idle() { isPlaying = false; }
|
||||
void SpriteAtlas::draw()
|
||||
{
|
||||
glBindVertexArray(curFrame->VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
SpriteAnimated::~SpriteAnimated()
|
||||
SpriteAtlas::~SpriteAtlas()
|
||||
{
|
||||
delete texture;
|
||||
glDeleteBuffers(1, &EBO);
|
||||
for (VertexIDs idSet : ids)
|
||||
for (VertexIDs idSet : singleIDs)
|
||||
{
|
||||
glDeleteBuffers(1, &idSet.VBO);
|
||||
glDeleteVertexArrays(1, &idSet.VAO);
|
||||
}
|
||||
auto deleteBufferList = [](std::pair <Direction, std::vector<VertexIDs>> items) {
|
||||
for (VertexIDs v : items.second) {
|
||||
glDeleteBuffers(1, &v.VBO);
|
||||
glDeleteVertexArrays(1, &v.VAO);
|
||||
}
|
||||
};
|
||||
std::for_each(directionalIDs.begin(), directionalIDs.end(), deleteBufferList);
|
||||
singleIDs.clear();
|
||||
directionalIDs.clear();
|
||||
}
|
||||
|
||||
SpriteDirectionalAnimated::SpriteDirectionalAnimated(const char* textureAtlas, float frameSize)
|
||||
{
|
||||
texture = new Texture();
|
||||
texture->loadTexture(textureAtlas);
|
||||
if (texture)
|
||||
Setup(frameSize);
|
||||
}
|
||||
|
||||
void SpriteDirectionalAnimated::Setup(float frameSize)
|
||||
void SpriteAtlas::SetupDirectional(float frameSize)
|
||||
{
|
||||
int width = texture->getWidth();
|
||||
int height = texture->getHeight();
|
||||
|
|
@ -174,10 +166,10 @@ void SpriteDirectionalAnimated::Setup(float frameSize)
|
|||
for (int col = 0; col < frameCols; col++)
|
||||
{
|
||||
Direction dir;
|
||||
// top of the spritesheet is the entities idle directions
|
||||
// then each row is a 4 frame walk cycle of each direction
|
||||
if (row == 0) dir = (Direction)(col + 1);
|
||||
else dir = (Direction)(row);
|
||||
// Directional spritesheets are stored, with an animation for each row,
|
||||
// on the first row we are looking down, then right etc...
|
||||
// refer to utility/direction.h to each index
|
||||
dir = (Direction)(row + 1); // note we add one, since dir: 0 is None, this is for non-directional sprites
|
||||
|
||||
float left = (col) * (frameSize / width);
|
||||
float right = (col + 1) * (frameSize / width);
|
||||
|
|
@ -209,56 +201,7 @@ void SpriteDirectionalAnimated::Setup(float frameSize)
|
|||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
if (row == 0)
|
||||
idleIDs.emplace(std::pair<Direction, VertexIDs>(dir, { VAO, VBO }));
|
||||
else
|
||||
walkingIDs[dir].push_back({ VAO, VBO });
|
||||
directionalIDs[dir].push_back({ VAO, VBO });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteDirectionalAnimated::draw()
|
||||
{
|
||||
if (isPlaying)
|
||||
{
|
||||
Uint32 currentTime = SDL_GetTicks();
|
||||
if (currentTime - lastFrameTick >= 1000.f / FPS)
|
||||
{
|
||||
if (++currentFrame > walkingIDs[direction].size() - 1)
|
||||
currentFrame = 0;
|
||||
lastFrameTick = currentTime;
|
||||
}
|
||||
glBindVertexArray(walkingIDs[direction][currentFrame].VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindVertexArray(idleIDs[direction].VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteDirectionalAnimated::play() { isPlaying = true; }
|
||||
void SpriteDirectionalAnimated::idle() { isPlaying = false; }
|
||||
|
||||
SpriteDirectionalAnimated::~SpriteDirectionalAnimated()
|
||||
{
|
||||
delete texture;
|
||||
glDeleteBuffers(1, &EBO);
|
||||
auto deleteBuffers = [](std::pair<Direction, VertexIDs> item) {
|
||||
glDeleteBuffers(1, &item.second.VBO);
|
||||
glDeleteVertexArrays(1, &item.second.VAO);
|
||||
};
|
||||
auto deleteBufferList = [](std::pair <Direction, std::vector<VertexIDs>> items) {
|
||||
for (VertexIDs v : items.second) {
|
||||
glDeleteBuffers(1, &v.VBO);
|
||||
glDeleteVertexArrays(1, &v.VAO);
|
||||
}
|
||||
};
|
||||
std::for_each(idleIDs.begin(), idleIDs.end(), deleteBuffers);
|
||||
std::for_each(walkingIDs.begin(), walkingIDs.end(), deleteBufferList);
|
||||
idleIDs.clear();
|
||||
walkingIDs.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,23 +5,19 @@
|
|||
#include "utility/script.h"
|
||||
#include "graphics/tiletype.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/animation.h"
|
||||
#include "gameplay/weapons/weapons.h"
|
||||
|
||||
std::shared_ptr<Sprite> ResourceManager::loadSpriteAnimated(const std::string& path, float frameSize)
|
||||
std::shared_ptr<SpriteAtlas> ResourceManager::loadSpriteAtlas(const std::string& path, float frameSize, bool isDirectional)
|
||||
{
|
||||
auto iterator = sprites.find(path);
|
||||
if (iterator != sprites.end())
|
||||
return iterator->second;
|
||||
auto sprite = std::make_shared<SpriteAnimated>(path.c_str(), frameSize);
|
||||
return std::dynamic_pointer_cast<SpriteAtlas>(iterator->second);
|
||||
auto sprite = std::make_shared<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
|
||||
sprites[path] = sprite;
|
||||
return sprite;
|
||||
}
|
||||
|
||||
std::shared_ptr<Sprite> ResourceManager::loadSpriteDirAnimated(const std::string& path, float frameSize)
|
||||
{
|
||||
return std::make_shared<SpriteDirectionalAnimated>(path.c_str(), frameSize);
|
||||
}
|
||||
|
||||
std::shared_ptr<Sprite> ResourceManager::loadSpriteStatic(const std::string& path)
|
||||
{
|
||||
auto iterator = sprites.find(path);
|
||||
|
|
@ -78,6 +74,12 @@ std::shared_ptr<SceneData> ResourceManager::loadScene(const std::string& id)
|
|||
return xmlLoader->getSceneData(id);
|
||||
}
|
||||
|
||||
std::shared_ptr<AnimationSet> ResourceManager::loadAnimationSet(const std::string& name, int entityid)
|
||||
{
|
||||
auto animSetData = xmlLoader->getAnimationSet(name);
|
||||
return std::make_shared<AnimationSet>(entityid, this, animSetData);
|
||||
}
|
||||
|
||||
// this will need some work, but for now where there is only one weapon type we can work with it
|
||||
// TODO: Allow different weapon types!
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -127,50 +127,72 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
|
|||
tinyxml2::XMLElement* playerElement = entities->FirstChildElement("player");
|
||||
if (playerElement == NULL)
|
||||
return false;
|
||||
int x, y;
|
||||
float frameSize = 64.f;
|
||||
bool isDirectional = false;
|
||||
const char* spritePath, * weaponName = "pistolGun";
|
||||
if (playerElement->QueryIntAttribute("x", &x) != tinyxml2::XML_SUCCESS ||
|
||||
playerElement->QueryIntAttribute("y", &y) != tinyxml2::XML_SUCCESS)
|
||||
|
||||
EntityData playData;
|
||||
const char *graphic, *weaponName = "pistolGun";
|
||||
|
||||
if (playerElement->QueryIntAttribute("x", &playData.x) != tinyxml2::XML_SUCCESS ||
|
||||
playerElement->QueryIntAttribute("y", &playData.y) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
playerElement->QueryStringAttribute("weapon", &weaponName);
|
||||
tinyxml2::XMLElement* sprite = playerElement->FirstChildElement("sprite");
|
||||
if (sprite == NULL)
|
||||
return false;
|
||||
if (sprite->QueryStringAttribute("file", &spritePath) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
sprite->QueryFloatAttribute("framesize", &frameSize);
|
||||
sprite->QueryBoolAttribute("directional", &isDirectional);
|
||||
out->entities.push_back({ true, x, y, spritePath, frameSize, weaponName, "", isDirectional});
|
||||
tinyxml2::XMLElement* anim = playerElement->FirstChildElement("animation");
|
||||
if (anim == NULL)
|
||||
{
|
||||
playData.animated = false;
|
||||
tinyxml2::XMLElement* sprite = playerElement->FirstChildElement("sprite");
|
||||
if (sprite == NULL)
|
||||
return false;
|
||||
if (sprite->QueryStringAttribute("file", &graphic) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
playData.animated = true;
|
||||
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
playData.isPlayer = true;
|
||||
playData.graphic = graphic;
|
||||
playData.weapon = weaponName;
|
||||
|
||||
out->entities.push_back(playData);
|
||||
|
||||
// Adding every other entity...
|
||||
// TODO: Add npcs to game and enable their use with XMLLoader
|
||||
|
||||
for (tinyxml2::XMLElement* e = entities->FirstChildElement("entity"); e != NULL; e = e->NextSiblingElement("entity"))
|
||||
{
|
||||
int x, y;
|
||||
float frameSize = 64.f;
|
||||
const char* spritePath, * weaponName = "pistolGun", * scriptPath;
|
||||
bool isDirectional = false;
|
||||
if (e->QueryIntAttribute("x", &x) != tinyxml2::XML_SUCCESS ||
|
||||
e->QueryIntAttribute("y", &y) != tinyxml2::XML_SUCCESS)
|
||||
|
||||
EntityData data;
|
||||
const char *graphic, *weaponName = "pistolGun", *scriptPath;
|
||||
if (e->QueryIntAttribute("x", &data.x) != tinyxml2::XML_SUCCESS ||
|
||||
e->QueryIntAttribute("y", &data.y) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
e->QueryStringAttribute("weapon", &weaponName);
|
||||
tinyxml2::XMLElement* sprite = e->FirstChildElement("sprite");
|
||||
if (sprite == NULL)
|
||||
return false;
|
||||
if (sprite->QueryStringAttribute("file", &spritePath) != tinyxml2::XML_SUCCESS)
|
||||
return false;
|
||||
sprite->QueryFloatAttribute("frameSize", &frameSize);
|
||||
sprite->QueryBoolAttribute("directional", &isDirectional);
|
||||
tinyxml2::XMLElement* script = e->FirstChildElement("script");
|
||||
if (script == NULL || script->QueryStringAttribute("file", &scriptPath))
|
||||
tinyxml2::XMLElement* anim = e->FirstChildElement("animation");
|
||||
if (anim == NULL)
|
||||
{
|
||||
out->entities.push_back({ false, x, y, spritePath, frameSize, weaponName, "", isDirectional });
|
||||
continue;
|
||||
data.animated = false;
|
||||
tinyxml2::XMLElement* sprite = e->FirstChildElement("sprite");
|
||||
if (sprite == NULL)
|
||||
continue;
|
||||
if (sprite->QueryStringAttribute("file", &graphic) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
out->entities.push_back({ false, x, y, spritePath, frameSize, weaponName, scriptPath, isDirectional });
|
||||
else
|
||||
{
|
||||
data.animated = true;
|
||||
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
tinyxml2::XMLElement* script = e->FirstChildElement("script");
|
||||
script->QueryStringAttribute("file", &scriptPath);
|
||||
data.isPlayer = false;
|
||||
data.graphic = graphic;
|
||||
data.script = scriptPath;
|
||||
data.weapon = weaponName;
|
||||
|
||||
out->entities.push_back(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -207,11 +229,13 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
|||
{
|
||||
// populate weapon data into this temp buffer, then push it into our list of weapons
|
||||
WeaponData data;
|
||||
const char* name, * sprite, * bulletSprite, * script;
|
||||
const char *name, *graphic, *bulletGraphic, *script;
|
||||
// Getting top level weapon data, attribs in the weapon Node
|
||||
if (weapon->QueryStringAttribute("name", &name) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
weapon->QueryFloatAttribute("fireSpeed", &data.fireSpeed);
|
||||
weapon->QueryIntAttribute("maxAmmo", &data.maxAmmo);
|
||||
weapon->QueryIntAttribute("clipSize", &data.clipSize);
|
||||
// Getting script file if Node exists
|
||||
tinyxml2::XMLElement* wepScript = weapon->FirstChildElement("script");
|
||||
if (wepScript)
|
||||
|
|
@ -219,13 +243,31 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
|||
else
|
||||
script = "";
|
||||
// Getting weapon sprite information, held in the sprite node
|
||||
tinyxml2::XMLElement* wepSprite = weapon->FirstChildElement("sprite");
|
||||
if (wepSprite)
|
||||
tinyxml2::XMLElement* anim = weapon->FirstChildElement("animation");
|
||||
if (anim)
|
||||
{
|
||||
wepSprite->QueryStringAttribute("file", &sprite);
|
||||
wepSprite->QueryBoolAttribute("animated", &data.animated);
|
||||
if (data.animated)
|
||||
wepSprite->QueryFloatAttribute("frameSize", &data.frameSize);
|
||||
data.animated = true;
|
||||
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (anim->ChildElementCount() != 0)
|
||||
{
|
||||
tinyxml2::XMLElement* size = anim->FirstChildElement("size");
|
||||
size->QueryFloatAttribute("x", &data.sizeX);
|
||||
size->QueryFloatAttribute("y", &data.sizeY);
|
||||
tinyxml2::XMLElement* offset = anim->FirstChildElement("offset");
|
||||
offset->QueryFloatAttribute("x", &data.offsetX);
|
||||
offset->QueryFloatAttribute("y", &data.offsetY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tinyxml2::XMLElement* wepSprite = weapon->FirstChildElement("sprite");
|
||||
if (wepSprite == NULL)
|
||||
continue;
|
||||
|
||||
wepSprite->QueryStringAttribute("file", &graphic);
|
||||
data.animated = false;
|
||||
if (wepSprite->ChildElementCount() != 0)
|
||||
{
|
||||
tinyxml2::XMLElement* size = wepSprite->FirstChildElement("size");
|
||||
|
|
@ -236,31 +278,32 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
|||
offset->QueryFloatAttribute("y", &data.offsetY);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we don't have a sprite element, default to pistol
|
||||
sprite = "sprites/pistolAtlas256.png";
|
||||
data.animated = true;
|
||||
data.frameSize = 256.f;
|
||||
data.sizeX = 30.f;
|
||||
data.sizeY = 30.f;
|
||||
}
|
||||
// getting bullet information held in the bullet node and each child node held therein
|
||||
tinyxml2::XMLElement* bullet = weapon->FirstChildElement("bullet");
|
||||
|
||||
if (bullet->QueryStringAttribute("sprite", &bulletSprite) != tinyxml2::XML_SUCCESS ||
|
||||
bullet->QueryBoolAttribute( "animated", &data.bulletAnimated) != tinyxml2::XML_SUCCESS ||
|
||||
bullet->FirstChildElement("size")->QueryFloatAttribute("x", &data.bulletSizeX) != tinyxml2::XML_SUCCESS ||
|
||||
if (bullet->FindAttribute("anim"))
|
||||
{
|
||||
data.bulletAnimated = true;
|
||||
if (bullet->QueryStringAttribute("anim", &bulletGraphic) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bulletAnimated = false;
|
||||
if (bullet->QueryStringAttribute("sprite", &bulletGraphic) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (bullet->FirstChildElement("size")->QueryFloatAttribute("x", &data.bulletSizeX) != tinyxml2::XML_SUCCESS ||
|
||||
bullet->FirstChildElement("size")->QueryFloatAttribute("y", &data.bulletSizeY) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
|
||||
data.name = name;
|
||||
data.script = script;
|
||||
data.sprite = sprite;
|
||||
data.bulletSprite = bulletSprite;
|
||||
data.graphic = graphic;
|
||||
data.bulletGraphic = bulletGraphic;
|
||||
|
||||
if (data.animated)
|
||||
if (bullet->QueryFloatAttribute("frameSize", &data.bulletFrameSize) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
tinyxml2::XMLElement* spread = bullet->FirstChildElement("spread");
|
||||
tinyxml2::XMLElement* speed = bullet->FirstChildElement("speed");
|
||||
tinyxml2::XMLElement* drop = bullet->FirstChildElement("drop");
|
||||
|
|
@ -281,4 +324,48 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
|
|||
}
|
||||
}
|
||||
return (!weaponData.empty());
|
||||
}
|
||||
|
||||
bool XMLLoader::loadAnimations(const char* animationFolder)
|
||||
{
|
||||
std::filesystem::path folder(animationFolder);
|
||||
if (!std::filesystem::exists(folder) || !std::filesystem::is_directory(folder))
|
||||
return false;
|
||||
for (auto& file : std::filesystem::directory_iterator(folder))
|
||||
{
|
||||
if (!file.path().has_extension() || !file.path().has_filename() || !file.exists() || file.is_directory())
|
||||
continue;
|
||||
tinyxml2::XMLDocument doc;
|
||||
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
tinyxml2::XMLElement* anims = doc.FirstChildElement("animations");
|
||||
bool directional = false;
|
||||
anims->QueryBoolAttribute("directional", &directional);
|
||||
if (anims == NULL)
|
||||
continue;
|
||||
for (tinyxml2::XMLElement* e = anims->FirstChildElement("animation"); e != NULL; e = e->NextSiblingElement("animation"))
|
||||
{
|
||||
AnimationData animData;
|
||||
const char *name, *type, *spriteAtlas;
|
||||
|
||||
if (e->QueryStringAttribute("name", &name) != tinyxml2::XML_SUCCESS ||
|
||||
e->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
tinyxml2::XMLElement* fps = e->FirstChildElement("FPS");
|
||||
fps->QueryFloatText(&animData.FPS);
|
||||
|
||||
tinyxml2::XMLElement* sprite = e->FirstChildElement("sprite");
|
||||
if (sprite->QueryStringAttribute("path", &spriteAtlas) != tinyxml2::XML_SUCCESS ||
|
||||
sprite->QueryFloatAttribute("frameSize", &animData.frameSize) != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
|
||||
animData.name = name;
|
||||
animData.type = type;
|
||||
animData.spriteAtlas = spriteAtlas;
|
||||
animData.animSet = file.path().stem().string();
|
||||
animData.directional = directional;
|
||||
animations.try_emplace(animData.name, std::make_shared<AnimationData>(animData));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue