Simple Boss Example Using SFML and THOR

Hello, and welcome to another exciting installment. In this tutorial, I'll walk you through my approach to designing and implementing a boss for my N.A.S.I.C. game tutorial. Because the details are complex, I decided to move this out of the main level tutorial and into its own.

Moving on, I decided I was getting stale using the same old spritesheet animation techniques I've come to know and love and explore a new path. For the boss fight in N.A.S.I.C., I approached my design of its graphic composition, animation, and behavior as individual pieces. All in all, I found this approach to add tons of charm and novelty to designing your game entities.

 

Here is some footage of our boss "Killer" in action.




 

As you can see, there are a number of things going on here - none of which are complicated in and of themselves - but which cumulatively make Killer who he is.

He has a very simple particle system for exhaust flames, 6 ammunition components consisting of three different types of ammo, eyes with color animation, and mandibles which implement animation of rotation. Killer also moves in a somewhat realistic manner - which uses easing to smooth out his motion.

The design could be improved - I should have used one sf::Texture instance and used the sprite members to take a subrect of the main texture for each component. I didn't feel like merging all the image parts into one png so this was my half-baked solution. It works, but could be cleaner. At any rate, here is the class definition for Killer:


#ifndef KILLER_HPP
#define KILLER_HPP

#include <iostream>
#include <list>
#include <SFML/Graphics.hpp>
#include <particle.hpp>

namespace nasic
{
    class killer : public sf::Drawable, public sf::Transformable
    {
        public:
            killer();

            ~killer();

            void init(sf::RenderWindow& window, float scale);

            sf::Vector2f getAABB()
            {
                m_dimensions = sf::Vector2f(m_helmet.getGlobalBounds().width, m_helmet.getGlobalBounds().height);
                return m_dimensions;
            };

            void updateEyeColor(unsigned int g, unsigned int a);
            void initParticles(int disturbance);
            void updateParticles(sf::Time dt, float scale);

            void animateMandibles(float angle);

            sf::Vector2f leftCannonPosition(){return m_leftCannon.getPosition();};
            sf::Vector2f rightCannonPosition(){return m_rightCannon.getPosition();};
            sf::Vector2f leftEyeLaserPosition(){return sf::Vector2f(m_eyeGlow.getPosition().x + m_eyeGlow.getGlobalBounds().width/5.f, m_eyeGlow.getPosition().y);};
            sf::Vector2f rightEyeLaserPosition(){return sf::Vector2f(m_eyeGlow.getPosition().x + m_eyeGlow.getGlobalBounds().width - m_eyeGlow.getGlobalBounds().width/5.f, m_eyeGlow.getPosition().y);};
            sf::Vector2f leftGunPosition(){return m_leftEarring.getPosition();};
            sf::Vector2f rightGunPosition(){return m_rightEarring.getPosition();};

            sf::Vector2f getTargetPosition(){return sf::Vector2f(m_eyeGlow.getPosition().x, m_eyeGlow.getPosition().y);};
            sf::Vector2f getTargetAABB(){return sf::Vector2f(m_eyeGlow.getSize().x, m_eyeGlow.getSize().y);};

            void damage(int d){m_health -= d;};

            int getHealth(){return m_health;};

            void updateState();

            sf::Uint32 getState(){return m_killerState;};

            sf::Vector2f getPosition() const;

            void move(float offsetX, float offsetY);

            void draw(sf::RenderTarget& target, sf::RenderStates states) const;

        public:
            enum killerState
            {
                normal,
                pissed,
                dead
            };

        private:

            sf::Texture face;
            sf::Texture helmet;
            sf::Texture leftEar;
            sf::Texture rightEar;
            sf::Texture leftMandible;
            sf::Texture rightMandible;
            sf::Texture leftEarring;
            sf::Texture rightEarring;
            sf::Texture leftTooth;
            sf::Texture rightTooth;
            sf::Texture particleTexture;
            nasic::particle m_particle;
            std::list<nasic::particle> particles;
            std::list<nasic::particle>::iterator particleIt;

