Results 1 to 8 of 8

Thread: Objects on a tilemap

  1. #1

    Objects on a tilemap

    Hello.


    I would like to know what the “best”, most efficient way is to handle objects on a tile map. So far I have mostly done it with one huge array which was easy to implement but feels inefficient. This way I have to loop through each item on each frame to see whether it is on screen and should be rendered. Is there a nicer way of handling these kinds of objects?


    My previous code:
    Tmap = class
    public
    Tiles: array of Ttile;
    Objects: array of Tobject;
    end;



    Mostly I'm just curious what the "proper" way is of doing this. Maybe I am doing it completely wrong from the start.

  2. #2
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2
    Hi T-Bear,

    If you are storing an X,Y pair for each item in the Tiles and Objects array, then you can improve things quite a bit by moving to a two dimensional array.

    Code:
    Tiles : array[0..200,0..200] of TTile;
    Objects : array[0..200,0..200] of TObject;
    Which obviously has the limitation of hard coded sizes. If you're using a dynamic array where you work out an index like index:=x+(y*width); then providing you only iterate through the cells that appear in the visible area, you're not going to gain too much I wouldn't have thought by changing it.

    When I wrote a tile based game for one of our competitions, I used pointer based datastorage which is in fact much like the dynamic array with index calculations.

    Can you post some of the code where you are actually using the map?
    :: AthenaOfDelphi :: My Blog :: My Software ::

  3. #3
    Usually peopole use two dimensional arrays (array of array of TObect) instead of one dimensional one. This alows them to acces grid cell data by row and column numbers.

    If you have tilemap with fixed tile size (all tiles are of the same size) you can easily calculate which tiles are in your viewport from your camera position. For instance:
    Camera position is on X row and your viewport would render 21 rows. This would mean that you would need to check tile information in rows from X-10 to row X+10.
    Similary you calculate which columns would be rendered.
    So you end up having all necessary information to use for lops for reading information

    Another approach would be dividing your map into sections (chunks).

    Anyway if you provide more information about your game and general map structure we would be able to offer you better advice particulary more suitable to your game.

  4. #4
    Like said above, make the object array two-dimensional. Or, if you need to have multiple objects on a tile, then I'd add an array/list to TTile, which would hold pointers/array-indexes of objects standing on given tile.

  5. #5
    Hi T-Bear,

    If you are storing an X,Y pair for each item in the Tiles and Objects array, then you can improve things quite a bit by moving to a two dimensional array.

    Code:
    Tiles : array[0..200,0..200] of TTile;
    Objects : array[0..200,0..200] of TObject;

    How would this work if the objects are larger than a single tile though? Basically on the map there are buildings which can span many tiles, and trees which are on a single tile.
    As you said this probably won't work with dynamic size of the objects.

    When I wrote a tile based game for one of our competitions, I used pointer based datastorage which is in fact much like the dynamic array with index calculations.
    How exactly would this work? Pointers from each tile object to the object on the tile? How would this work with objects larger than single tiles?

    Can you post some of the code where you are actually using the map?
    Anyway if you provide more information about your game and general map structure we would be able to offer you better advice particulary more suitable to your game.
    I am mostly just doing some information gathering for my new project, reading about stuff and so on, so I don't have any code sample for how the map structure is going to work exactly. I tried finding some old code illustrating how I did this, but couldn't find any.

  6. #6
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2
    The objects that I had that were bigger than a single tile were broken up into multiple tiles. By doing this I was able to create the illusion of depth by drawing them on different layers relative to the player so the 'front' were rendered behind the player while the 'back' was rendered in front of the player.

    But, back to your question... how could this work if the objects are bigger than a tile? Good question

    I'm not sure and it's not a solution I would pursue personally because of the overheads involved.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  7. #7
    Your original solution was almost perfect, but you are right, on larger maps it would get lower performance. Thus you can divide your map into chunks.

    Code:
    const CHUNKSIZE = 32;
    
    TChunk = class
    public
      posX, posY: integer;
      Tiles: array[0..CHUNKSIZE-1, 0..CHUNKSIZE] of TTile;
      Objects: array of TObject;
    end;
    
    TMap = class
    public
      Chunks: array of array of TChunk;
      function GetTile(x, y: integer): TTile;
    end;
    
    function TMap.GetTile(x, y: integer): TTile;
    var cx, cy: integer;
    procedure
      cx:=x div CHUNKSIZE;
      cy:=y div CHUNKSIZE;
      result:=Chunks[cx, cy].Tiles[x-cx, y-cy]
    end;
    Or something along these lines... Of course you could do range checking in GetTile() to avoid critical errors on negative values or out of boundaries.

  8. #8
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    Location
    Spokane,WA,Usa
    Posts
    206
    if I were trying to do someting like this I would use an 8bit index map and use index 0 as a null. the background would be for normal size tiles while the forground would be for larger tiles. then I would add a clip frame that reperesents the view able portion of the map. now all you have to do is move the clipframe around within the map to change the view. on the forground the indexed position would be the top/left and all indexes underneath it would be 0's. your clip frame would have to be larger then the actual view so if a larger tile were half on it would still be displayed.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •