Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.






A bit about my game and some slow progress

Posted by blewisjr, 17 November 2013 · 374 views

Hello Everyone,

I feel it is time for some updates on my game as I really did not say much about it. So I would like to introduce you to the concept of a game I have been wanting to make for years. The game is called Orbis. The general idea behind the game is Asteroids with a twist.
So ultimately I will be making a Asteroids clone with a few twists to spice up an old game I use to love to play at the Arcades or even on the Atari!!!!
I am not sure if I am ready to really detail out all the features quite yet as I am not sure exactly what will make it into the game just yet. So we will leave it at Asteroids with a twist for now till I flesh out more of the concepts.

I also decided to make some tool changes for the game. I decided I would stay with C++ even though after my first foray back into C++ I wanted to scream back to C. Ultimately I ditched QTCreator and MinGW. For some reason I was having issues with MinGW on Windows 8 so I decided to install Visual Studio 2013 Express Windows Desktop edition. I must say I am really impressed. I also decided to stick with SFML. To use SFML with VS2013 I needed to rebuild the library and building SFML 2.1 did not work out to well so I ended up going with the Git repo and building from there. So far so good. So here is what my new environment looks like.
  • Visual Studio 2013 Express Windows Desktop
  • CMake 2.8.12.1
  • SFML (master)
  • Git Version Control (on BitBucket)
I am still using CMake because if I do decide to build the game on Linux for testing on my laptop CMake will save my life. So right now I use CMake to generate the Visual Studio projects and work from there. Not pretty but saves tons of headaches. Visual Studio leaves me out of my comfort zone as I am not a huge IDE fan period but we will see where this setup takes me.

Now a bit on the progress. Not much honestly. Much of my time is taken up by school and on top of it I am trying to get back into the groove of C++ after spending a few years in the world of C. So bear with me we will get there.

The first task I really wanted to get done was make sure SFML actually worked and it did. From there I felt the most important thing I should get out of the way is Resource Management because this is something I really can't have a game without. Sadly this was probably not the best place to start when I am trying to get my C++ groove back but none the less I think I was successful. My goal here was to put together a cache for my resources. This will be the core of ensuring all resources are properly freed up when no longer needed and will also be the core of my TextureAtlas system which is what I will be building next. I really needed this to be generic because SFML has many types of resources. So this resource cache is built to handle sf::Image, sf::Texture, sf::Font, and sf::Shader. There may be a few things but this is what I can think of off the top of my head. It will not handle music because sf::Music handles everything very differently so I will need to take a different approach for music.

I also wanted to ensure that the memory of the cache was handled automatically. Since I am not in the world of C and the fun void* generic programming world I figured I might as well try to use some C++11.

So my first foray into C++ after years and years of not touching it includes Templates, and some C++11. In other words AHHHH MY EYES!!!!
Sorry for no comments but here is the code I came up with using unique_ptr for the resource which gets stored in a map. The actual key to the map will be implemented as a enum elsewhere so I can index into the cache to get what is needed. There are 4 methods. 2 load_resource methods and 2 get_resource methods there is no way to remove a resource at this point as I am not sure I need it yet for this game at least.
One load_resource takes care of the basic loadFromFile. sf::Shader as a extra param and so can sf::Texture so the overloaded load_resource takes care of that. get_resource just returns the resource and there is a overloaded version to be called in case the cache is a const.

Again sorry for no comments I feel the code is simple enough to not need any.
#ifndef RESOURCECACHE_H
#define RESOURCECAHCE_H
#include <memory>
#include <map>
#include <string>
#include <stdexcept>

template <typename Resource, typename ResourceID>
class ResourceCache
{
public:
    void load_resource(ResourceID id, const std::string& file);
    template <typename Parmeter>
    void load_resource(ResourceID id, const std::string& file, const Parmeter& parameter);

    Resource& get_resource(ResourceID);
    const Resource& get_resource(ResourceID) const;

private:
    std::map<ResourceID, std::unique_ptr<Resource>> resources;
};

template <typename Resource, typename ResourceID>
void ResourceCache<Resource, ResourceID>::load_resource(ResourceID id, const std::string& file)
{
    std::unique_ptr<Resource> resource(new Resource());
    if (!resource->loadFromFile(file))
        throw std::runtime_error("ResourceCache::load_resource: Failed to load (" + file + ")");

    resources.insert(std::make_pair(id, std::move(resource)));
}