            sf::Sprite m_face;
            sf::Sprite m_helmet;
            sf::Sprite m_leftEar;
            sf::Sprite m_rightEar;
            sf::Sprite m_leftCannon;
            sf::Sprite m_rightCannon;
            sf::Sprite m_leftTooth;
            sf::Sprite m_rightTooth;
            sf::Sprite m_leftMandible;
            sf::Sprite m_rightMandible;
            sf::Sprite m_leftEarring;
            sf::Sprite m_rightEarring;
            sf::RectangleShape m_eyeGlow;

            sf::Uint32 m_killerState;
            int m_health;
            sf::Vector2f m_dimensions;
    };
}

#endif // KILLER_HPP

Stay tuned for an explanation of the implementation of the Killer class. For now, here is the code:


#include <killer.hpp>

nasic::killer::killer()
{
    m_health = 100;
    m_killerState = killerState::normal;
}

nasic::killer::~killer()
{

}

void nasic::killer::init(sf::RenderWindow& window, float scale)
{

    if(!face.loadFromFile("img/killerFace.png"))
    {
        std::cerr<<"Could not load killerFace.png"<<std::endl;
    }

    if(!helmet.loadFromFile("img/killerHelmet.png"))
    {
        std::cerr<<"Could not load killerHelmet.png"<<std::endl;
    }

    if(!leftEar.loadFromFile("img/killerLeftEar.png"))
    {
        std::cerr<<"Could not load killerLeftEar.png"<<std::endl;
    }

    if(!rightEar.loadFromFile("img/killerRightEar.png"))
    {
        std::cerr<<"Could not load killerRightEar.png"<<std::endl;
    }

    if(!leftEarring.loadFromFile("img/killerLeftEarring.png"))
    {
        std::cerr<<"Could not load killerLeftEarring.png"<<std::endl;
    }

    if(!rightEarring.loadFromFile("img/killerRightEarring.png"))
    {
        std::cerr<<"Could not load killerRightEarring.png"<<std::endl;
    }

    if(!leftMandible.loadFromFile("img/killerLeftMandible.png"))
    {
        std::cerr<<"Could not load killerLeftMandible.png"<<std::endl;
    }

    if(!rightMandible.loadFromFile("img/killerRightMandible.png"))
    {
        std::cerr<<"Could not load killerRightMandible.png"<<std::endl;
    }

    if(!leftTooth.loadFromFile("img/killerLeftTooth.png"))
    {
        std::cerr<<"Could not load killerLeftTooth.png"<<std::endl;
    }

    if(!rightTooth.loadFromFile("img/killerRightTooth.png"))
    {
        std::cerr<<"Could not load killerRightTooth.png"<<std::endl;
    }

    m_face.setTexture(face);
    m_helmet.setTexture(helmet);
    m_leftEar.setTexture(leftEar);
    m_rightEar.setTexture(rightEar);
    m_leftTooth.setTexture(leftTooth);
    m_rightTooth.setTexture(rightTooth);
    m_leftMandible.setTexture(leftMandible);
    m_rightMandible.setTexture(rightMandible);
    m_leftEarring.setTexture(leftEarring);
    m_rightEarring.setTexture(rightEarring);

    m_leftMandible.setOrigin(m_leftMandible.getGlobalBounds().width/2.f, 0.f);
    m_rightMandible.setOrigin(m_rightMandible.getGlobalBounds().width/2.f, 0.f);

    m_face.setScale(scale,scale);
    m_helmet.setScale(scale,scale);
    m_leftEar.setScale(scale,scale);
    m_rightEar.setScale(scale,scale);
    m_leftCannon = m_leftEar;
    m_rightCannon = m_rightEar;
    m_leftTooth.setScale(scale,scale);
    m_rightTooth.setScale(scale,scale);
    m_leftMandible.setScale(scale,scale);
    m_rightMandible.setScale(scale,scale);
    m_leftEarring.setScale(scale,scale);
    m_rightEarring.setScale(scale,scale);

    m_helmet.setPosition(window.getSize().x/5.f, -scale*100.f);
    m_face.setPosition(m_helmet.getPosition().x + m_helmet.getGlobalBounds().width/9.f, m_helmet.getPosition().y + (m_helmet.getGlobalBounds().height * .85f));
    m_leftEar.setPosition(m_face.getPosition().x - m_leftEar.getGlobalBounds().width, m_face.getPosition().y);
    m_rightEar.setPosition(m_face.getPosition().x + m_face.getGlobalBounds().width, m_face.getPosition().y);
    m_leftCannon.setPosition(m_leftEar.getPosition().x - m_leftEar.getGlobalBounds().width/2.f, m_leftEar.getPosition().y - m_leftEar.getGlobalBounds().height/2.f);
    m_rightCannon.setPosition(m_rightEar.getPosition().x + m_rightEar.getGlobalBounds().width/2.f, m_rightEar.getPosition().y - m_rightEar.getGlobalBounds().height/2.f);
    m_leftEarring.setPosition(m_leftEar.getPosition().x, m_leftEar.getPosition().y + m_leftEar.getGlobalBounds().height);
    m_rightEarring.setPosition(m_rightEar.getPosition().x + m_rightEar.getGlobalBounds().width - m_rightEarring.getGlobalBounds().width, m_rightEar.getPosition().y + m_rightEar.getGlobalBounds().height);
    m_leftTooth.setPosition(m_face.getPosition().x + m_face.getGlobalBounds().width/2.f - m_leftTooth.getGlobalBounds().width, m_face.getPosition().y + m_face.getGlobalBounds().height);
    m_rightTooth.setPosition(m_face.getPosition().x + m_face.getGlobalBounds().width/2.f, m_face.getPosition().y + m_face.getGlobalBounds().height);
    m_leftMandible.setPosition(m_face.getPosition().x + m_leftMandible.getGlobalBounds().width/2.f, m_face.getPosition().y + m_face.getGlobalBounds().height);
    m_rightMandible.setPosition(m_face.getPosition().x + m_face.getGlobalBounds().width - m_rightMandible.getGlobalBounds().width/2.f, m_face.getPosition().y + m_face.getGlobalBounds().height);

    m_eyeGlow.setSize(sf::Vector2f(scale*70.f,scale*20.f));
    m_eyeGlow.setFillColor(sf::Color(255,255,0,255));
    m_eyeGlow.setPosition(m_face.getPosition().x + m_face.getGlobalBounds().width*.1f, m_face.getPosition().y + m_face.getGlobalBounds().height*.2f);

    //set up for particles
    if (!particleTexture.loadFromFile("img/particle.png"))
    {
        std::cerr<<"Could not load particle.png"<<std::endl;
    }

    m_particle.setTexture(particleTexture);
    m_particle.setColor(sf::Color(255,255,255,255));
}

