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

Author Topic: game engine question 2  (Read 3234 times)

0 Members and 1 Guest are viewing this topic.

section_two

  • Newbie
  • *
  • Posts: 19
    • View Profile
game engine question 2
« on: June 25, 2011, 05:59:59 am »
Hi,

I want to make a tilemap, but with million of tiles. I know about split the map, and drawing only the part i see. The problem is not the fps, is the memory(RAM).

So doing something like sf::Sprite[10000000], is not a good choice.

So, i have classes TILE, MAP, WORLD. World contain maps, maps contain tiles.

The problem is that loading 10000000 tile Object,even without declaring each Sprite... just a few methods , vars.......etc, memory goes to hell.


Before i know this, i notice that with a lot of sprites memory die, so, i split the map in smaller maps, and i load only the Sprites that i need. But that dosent work. Because  memory die without loading any Sprite, "only" the tiles object(10000000 objects). When i say die, i say  1GB of memory running.

I dont know how to implement this. If i create and delete tile objects, every time i create the object i have to load every single var again, like sprite, pos of the sprite, layers, anim, all.

Hope you understand my question.

Thanks

Vit

  • Newbie
  • *
  • Posts: 14
    • View Profile
game engine question 2
« Reply #1 on: June 25, 2011, 03:42:20 pm »
How big is each of your tile objects? 1000000 tiles should only be a few MB at most.

Does each of your map objects contain 1000000 tiles, or are there 1000000 tiles in the world in total? 1 GB of memory is a lot for just a million tiles. I don't know how you managed to get 1KB per tile. Does each tile have its own sf::Image by any chance? It's far better to have an array of sf::Images that can be accessed by the rendering code, and give each tile object an index into that array.

I'd split the world/maps up into smaller chunks - for example, in my game, I have a (practically) infinite world, which is split into 32x32 chunks. Only the chunks near the player's location need to be loaded, so the rest of them can be saved to a file and removed from RAM.
You could probably use bigger chunks than that (the reason mine are that size is that each chunk is rendered at once, and my graphics card can't cope with chunks much larger). Each tile is 4 bytes, so a chunk is 4 KB. This means I can load enough chunks around the player to make the world seamless without using much memory. Loading chunks from files is fast, too, as there isn't much data that needs to be loaded.
Then, separate from the chunk objects, I have a fixed number of chunk renderer objects. All visible chunks are attached to one of those; when the  player moves far enough that the visible chunks change, I detach the renderers and reattach them to the new visible chunks. That way, only the chunks right next to the player need to have any sort of rendering data; further-away chunks only need to store basic tile data (i.e. only take 4 KB per chunk).

I'm using straight OpenGL for rendering, but I'd imagine a good strategy to use in SFML would be to render each chunk to a single sf::Image (or if you're using layers, one sf::Image per layer). Then, you only need one sf::Sprite per chunk, saving rendering time (though it would be more memory-expensive, as you'll need a large sf::Image per chunk). When a chunk is no longer visible, you can delete its image. I know that's how RPG Maker works; each map is rendered to an image rather than being drawn tile-by-tile each frame.

section_two

  • Newbie
  • *
  • Posts: 19
    • View Profile
game engine question 2
« Reply #2 on: June 25, 2011, 08:30:01 pm »
Code: [Select]
#include <SFML/Graphics.hpp>

const int MAXLAYERS=3;
const int MAPSIZE=128;

struct sTileLayer
{
   // sf::Sprite *sprite;
};

class cTile
{
    public:
        cTile(){layer=new sTileLayer[MAXLAYERS];};
        virtual ~cTile(){delete layer;};
    private:
       sTileLayer *layer;
};

class cMap
{
    public:
        cMap(){tile=new cTile[MAPSIZE*MAPSIZE];};
        virtual ~cMap(){delete tile;};
    private:
        cTile *tile;
};

class cWorld
{
    public:
        cWorld(){map=NULL;};
        virtual ~cWorld(){delete map;};
        void CreateMap(int w, int h){map=new cMap[w*h];};
    private:
        cMap *map;
};

int main()
{
    sf::RenderWindow App(sf::VideoMode(1024,768, 32), "SFML Graphics");

    cWorld world;
    world.CreateMap(40,40);

    App.UseVerticalSync(true);
    App.SetFramerateLimit(60);

    while (App.IsOpened())
    {
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
                App.Close();
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App.Close();
        }
        App.Clear();
        App.Display();
    }

    return EXIT_SUCCESS;
}


This is the minimal code. I have 1 world with 40x40 maps, each with 128x128 tiles.
Total = 40*40*128*128 = 26214400 tiles.

This gives me 629.280 K. Notice that sprite ptr in layers is //.

Disch

  • Full Member
  • ***
  • Posts: 220
    • View Profile
game engine question 2
« Reply #3 on: June 25, 2011, 09:28:17 pm »
Quote
I'm using straight OpenGL for rendering, but I'd imagine a good strategy to use in SFML would be to render each chunk to a single sf::Image (or if you're using layers, one sf::Image per layer). Then, you only need one sf::Sprite per chunk, saving rendering time (though it would be more memory-expensive, as you'll need a large sf::Image per chunk).


I don't recommend this.

1)  Drawing individual tiles is not that much slower.  (try it and see)

2)  Drawing full layers might actually be slower if you have large portions of the layer which are fully transparent.  You can skip over/ignore individual tiles that are transparent, but if you're drawing the full layer all at once, the renderer will have to draw all of them.

3)  Drawing individual tiles lets you do other snazzy things, like have tiles that animate.

section_two

  • Newbie
  • *
  • Posts: 19
    • View Profile
game engine question 2
« Reply #4 on: June 26, 2011, 01:15:28 am »
i have to load not only the sprites near, and delete the far ones ?? the tiles data too ????

Code: [Select]
#include <SFML/Graphics.hpp>

const int MAXLAYERS=3;
const int MAPSIZE=128;

struct sTileLayer
{
   // sf::Sprite *sprite;
};

class cTile
{
    public:
        cTile(){layer=new sTileLayer[MAXLAYERS];};
        virtual ~cTile(){delete layer;};
    private:
       sTileLayer *layer;
};

class cMap
{
    public:
        cMap(){tile=new cTile[MAPSIZE*MAPSIZE];};
        virtual ~cMap(){delete tile;};
    private:
        cTile *tile;
};

class cWorld
{
    public:
        cWorld(){map=NULL;};
        virtual ~cWorld(){delete map;};
        void CreateMap(int w, int h){map=new cMap[w*h];};
    private:
        cMap *map;
};

int main()
{
    sf::RenderWindow App(sf::VideoMode(1024,768, 32), "SFML Graphics");

    cWorld world;
    world.CreateMap(40,40);

    App.UseVerticalSync(true);
    App.SetFramerateLimit(60);

    while (App.IsOpened())
    {
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
                App.Close();
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App.Close();
        }
        App.Clear();
        App.Display();
    }

    return EXIT_SUCCESS;
}

Waterlimon

  • Newbie
  • *
  • Posts: 7
    • View Profile
game engine question 2
« Reply #5 on: July 05, 2011, 05:52:13 pm »
I think you should only keep the tiles of the current map in memory, and when u go to another map, load the new maps data from a file and save any changes that were made to the other map to the other maps file.
This sententace makes me more unique. Too lazy to upload avatar. Nobody reads usernames.