template <typename Resource, typename ResourceID>
template <typename Parameter>
void ResourceCache<Resource, ResourceID>::load_resource(ResourceID id, const std::string& file, const Parameter& parameter)
{
    std::unique_ptr<Resource> resource(new Resource());
    if (!resource->loadFromFile(file, parameter))
        throw std::runtime_error("ResourceCache::load_resource: Failed to load (" + file + ")");

    resources.insert(std::make_pair(id, std::move(resource)));
}

template <typename Resource, typename ResourceID>
Resource& ResourceCache<Resource, ResourceID>::get_resource(ResourceID id)
{
    auto resource = resources.find(id);
    return *resource->second;
}

template <typename Resource, typename ResourceID>
const Resource& ResourceCache<Resource, ResourceID>::get_resource(ResourceID id) const
{
    auto resource = resources.find(id);
    return *resource->second;
}
#endif
Here is the main.cpp file which I used for my functional test as well so you can see it in use.
#include <SFML/Graphics.hpp>
#include "ResourceCache.h"

enum TextureID
{
    Background
};

int main()
{
    sf::RenderWindow window(sf::VideoMode(250, 187), "SFML Works!");
    ResourceCache<sf::Texture, TextureID> TextureCache;
    TextureCache.load_resource(TextureID::Background, "./Debug/background.png");
    sf::Texture bkg = TextureCache.get_resource(TextureID::Background);
    sf::Sprite bkg_sprite(bkg);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(bkg_sprite);
        window.display();
    }
    return 0;
}
Like stated this is my first foray back into C++ so feel free to let me know if you see anything obviously wrong with the ResourceCache class. Much appreciated in advance.

Until Next Time.




Hey. I just a question about the code. I am curious about why you chose to use a unique pointer to store the resource instead of, say, a shared pointer. It seems to me that the resource is intended to be shared so a shared pointer would seem right, and then you could provide weak pointers to those components that wanted to use the resource. In that way, if the resource cache is deleted the components are not left with dangling references.

 

 

Also, you probably want to check the results of those find() calls but you already know that :)

I did indeed think of using shared pointers but decided on unique pointers for simplicity.  The general thought I had was that each scene handles it's own resources so I will not have to pass caches around the application.  This means  each resource is unique and never actually gets copied.  So shared pointer seems a little heavy.  The other advantage is it allows me to pass out the reference to the resource instead of having to push out like you said a weak pointer because each resource by design has a 1:1 mapping to a single unique pointer.  Overall it leads to a bit of cleaner code or at least I hope.

 

I do understand where you are coming from in saying about the dangling refs but I don't quite see it possible because as long as a scene is alive internally it will have access to it's resources.  Using a state machine to manage the scenes should make this quite easy to attain in theory.

 

So ultimately by code design I am trying to modularize everything to a point where things are self contained instead of floating across the application.  My goal with that is to hope that the isolation can lead to better quality code, easier to maintain code, and easier to debug code.

 

Oh and yes I meant to check those find calls thanks for reminding me to actually do it lol.

 

Hope I answered your question in a non confusing way sometimes it is hard for me to explain what I am thinking.

neat, I was just thinking about how best to batch draw calls in SFML - It didn't occur to me that the texture can be batched, leaving the transformations intact inside a Sprite instance. Thanks!

Boy, that's kind of dangerous. If you push out a reference like that, and if at some point the resource is unloaded (and a good resource manager should allow for unloading resources as easily as loading) then the reference is invalid and a segfault is likely. The pointer type you use should reflect its usage pattern.

 

In my opinion, the best model to use in this case is to either use shared_ptrs all around, as suggested by jdd (which would more accurately reflect the fact that multiple entities can share a single instance of a resource), or to have the resource cache store a weak_ptr, and have the entities hold a shared_ptr. That way, the resource unloading happens "automatically" when all shared_ptrs are dropped, and the resource cache can merely check its stored weak_ptr for validity if the resource is requested again.

 

Either way, though, a sharing paradigm far more accurately reflects your actual usage than a unique_ptr with some unsafe references.

Two is for sure a winner.  I will look into making the code modifications to shared_ptr.  In my methodology of what I was going for I was sure unique_ptr would work.  I guess that is just my naivety with C++ and more modern C++ features at that.  Coming from a heavier background in C does not really help matters either.  Thanks for the explanation JTippetts.  Any future suggestions on code I post is just as open to scrutiny after all it is one of the best ways to learn.

November 2014 »

S M T W T F S
      1
2345678
9101112131415
16171819202122
2324252627 28 29
30      

Recent Comments

Recent Comments

PARTNERS