void nasic::killer::animateMandibles(float angle)
{
    m_leftMandible.rotate(angle);
    m_rightMandible.rotate(-angle);
}

void nasic::killer::updateEyeColor(unsigned int g, unsigned int a)
{
    m_eyeGlow.setFillColor(sf::Color(255,g,0,a));
}

void nasic::killer::initParticles(int disturbance)
{
    //instantiate as many particles as the frame rate will allow
    m_particle.setPosition(getPosition().x + getAABB().x/4.f + disturbance, getPosition().y + getAABB().y * 1.5f);
    particles.push_back(m_particle);
}

void nasic::killer::updateParticles(sf::Time dt, float scale)
{
    for(particleIt = particles.begin(); particleIt != particles.end(); ++particleIt)
    {
        if(!particleIt->isAlive())
            particleIt = particles.erase(particleIt);
        else
        {
            particleIt->move(0.f, scale*2.f);
            particleIt->decAlpha(dt);
        }
    }
}

void nasic::killer::updateState()
{
    if(m_health > 30)
        m_killerState = killerState::normal;
    else if(m_health < 30 && m_health > 0)
        m_killerState = killerState::pissed;
    else if(m_health <= 0)
        m_killerState = killerState::dead;
}

void nasic::killer::move(float offsetX, float offsetY)
{
    m_helmet.move(offsetX, offsetY);
    m_face.move(offsetX, offsetY);
    m_leftEar.move(offsetX, offsetY);
    m_rightEar.move(offsetX, offsetY);
    m_leftCannon.move(offsetX, offsetY);
    m_rightCannon.move(offsetX, offsetY);
    m_leftEarring.move(offsetX, offsetY);
    m_rightEarring.move(offsetX, offsetY);
    m_leftTooth.move(offsetX, offsetY);
    m_rightTooth.move(offsetX, offsetY);
    m_leftMandible.move(offsetX, offsetY);
    m_rightMandible.move(offsetX, offsetY);
    m_eyeGlow.move(offsetX, offsetY);
}

