Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Draw a rotating 'head'  (Read 1829 times)

0 Members and 1 Guest are viewing this topic.

DatCorno

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Draw a rotating 'head'
« on: February 22, 2014, 11:03:35 pm »
Hey there! I'm currently working on a Tower Defense type of game and it came to my mind that it would look way cooler if the 'head' of the towers (or the canon or whatever you want to call it) could rotate around and aim at the target. So I create two images : the tower's body and the canon. But here comes the problem : how do I put it in the middle of my sprite? I tried a lot of things : setting the origin to the center of the sprite, calculate the position of the head with the x and y of the body + de width/height but none of that worked...

I should mention that the image representing the head is too small, so I use sprite.scale to grow it, and I think it affects the result of what I'm trying to do.

I attached the cpp to the post. Here's the headers :

Tower.hpp :
#ifndef TOWER_HPP
#define TOWER_HPP

#include "Entity.hpp"
#include <functional>
#include <map>

class Tower;

namespace std {
        template <typename T>
        using add_pointer_ti = typename add_pointer<T>::type;
}

using TowerCreator = std::add_pointer_ti<Tower*()>;

class Tower : public Entity{
public:
        virtual ~Tower(){}

        void Draw(sf::RenderWindow& win);

        void setPosition(float, float);

        static Tower* create(sf::Keyboard::Key id);
        static void registerToFactory(sf::Keyboard::Key id, TowerCreator func);
        //TO ADD : Shoot and ApplyEffect (virtual)

protected :
        void LoadSprite();

        Tower(float, float);

        std::string headFileName;
        sf::Texture headTexture;
        sf::Sprite headSprite;
        int cost;
        int upgradeCost;
        float range;

private :
        static std::map<sf::Keyboard::Key, TowerCreator>& factories();

};

#endif

BasicTower.cpp :
#include "BasicTower.hpp"

using namespace sf;

class BasicTower::Factory{
public :
        Factory(){
                Tower::registerToFactory(Keyboard::Q, create);
        }

        static Tower* create();
};

BasicTower::Factory* BasicTower::factory = new BasicTower::Factory();

Tower* BasicTower::Factory::create(){
        return new BasicTower();
}

BasicTower::BasicTower() : Tower(0.0f, 0.0f) {
        filename = "Textures/baseTower.png";
        headFileName = "Textures/baseTowerHead.png";
        LoadSprite();
}

BasicTower::BasicTower(float _x, float _y) : Tower(_x, _y)
{
        headFileName = "Textures/baseTowerHead.png";
        filename = "Textures/baseTower.png";
        LoadSprite();
}

Game.hpp :
#ifndef GAME_HPP
#define GAME_HPP

#include "SFML\Graphics.hpp"
#include <vector>
#include <memory>
#include "Tower.hpp"
#include "BasicTower.hpp"

struct Game {

        Game();
        ~Game();
        int Run();

private:
        void Update();
        void Draw();
        void AddTower();
       
        std::unique_ptr<Entity> selectedEntity;
        std::unique_ptr<Tower> selectedTowerType;
        sf::RenderWindow win;
        std::vector<std::unique_ptr<Tower>> towers;
};

#endif

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Draw a rotating 'head'
« Reply #1 on: February 23, 2014, 12:40:33 pm »
But here comes the problem : how do I put it in the middle of my sprite? I tried a lot of things : setting the origin to the center of the sprite
Generally, I would set all origins to the sprite centers, it makes things a lot simpler. You can use this helper function to do so:
void centerOrigin(sf::Sprite& sprite)
{
        sf::FloatRect bounds = sprite.getLocalBounds();
        sprite.setOrigin(std::floor(bounds.width / 2.f), std::floor(bounds.height / 2.f));
}

You can then position both tower and turret (the rotating part) sprites as follows:
sf::Sprite tower;
tower.setPosition(pos);
centerOrigin(tower);

sf::Sprite turret;
turret.setPosition(tower.getPosition());
centerOrigin(turret);

Using a centered origin is also wise because the origin of rotation is also located in the center.

Your code has memory leaks. Use std::unique_ptr if you need dynamic allocation (but try to avoid it in the first place!). A factory is a perfect example where you can return unique pointers, since you're only transferring ownership. For in-depth information, my article Why RAII Rocks might be interesting.

By the way, you're not allowed to extend the std namespace except for template specializations. And std::add_pointer_t already exists (see here)... Maybe your standard library doesn't support it yet?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Draw a rotating 'head'
« Reply #2 on: February 23, 2014, 07:57:33 pm »
I'll respond to your private message here, so that others can read and participate as well.

First of, I read your article on RAII and even though I understood what it meant, I can't get my head around when to use and how to use it properly.
It's simple: use it always :P

What exactly don't you understand?


Second, you said :
Quote
Use std::unique_ptr if you need dynamic allocation (but try to avoid it in the first place!)
why should I try to avoid it?
I meant you should try to avoid dynamic allocations where possible. Often it's not necessary to use pointers or smart pointers, when automatic objects work fine. In this forum, code like
sf::RenderWindow window = new sf::RenderWindow(...);
// use the window
delete window;
is not uncommon. But it's simpler, shorter and safer to write
sf::RenderWindow window(...);
// use the window

In your case, I wondered why the factory returns a pointer to a tower and not a tower itself. Is it used polymorphically? For example, do you store a container of abstract entities rather than a container of towers?


And finally, could you point me in a direction of how would I modify my factory so that it uses RAII?
First, I would use a slightly different design. I'm no fan of global/static objects for convenience. When reflecting more about it, it's almost always possible to find a clear owner of an object, nothing just "needs to be there" (there are of course exceptions like logging).

Concretely, I would make the factory a member of an enclosing class (for example World) that also contains the towers.
class TowerFactory
{
public:
    // non-static member functions!
    void registerTower(sf::Keyboard::Key id, TowerCreator func);

    // if you use it polymorphically:
    std::unique_ptr<Tower> create(sf::Keyboard::Key id) const;
    // otherwise:
    Tower create(sf::Keyboard::Key id) const;

private:
    // object, not singleton function
    std::map<sf::Keyboard::Key, TowerCreator> factories;
};

class World
{
    ...
private:
    TowerFactory factory;
    std::vector<Tower> towers;
};

One question is also, what advantage does the factory offer? Why not construct towers directly? One possible answer is that it gathers resources like textures, and passes references to the tower when constructing. That's also a flaw in your current design: you store a texture in each tower, duplicating the resource unnecessarily.

The tower itself might then consist of simply some logic attributes (such as hitpoints, position, rotation, target, range, ...). If you want, you can also add drawing-related functionality such as sprites. In the latter case, you should inherit sf::Drawable rather than writing a custom Draw() function. Also, you needn't redeclare empty virtual destructors, and you should avoid makîng member variables protected (encapsulate them as much as possible by making them private).

By the way, I've once gathered some reoccurring topics in this thread, you might be interested in specific points from that list.
« Last Edit: February 23, 2014, 07:59:46 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: