Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


agentultra

Member Since 06 Feb 2013
Offline Last Active May 09 2013 09:11 PM

Topics I've Started

Implementing a scene director

12 February 2013 - 12:11 PM

I have an App class that I would like to manage a stack of objects subclassed from Scene and the main game loop. The App class' purpose is to yield control of the main game loop to the currently active Scene object.

 

using namespace std;

typedef unique_ptr<Scene> ScenePtr

class App {
    ...
    stack<ScenePtr, vector<ScenePtr>> scene_stack;
    ScenePtr current_scene;
    ScenePtr next_scene;

    // Don't want to go through the trouble of managing a Singleton
    // but for basic safety, don't allow copies.
    App(App& other);

    int run();

public:
    App();
    ~App();

    ...

    void startWithScene(ScenePtr scene);
    void pushScene(ScenePtr scene);
    void popScene();
};
 

 

 

There's a bunch of other code in there for initializing the display, running the actual game loop, etc. What I'm having trouble with (and can't find a decent answer on SO for) is how I can pass a pointer to a dynamically allocated Scene subclass into startWithScene, pushScene, etc.

 

 

 

int App::startWithScene(ScenePtr scene)
{
    current_scene = std::move(scene);
    current_scene->init();
    return run();
} 

 

And what I'm trying to do in main() is:

 

 

...
#include "BlankScene.h"

int main(int argc, char *argvp[])
{
    App app = App();
    app.startWithScene(ScenePtr(new BlankScene()));
}

The idea is that the Scene base class is just an interface for the App to use. The subclass provides the implementation for any given scene in a game. The scene is responsible for all of its own entities, responding to the events it's interested in, rendering itself to the display, etc. This seems like a reasonable design to me and I'm just trying to get the minimum possible infrastructure in place to get it going.

 

However I'm getting an error that seems unrelated. On the line in main() where I create an instance of the App the compiler is telling me that I'm calling a private constructor of the class. It wasn't giving that error before I added the class members and methods to implement the scene management stuff.

 

I'm starting to wonder if I'm barking up the wrong tree here. I'm reading as much as I can about smart pointers in C++11 (very nice feature) but this error is throwing me for a loop. Are there more implicit constructors or something?

 

(And is this even a reasonable design?)


Link Errors w/ SDL + XCode 4

07 February 2013 - 03:20 PM

I did manage to get SDL 1.2 working on OSX using XCode4 following many of the great guides out there.

 

Now I've written a basic "Map" template class that will be used as the basis for my dungeon-generation stuff. It's nothing terribly fancy; mainly just a template around a std::vector and some accessors for accessing locations in the array using x,y coordinates.

 

However, I'm getting some linker errors when I try to create an instance of my class in my main.cpp; I'm not sure why it's unable to resolve the symbols and am wondering if it might have something to do with SDL's macro magic.

 

Code here:
 

Map.h

#ifndef __DungeonSoft__Map__
#define __DungeonSoft__Map__

#include <iostream>
#include <vector>

#include "monads.h"

typedef std::pair<int, int> point; // x, y

template <typename T>
class Map {
    std::vector<T> map;

public:
    const int width;
    const int height;

    Map();
    Map(int w, int h);
    Map<T> operator=(const Map<T>& other);
    ~Map();
    
    int getWidth() { return width; };
    int getHeight() { return height; };
    T get(int x, int y) const;
    void set(int x, int y, T val);
    std::vector<std::pair<point, Maybe<T>>> neighbours(int x, int y) const;
};

#endif /* defined(__DungeonSoft__Map__) */

 

Map.cpp

#include "Map.h"


template <class T>
Map<T>::Map() : width(0), height(0)
{
}

template <class T>
Map<T>::Map(int w, int h) : width(w), height(h)
{
    map.reserve(width * height);
    for (typename std::vector<T>::iterator it = map.begin(); it != map.end(); ++it) {
        *it = T();
    }
}

template <class T>
Map<T> Map<T>::operator=(const Map<T>& other)
{
    map.clear();
    map.reserve(other.width * other.height);
    for (typename std::vector<T>::iterator it = other.map.begin(); it != other.map.end(); ++it) {
        map[it] = *it;
    }
}

template <class T>
Map<T>::~Map<T>()
{
    map.clear();
}

template <class T>
T Map<T>::get(int x, int y) const
{
    return map[y * width + x];
}

template <class T>
void Map<T>::set(int x, int y, T val)
{
    map[y * width + x] = val;
}

template <class T>
std::vector<std::pair<point, Maybe<T>>> Map<T>::neighbours(int x, int y) const
{
    typedef std::pair<point, Maybe<T>> neighbour;

    point coords[8] = {
        point(-1, -1),
        point(0, -1),
        point(1, -1),
        point(-1, 0),
        point(1, 0),
        point(-1, 1),
        point(0, 1),
        point(1, 1)
    };
    
    std::vector<neighbour> ns;
    for (int i = 0; i <= sizeof(point) * 8; ++i) {
        int x_off = x + coords[i].first;
        int y_off = y + coords[i].second;

        try
        {
            ns.push_back(neighbour(point(x_off, y_off), Maybe<T>(map[y_off * width + x_off])));
        } catch (std::out_of_range& err) {
            ns.push_back(neighbour(point(-1, -1), Maybe<T>()));
        }
    }
    return ns;
}

 

and the monad.h utility header:

/*
 * Minimal C++ implementation of Functor, Monad and Maybe.
 *
 * Requires c++0x variadic templates and lambda expressions:
 * 
 *      g++ -std=c++0x main.cpp -o main
 *
 * fmap, monadic bind and return implementations for std::vector
 * and Maybe.
 *
 * Copyright 2012 James Brotchie <brotchie@gmail.com>
 *  https://github.com/brotchie/
 *  @brotchie
 *
 */

#ifndef __DungeonSoft__monads__
#define __DungeonSoft__monads__

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

/* Functor */
template <template <typename...> class F>
struct Functor {
    template <typename A, typename B>
    static function <F<B>(F<A>)> fmap(function <B(A)>);
};

template <template <typename...> class F, typename A, typename B>
static function <F<B>(F<A>)> fmap(function <B(A)> f) {
    return Functor<F>::fmap(f);
}

template <template <typename...> class F, typename A, typename B>
static F<B> fmap_(function <B(A)> f, F<A> v) {
    return Functor<F>::fmap(f)(v);
}

template <template <typename...> class F, typename A, typename B>
static F<B> operator %(function <B(A)> f, F<A> v) {
    return Functor<F>::fmap(f)(v);
}

/* Monad */
template <template <typename...> class F>
struct Monad {
    template <typename A>
    static F<A> return_(A);

    template <typename A, typename B>
    static F<B> bind(F<A>, function<F<B>(A)>);
};

template <template <typename...> class F, typename A, typename B>
static F<B> bind(F<A> m, function<F<B>(A)> f) {
    return Monad<F>::bind(m, f);
}

template <template <typename...> class F, typename A>
static F<A> return_(A a) {
    return Monad<F>::return_(a);
}

template <template <typename...> class F, typename A, typename B>
static F<B> operator >=(F<A> m, function<F<B>(A)> f) {
    return Monad<F>::bind(m, f);
}

template <template <typename...> class F, typename A, typename B>
static F<B> operator >>(F<A> a, F<B> b) {
    function<F<B>(A)> f = [b](A){ return b; };
    return a >= f;
}

/* Maybe */
template <typename T>
class Maybe {
public:
    Maybe() : _empty(true){};
    explicit Maybe(T value) : _empty(false), _value(value){};

    T fromJust() const {
        if (isJust()) {
            return _value;
        } else {
            throw "Cannot get value from Nothing";
        }
    }

    bool isJust() const { return !_empty; }
    bool isNothing() const { return _empty; }

    static bool isJust(Maybe &m) { return m.isJust(); }
    static bool isNothing(Maybe &m) { return m.isNothing(); }
private:
    bool _empty;
    T _value;
};

template <typename T>
ostream& operator<<(ostream& s, const Maybe<T> m)
{
    if (m.isJust()) {
        return s << "Just " << m.fromJust();
    } else {
        return s << "Nothing";
    }
}

/* Functor Maybe */
template <>
struct Functor<Maybe> {
    template <typename A, typename B>
    static function <Maybe<B>(Maybe<A>)> fmap(function <B(A)> f) {
        return [f](Maybe<A> m) -> Maybe<B> {
            if (m.isNothing()) {
                return Maybe<B>();
            } else {
                return Maybe<B>(f(m.fromJust()));
            }
        };
    };
};

/* Monad Maybe */
template <>
struct Monad<Maybe> {
    template <typename A>
    static Maybe<A> return_(A v){
        return Maybe<A>(v);
    }

    template <typename A, typename B>
    static Maybe<B> bind(Maybe<A> m, function<Maybe<B>(A)> f){
        if (m.isNothing()){
            return Maybe<B>();
        } else {
            return f(m.fromJust());    
        }
    }
};

/* Functor vector */
template <>
struct Functor<vector> {
    template <typename A, typename B>
    static function <vector<B>(vector<A>)> fmap(function <B(A)> f) {
        return [f](vector<A> v){
            vector<B> result;
            transform(v.begin(), v.end(), back_inserter(result), f);
            return result;
        };
    }
};

/* Monad vector */
template <>
struct Monad<vector> {
    template <typename A>
    static vector<A> return_(A v){
        return vector<A>{v};
    }

    template <typename A, typename B>
    static vector<B> bind(vector<A> m, function<vector<B>(A)> f){
        vector<B> v;
        for_each(m.begin(), m.end(), [f, &v](A a){
            vector<B> result = f(a);
            copy(result.begin(), result.end(), back_inserter(v));
        });
        return v;
    }
};

template <typename A, typename B, typename C>
static function<C(A)> compose(function<B(A)> f1, function<C(B)> f2) {
    return [f1,f2](A v) -> C {
        return f2(f1(v));
    };
}

#endif /* defined(__DungeonSoft__monads__) */

 

and finally, my main.cpp

#include <SDL/SDL.h>
#include "SDLMain.h"

#include "Map.h"

const int WINDOW_WIDTH = 300;
const int WINDOW_HEIGHT = WINDOW_WIDTH / 16 * 9;
const int SCALE = 3;


int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);
    
    Map<int> map = Map<int>(10, 10);
    for (int y = 0; y <= map.getHeight(); ++y) {
        for (int x = 0; x <= map.getWidth(); ++x) {
            std::cout << map.get(x, y);
        }
        std::cout << std::endl;
    }

    SDL_Surface *screen = SDL_SetVideoMode(WINDOW_WIDTH * SCALE, WINDOW_HEIGHT * SCALE, 32, SDL_DOUBLEBUF);
    SDL_WM_SetCaption("DungeonSoft Presents: The Song of Wolves", "icon.ico");
    
    bool isRunning = true;
    SDL_Event event;
    while(isRunning) {
        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    isRunning = false;
                    break;
                    
                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym) {
                        case SDLK_ESCAPE:
                            isRunning = false;
                            break;
                            
                        default:
                            break;
                    }
                    break;
                    
                case SDL_VIDEOEXPOSE:
                    SDL_Flip(screen);
                    break;
                    
                default:
                    break;
            }
            SDL_Flip(screen);
        }
    }

    SDL_Quit();
    return 0;
}

 

 

The error I'm getting is:

Undefined symbols for architecture x86_64:
  "Map<int>::Map(int, int)", referenced from:
      _SDL_main in main.o
  "Map<int>::~Map()", referenced from:
      _SDL_main in main.o
  "Map<int>::get(int, int) const", referenced from:
      _SDL_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

 

Do I just have the signature wrong on the ctor or something?


PARTNERS