sf::Vector2f nasic::killer::getPosition()const
{
    return m_helmet.getPosition();
}

void nasic::killer::draw(sf::RenderTarget& target, sf::RenderStates states)const
{
    //draw particles
    std::list<nasic::particle>::const_iterator partIt;
    if(particles.size() > 0)
    {
        for(partIt = particles.begin(); partIt != particles.end(); ++partIt)
        {
            target.draw(*partIt, states);
        }
    }

    target.draw(m_eyeGlow,states);
    target.draw(m_face,states);
    target.draw(m_helmet,states);
    target.draw(m_leftEar,states);
    target.draw(m_rightEar,states);
    target.draw(m_leftCannon,states);
    target.draw(m_rightCannon,states);
    target.draw(m_leftTooth,states);
    target.draw(m_rightTooth,states);
    target.draw(m_leftMandible,states);
    target.draw(m_rightMandible,states);
    target.draw(m_leftEarring,states);
    target.draw(m_rightEarring,states);

    states.transform *= getTransform();
}

And here is a minimal example which utilizes the Killer class and implements the ammunition aspects of the boss - which I chose to separate from the Killer class to make other aspects of the creation of a level easier to follow (i.e. instantiation of the projectiles, handling of position updates, and collision detection). I may change this in the near future, I have not decided yet.


#include <iostream>
#include <random>
#include <list>
#include <SFML/Graphics.hpp>
#include <Thor/Math/Distributions.hpp>
#include <interpolate.hpp>
#include <killer.hpp>
#include <ammo.hpp>
#include <particle.hpp>
#include <killer.hpp>

int main(void)
{
    sf::RenderWindow window;

    //current fullscreen video mode
    sf::VideoMode mode = sf::VideoMode::getDesktopMode();

    //create scale vars based on a denominator of 800x600 displays
    //works for this purpose, but may be less than ideal for many cases
    float m_scaleX = mode.width/800.f;
    float m_scaleY = mode.height/600.f;

    float m_winsizeX = mode.width;
    float m_winsizeY = mode.height;

    //info about the available fullscreen video modes
    std::vector<sf::VideoMode> modes = mode.getFullscreenModes();
    for (std::size_t i = 0; i < modes.size(); ++i)
    {
        sf::VideoMode mode = modes[i];
        std::cout << "Mode #" << i << ": "
                  << mode.width << "x" << mode.height << " - "
                  << mode.bitsPerPixel << " bpp" << std::endl;
    }

    //information about the current OpenGL context
    sf::ContextSettings settings;
    settings.depthBits = 24;
    settings.stencilBits = 8;
    settings.antialiasingLevel = 4;
    settings.majorVersion = 4;
    settings.minorVersion = 0;

    window.setFramerateLimit(60);//set the refresh limit to the current frame rate 60fps
    window.create(sf::VideoMode(mode.width,mode.height,mode.bitsPerPixel), "Not Another Space Invaders Clone", sf::Style::Fullscreen, settings);
    sf::Event e;
    bool running = true;

    //set up for killer
    nasic::killer m_killer;
    m_killer.init(window, m_scaleX);

    int killerDirection = 1;
    nasic::ammo* m_ammoPtr;
    std::list<nasic::ammo> m_enemyAmmo;
    std::list<nasic::ammo> m_missileAmmo;
    std::list<nasic::ammo>::iterator m_missileIt;
    std::list<nasic::ammo>::iterator m_eAmmoIt;

    //some stuff to uniformly distribute the particles
    std::mt19937 engine;
    std::uniform_int_distribution<int> distr(m_scaleX*10, (int)m_killer.getAABB().x/4);
    auto randomizer = std::bind(distr, engine);
    thor::Distribution<int> thorDistr(randomizer);

    //time variables
    sf::Clock tickClock;
    sf::Time timeSinceLastUpdate = sf::Time::Zero;
    sf::Time TimePerFrame = sf::seconds(1.f/60.f);
    sf::Time bossIntroFrames = sf::Time::Zero;
    sf::Time bossMotionFrames = sf::Time::Zero;
    sf::Time bossMandibleFrames = sf::Time::Zero;
    sf::Time bossCannonFrames = sf::Time::Zero;
    sf::Time bossMissileFrames = sf::Time::Zero;
    sf::Time bossGunFrames = sf::Time::Zero;
    sf::Time bossBurstFrames = sf::Time::Zero;
    sf::Time missileAmmoFrames = sf::Time::Zero;
    sf::Time missileBurstFrames = sf::Time::Zero;
    sf::Time particleFrames = sf::Time::Zero;
    sf::Time eyeColorFrames = sf::Time::Zero;
    bool introDone = false;
    int mandibleRotationDirection = 1;
    int tempcounter = 0;
    int colorSwitch = 1;

    while(running)
    {
        while(window.pollEvent(e))
        {
            if(e.type == sf::Event::Closed)
            {
                window.close();
                return 0;
            }

            if(e.type == sf::Event::KeyPressed)
            {
                switch(e.key.code)
                {
                case sf::Keyboard::Escape:
                {
                    window.close();
                    return 0;
                }
                }
            }
        }

        timeSinceLastUpdate += tickClock.restart();
        while (timeSinceLastUpdate > TimePerFrame)
        {
            srand(time(NULL));//seed a random number every frame
            timeSinceLastUpdate -= TimePerFrame;

            bossIntroFrames += TimePerFrame;
            bossCannonFrames += TimePerFrame;
            bossMissileFrames += TimePerFrame;
            bossGunFrames += TimePerFrame;

            if(missileAmmoFrames.asSeconds() > 3.f)
                missileAmmoFrames = sf::Time::Zero;

            else
                missileAmmoFrames += TimePerFrame;

            //updates and time for pause message
            if(eyeColorFrames.asSeconds() > 2.f)
            {
                eyeColorFrames = sf::Time::Zero;
                colorSwitch *= -1;
            }

            else
                eyeColorFrames += TimePerFrame;

            float r = interpolate::sineEaseIn(eyeColorFrames.asSeconds(),0.f,255.f,2.f);
            float g = interpolate::sineEaseIn(eyeColorFrames.asSeconds(),0.f,255.f,2.f);
            float b = interpolate::sineEaseIn(eyeColorFrames.asSeconds(),0.f,255.f,2.f);

            if(colorSwitch == -1 && r < 255)
            {
                m_killer.updateEyeColor((unsigned int)r,255-(unsigned int)g);
            }

            if(colorSwitch == 1 && r < 255)
            {
                m_killer.updateEyeColor(255-(unsigned int)r,(unsigned int)g);
            }

            ///////////////////////////////////
            //perform boss motion updates
            ///////////////////////////////////

            if(bossMandibleFrames.asSeconds() > 1.f)
            {
                bossMandibleFrames = sf::Time::Zero;
                mandibleRotationDirection *= -1;
            }

            else
            {
                bossMandibleFrames += TimePerFrame;
            }

            m_killer.animateMandibles(m_scaleX*mandibleRotationDirection*interpolate::expoEaseIn(bossMandibleFrames.asSeconds(), 0.f, 1.f, 1.f));

            if(bossIntroFrames.asSeconds() < 1.f)
                m_killer.move(0.f, m_scaleX*10.f*interpolate::expoEaseOut(bossIntroFrames.asSeconds(),0.f,1.f,1.f));

            if(bossIntroFrames.asSeconds() > 4.f)
            {
                if(bossMotionFrames.asSeconds() >= 5.f)
                {
                    bossMotionFrames = sf::Time::Zero;
                    killerDirection *= -1;//switch directions...
                }

                else
                {
                    bossMotionFrames += TimePerFrame;
                }

                m_killer.move(killerDirection*(m_scaleX*10.f)*(interpolate::backEaseOut(bossMotionFrames.asSeconds(), 0.f, 1.f, 5.f)), m_scaleY*bossMotionFrames.asSeconds()*(float)killerDirection/12.f);

                ///////////////////////////////
                //perform boss ammo updates
                ///////////////////////////////

                if(bossBurstFrames.asSeconds() > .5f)
                    bossBurstFrames = sf::Time::Zero;

                else
                    bossBurstFrames += TimePerFrame;

                if(missileBurstFrames.asSeconds() > 3.f)
                    missileBurstFrames = sf::Time::Zero;
                else
                    missileBurstFrames += TimePerFrame;

                //instantiate as many particles as the frame rate will allow
                m_killer.initParticles(thorDistr());

                //update particles
                m_killer.updateParticles(TimePerFrame,m_scaleX);

                //load up the enemy ammo vector every second
                if(bossGunFrames.asSeconds() > .1f && bossBurstFrames.asSeconds() > 0.25f)
                {
                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::delsiriak, sf::Vector2f(m_killer.leftGunPosition().x  + m_scaleX*15.f, m_killer.leftGunPosition().y - m_scaleY*10.f), m_scaleY);
                    m_enemyAmmo.push_back(*m_ammoPtr);

                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::delsiriak, sf::Vector2f(m_killer.rightGunPosition().x, m_killer.rightGunPosition().y - m_scaleY*10.f), m_scaleY);
                    m_enemyAmmo.push_back(*m_ammoPtr);

                    bossGunFrames = sf::Time::Zero;
                }

                if(bossMissileFrames.asSeconds() > .1f && missileBurstFrames.asSeconds() > 3.f)
                {
                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::missile, m_killer.leftEyeLaserPosition(), m_scaleY);
                    m_missileAmmo.push_back(*m_ammoPtr);

                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::missile, m_killer.rightEyeLaserPosition(), m_scaleY);
                    m_missileAmmo.push_back(*m_ammoPtr);

                    bossMissileFrames = sf::Time::Zero;
                }

                if(bossCannonFrames.asSeconds() > .1f && bossBurstFrames.asSeconds() > 0.5f)
                {
                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::rhiians, sf::Vector2f(m_killer.leftCannonPosition().x + m_scaleX*10.f, m_killer.leftCannonPosition().y + m_scaleY*60.f), m_scaleY);
                    m_enemyAmmo.push_back(*m_ammoPtr);

                    m_ammoPtr = new nasic::ammo(nasic::ammo::ammoType::rhiians, sf::Vector2f(m_killer.rightCannonPosition().x + m_scaleX*30.f, m_killer.rightCannonPosition().y + m_scaleY*60.f), m_scaleY);
                    m_enemyAmmo.push_back(*m_ammoPtr);

                    bossCannonFrames = sf::Time::Zero;
                }

                //fire ammo
                for(m_eAmmoIt = m_enemyAmmo.begin(); m_eAmmoIt != m_enemyAmmo.end(); ++m_eAmmoIt)
                {
                    m_eAmmoIt->fire(TimePerFrame);
                }

                //missiles are a special case as ammo, therefore,
                //the firing of missiles will be done specially...;)

                for(m_missileIt = m_missileAmmo.begin(); m_missileIt != m_missileAmmo.end(); ++m_missileIt)
                {
                    if(missileAmmoFrames.asSeconds() < 3.f)
                        m_missileIt->fire(missileAmmoFrames);
                }

                std::list<nasic::ammo>::iterator screenAmmoIt;//check to see if enemy bullet left the screen...
                for(screenAmmoIt = m_enemyAmmo.begin(); screenAmmoIt != m_enemyAmmo.end(); ++screenAmmoIt)
                {
                    if(screenAmmoIt->getPosition().y > window.getSize().y)
                    {
                        screenAmmoIt = m_enemyAmmo.erase(screenAmmoIt);//delete missed shots...
                    }
                }

                //////////////////////////////////
                //handle missiles leaving screen
                //////////////////////////////////
                std::list<nasic::ammo>::iterator missileIt;
                for(missileIt = m_missileAmmo.begin(); missileIt != m_missileAmmo.end(); ++missileIt)
                {
                    if(missileIt->getPosition().y >= m_winsizeY)
                    {

                        missileIt = m_missileAmmo.erase(missileIt);
                    }
                }
            }
        }

        window.clear();

        window.draw(m_killer);

        //draw the missiles if the boss fight is happening
        for(m_missileIt = m_missileAmmo.begin(); m_missileIt != m_missileAmmo.end(); ++m_missileIt)
        {
            window.draw(*m_missileIt);
        }

        for(m_eAmmoIt = m_enemyAmmo.begin(); m_eAmmoIt != m_enemyAmmo.end(); ++m_eAmmoIt)
        {
            window.draw(*m_eAmmoIt);
        }

        window.display();
    }

    return 0;
}