Jump to content
  • Advertisement
Sign in to follow this  
Scottehy

2D Tile Engine, should I change my current Design.

This topic is 840 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey Guys!

 

So I've resumed programming again after a long break. Due to other work. I started working on a Tile Engine this time, and the game is starting to become larger. So I'm wondering how I should change my design and data storage.

 

I'll delve right in and make it as simple as possible, I'm using C# with Monogame for everything.

 

So right now the design works like such, and of course is working. I get no lag or issues so far, interactions between objects are all fine.

 

I have a Grid at the moment that is 200 by 200 of a class called Cell. Each cell is 32x32 pixels big. The grid is stored as a 2D array[,]. 

Cell contains:

  • A pointer to a Node class, which can be an NPC, Player, Furniture etc
  • A base layer, Floor/Wall etc which are enums and a string, the string is a key for pulling textures from my TextureManager Dictionary
  • A bool for checking if this tile is occupied or not. This helped for A* path finding etc

The actual NPCs are contained in just a plain old c# List<NPC> etc. Same with furniture and other objects that aren't a base Wall or Floor. The reason I separated all this is so when I iterate through a cell, I can render all of that cells objects. So for example, in my drawing call. I iterate through only the cells we can see on screen. Then do a Draw call to the floor. I then iterate again and draw from top to bottom, the wall, npc's/player and furniture etc. This way the tiles that are taller than 32 pixels render correctly and don't overlap objects incorrectly. But this isn't the issue, I know I could just use a depthlayer in my spritebatch draw call to fix up it's z ordering.

 

The view is like an oldschool pokemon / zelda game. Where the characters are 1.5 tiles in height (32x48), and the walls are 2 tiles in height (32x64) etc. So these have no issue in size, due to I can just consider them a single tile. 

 

So the first issue I run into now, is objects that are bigger than a single tile (not just the texture) but rather say a table that is 3x2 tiles in size. Seeming as I was storing an objects pointer in each cell, it allowed for very simple collision, (if I want to move right, is the cell.occupied etc). How should I go about this, should I store it to a pointer in the cell still, and just mark the extra 5 tiles it would take up as occupied? Or should I store it in all 6 cells for collision/interaction sake, but mark 5 of them not to update/draw.

 

Or should I be totally redesigning how larger items are stored? And totally revamp my array[,] / List<objects>. This is where I'm wondering if I should be using a Dictionary for objects as well, and make they key a Point, so I can just type in a cell location technically to get the object out that way? I'm sure there is a much simpler way or design for this, so I'd love to hear some thoughts.

 

 

 

This part might look a bit of a mess, just trying to get what's in my head down into words.

 

The next thing is about expanding the map. I'm asking this now as it will relate to the above in how I change my data storage. I want to go on the same sort of design as a pokemon game. Where you have a large map that is loaded in chunks (each chunk on the world map with be same same size), and when you enter a building you're technically just loading a single chunk.

 

I don't have an issue with how to do this as much, but more so what should I be storing it all in? Should each chunk be stored in a text file, for example a simple drawn map where 0 = floor, 1 = wall, 2 bench and so forth (during editing stages). Which is then loaded into an 2D[x, y] size array. 

 

Said Array would be stored in a 2x2 array that loads 4 maps at once, providing you were in a corner of a a map etc. 

 

Another question I have about the above though, is when changing chunks, should I be wrapping everything position? So we're always in more of a local location design.

 

Any thoughts and comments would be much appreciated. Or links to some well designed tile engines. I've read through far to many tutorials but most of them seem to fall short of something fantastic.

 

Cheers,

Scott.

Share this post


Link to post
Share on other sites
Advertisement
So the first issue I run into now, is objects that are bigger than a single tile (not just the texture) but rather say a table that is 3x2 tiles in size. Seeming as I was storing an objects pointer in each cell, it allowed for very simple collision, (if I want to move right, is the cell.occupied etc). How should I go about this, should I store it to a pointer in the cell still, and just mark the extra 5 tiles it would take up as occupied? Or should I store it in all 6 cells for collision/interaction sake, but mark 5 of them not to update/draw.

One alternative could be to store a reference to the table in all 6 locations, and have a base-location also stored in the table. Drawing can be decided by comparing the location with the table base-location. That looks like it would keep most things as-is, except you have to compare locations with base locations often.

 

If you're worried about drawing only, you could keep a set of objects to draw, where the table would drop out for the other locations, as you already added it.

 

 

... but more so what should I be storing it all in? Should each chunk be stored in a text file, ...

I would do so as it is the simplest way.

You need some form of adding new levels to your game, and a text-file is a simple way to do that.

 

If you ever decide to go for something else, you can either rewrite the levels you already have, or write a conversion from loaded in the game back to whatever new format you have then.

Share this post


Link to post
Share on other sites

Hey Guys!

 

So I've resumed programming again after a long break. Due to other work. I started working on a Tile Engine this time, and the game is starting to become larger. So I'm wondering how I should change my design and data storage.

 

I'll delve right in and make it as simple as possible, I'm using C# with Monogame for everything.

 

So right now the design works like such, and of course is working. I get no lag or issues so far, interactions between objects are all fine.

 

I have a Grid at the moment that is 200 by 200 of a class called Cell. Each cell is 32x32 pixels big. The grid is stored as a 2D array[,]. 

Cell contains:

  • A pointer to a Node class, which can be an NPC, Player, Furniture etc
  • A base layer, Floor/Wall etc which are enums and a string, the string is a key for pulling textures from my TextureManager Dictionary
  • A bool for checking if this tile is occupied or not. This helped for A* path finding etc

The actual NPCs are contained in just a plain old c# List<NPC> etc. Same with furniture and other objects that aren't a base Wall or Floor. The reason I separated all this is so when I iterate through a cell, I can render all of that cells objects. So for example, in my drawing call. I iterate through only the cells we can see on screen. Then do a Draw call to the floor. I then iterate again and draw from top to bottom, the wall, npc's/player and furniture etc. This way the tiles that are taller than 32 pixels render correctly and don't overlap objects incorrectly. But this isn't the issue, I know I could just use a depthlayer in my spritebatch draw call to fix up it's z ordering.

 

The view is like an oldschool pokemon / zelda game. Where the characters are 1.5 tiles in height (32x48), and the walls are 2 tiles in height (32x64) etc. So these have no issue in size, due to I can just consider them a single tile. 

 

So the first issue I run into now, is objects that are bigger than a single tile (not just the texture) but rather say a table that is 3x2 tiles in size. Seeming as I was storing an objects pointer in each cell, it allowed for very simple collision, (if I want to move right, is the cell.occupied etc). How should I go about this, should I store it to a pointer in the cell still, and just mark the extra 5 tiles it would take up as occupied? Or should I store it in all 6 cells for collision/interaction sake, but mark 5 of them not to update/draw.

 

Or should I be totally redesigning how larger items are stored? And totally revamp my array[,] / List<objects>. This is where I'm wondering if I should be using a Dictionary for objects as well, and make they key a Point, so I can just type in a cell location technically to get the object out that way? I'm sure there is a much simpler way or design for this, so I'd love to hear some thoughts.

 

 

 

This part might look a bit of a mess, just trying to get what's in my head down into words.

 

The next thing is about expanding the map. I'm asking this now as it will relate to the above in how I change my data storage. I want to go on the same sort of design as a pokemon game. Where you have a large map that is loaded in chunks (each chunk on the world map with be same same size), and when you enter a building you're technically just loading a single chunk.

 

I don't have an issue with how to do this as much, but more so what should I be storing it all in? Should each chunk be stored in a text file, for example a simple drawn map where 0 = floor, 1 = wall, 2 bench and so forth (during editing stages). Which is then loaded into an 2D[x, y] size array. 

 

Said Array would be stored in a 2x2 array that loads 4 maps at once, providing you were in a corner of a a map etc. 

 

Another question I have about the above though, is when changing chunks, should I be wrapping everything position? So we're always in more of a local location design.

 

Any thoughts and comments would be much appreciated. Or links to some well designed tile engines. I've read through far to many tutorials but most of them seem to fall short of something fantastic.

 

Cheers,

Scott.

 

Your initial mistake is to put everything in a "cell" to make all system works.

I'd first seperate graphics from logic, meaning containing a player in a different field and not in a tile, this way the tile doesn't need to update itself whenever something moves.

it's just there.

Secondly, for you first issue, if you implement it as i've mentioned, you'd have a table somewhere (in a level class for example) and it would take 3x2 on starting point (1,1) (just an example).

The calculations are very straight forward (first grade math).

This is just an idea, it won't suit you 100% so try to tweak it for your own needs.

-------------------------

How you've chosen to implement it shows an amatuer perspective about code design.

An engine should suit you for all your need and your future needs. (or at least don't make it hard to implement new things).

First pause your project and learn how to design better, learn the SOLID principles and other game-development related principles. 

Take an existing tile engine (Find an open source) and read the code. Learn before you write. 

Share this post


Link to post
Share on other sites

I have a Grid at the moment that is 200 by 200 of a class called Cell. Each cell is 32x32 pixels big. The grid is stored as a 2D array[,]. 

Cell contains:

  • A pointer to a Node class, which can be an NPC, Player, Furniture etc
  • A base layer, Floor/Wall etc which are enums and a string, the string is a key for pulling textures from my TextureManager Dictionary
  • A bool for checking if this tile is occupied or not. This helped for A* path finding etc

 

Some thoughs:

 

- If I read it correctly, there can only ever be one "Node" in a cell, right? Does it really make sense in your case to have it this way? This can be a major restriction, and while I know some tile systems handle it this way (Rpg-Maker, ...), I find it a major bummer in most cases.

What about pixel movement? What about if you have a 2-tile wide door that you want to guard by a 1 tile-wide guard? What if there ever need to be multiple objects per tile (objects without passability, objects spawned by another object, projectiles, ...).

So unless I'm mistaken about how you though about that, this is an unnecessary restriction. If you ever need something like A* or a grid-like movement system, you build it on top. Other than that, you should basically allow objects to be places whereever they want (in an editor, add a button to allow toggling a grid-lock), and as many as they want.

 

- What type of tile-maps do you want to build? Generally, having one texture identified by string per tile is a major waste of productivity. Most tilesystem (Rpg-Maker, Tiled...) Allow you using a Tilemap (composition of multiple tiles in one texture), and then have some paint-tool to allow to easily paint a tilemap like you would a picture.

Ok, depending on how many tiles you have you could even have them as separated textures (in my case, most tilesets have 500+ different tiles so thats a no-no),. But even in this case you *need* a system for abstracting this concept away. I'm not going to fill a 100*100 tilemap with all strings to different textures, and so is nobody else. So a brush tool also  makes sense in this case, just instead of storing a tile-id, you store the texture-reference.

Share this post


Link to post
Share on other sites

@Alberth - That's how I was thinking of implementing it, I just wasn't sure if it was over or under kill. 

 

@WoopsASword - The cell itself only contains pointers to objects. As in the active solid object in it. So for physical updates, they're handled outside the cell. The cell just happens to have access to what's in it for interaction purposes. I tried to lock everything to the grid though, for the sake of voiding real collision. The player/npc though is actually separate from the cell. What I have at the moment is more of a prototype, more the reason to see how others would do it and their thoughts. As for drawing textures, they're all stored on a single texture / tile map. I have a dictionary that holds info about about what part of that texture to draw / animate. 

 

Changing code / scrapping code / rewriting code is no issue, I'm just working out what will fit best before I add actual gameplay mechanics. I just want to make sure I'm heading in the right direction. 

 

---

 

@Juliean - There can be more than one Node in a cell, they're designed to be able to look at more than a single object. As for your guard and door example. In games like this I've played. They usually have 2 guards, or a guard that's scripted to quickly move in front of the player to block them. The game has no fast action or movement though, so projectiles and spawned objects have no issues fighting for room on the grid. I have pathfinding already in place as well, working fine with no issues. I do have all my level textures contained in a single texture. The string is just the key in the dictionary to pull out a certain texture. Etc "WOODWALL_TOPLEFT" would return me the source rectangle of the section I'm looking for, on my tilemap texture.

Share this post


Link to post
Share on other sites
There can be more than one Node in a cell, they're designed to be able to look at more than a single object. As for your guard and door example. In games like this I've played. They usually have 2 guards, or a guard that's scripted to quickly move in front of the player to block them. The game has no fast action or movement though, so projectiles and spawned objects have no issues fighting for room on the grid. I have pathfinding already in place as well, working fine with no issues.

If you have a specific case that fits this, its fine :)

 

I do have all my level textures contained in a single texture. The string is just the key in the dictionary to pull out a certain texture. Etc "WOODWALL_TOPLEFT" would return me the source rectangle of the section I'm looking for, on my tilemap texture.

Well but how do you actually build the tilemap? Do you really have to type WOODWALL_TOPLEFT in the specific cell to select this tile (I'm using you have or plan on having an editor)? I don't know how exactly your tilemaps are laid out but for anything more than like 20 tiles per screen, this sounds like an enormous pain. Might not be an issue with the design, but if you plan on making a content-heavy game with lots of different locations, you are going to spend a huge ton of time remembering and typing in repeated names of tiles, unless you have the proper toolset to automate this.

Share this post


Link to post
Share on other sites

 

There can be more than one Node in a cell, they're designed to be able to look at more than a single object. As for your guard and door example. In games like this I've played. They usually have 2 guards, or a guard that's scripted to quickly move in front of the player to block them. The game has no fast action or movement though, so projectiles and spawned objects have no issues fighting for room on the grid. I have pathfinding already in place as well, working fine with no issues.

If you have a specific case that fits this, its fine :)

 

I do have all my level textures contained in a single texture. The string is just the key in the dictionary to pull out a certain texture. Etc "WOODWALL_TOPLEFT" would return me the source rectangle of the section I'm looking for, on my tilemap texture.

Well but how do you actually build the tilemap? Do you really have to type WOODWALL_TOPLEFT in the specific cell to select this tile (I'm using you have or plan on having an editor)? I don't know how exactly your tilemaps are laid out but for anything more than like 20 tiles per screen, this sounds like an enormous pain. Might not be an issue with the design, but if you plan on making a content-heavy game with lots of different locations, you are going to spend a huge ton of time remembering and typing in repeated names of tiles, unless you have the proper toolset to automate this.

 

This is more why I was saying, here is the prototype/implementation on how I'm doing it. Who has some advice for me on how I should do it. I did it this way after researching and reading a few tutorials I found on tile engines.

 

I have an artist that is giving me for example, a texture with X floor tiles, X wall tiles, X npc frames, then a text file that contains
#WOODWALL_TOPLEFT, #location(x, y, width, height) #framecount if there are more than 1 frames (npc walking etc). This is all parsed through a custom loader that sets it all up for me. Thus allowing me to call a string key of WOODWALL_TOPLEFT in the dictionary. 

Share this post


Link to post
Share on other sites

As a minor nit, I'd probably change your string to a hash, generally there's no reason a string should be used internally anywhere.   This could decrease your Cell size by quite a bit.

Edited by ferrous

Share this post


Link to post
Share on other sites

@Alberth - That's how I was thinking of implementing it, I just wasn't sure if it was over or under kill. 

 

@WoopsASword - The cell itself only contains pointers to objects. As in the active solid object in it. So for physical updates, they're handled outside the cell. The cell just happens to have access to what's in it for interaction purposes. I tried to lock everything to the grid though, for the sake of voiding real collision. The player/npc though is actually separate from the cell. What I have at the moment is more of a prototype, more the reason to see how others would do it and their thoughts. As for drawing textures, they're all stored on a single texture / tile map. I have a dictionary that holds info about about what part of that texture to draw / animate. 

 

Changing code / scrapping code / rewriting code is no issue, I'm just working out what will fit best before I add actual gameplay mechanics. I just want to make sure I'm heading in the right direction. 

 

---

 

@Juliean - There can be more than one Node in a cell, they're designed to be able to look at more than a single object. As for your guard and door example. In games like this I've played. They usually have 2 guards, or a guard that's scripted to quickly move in front of the player to block them. The game has no fast action or movement though, so projectiles and spawned objects have no issues fighting for room on the grid. I have pathfinding already in place as well, working fine with no issues. I do have all my level textures contained in a single texture. The string is just the key in the dictionary to pull out a certain texture. Etc "WOODWALL_TOPLEFT" would return me the source rectangle of the section I'm looking for, on my tilemap texture.

That's the issue, why the tile needs to know wherever it holds something or not?

A tile is a tile, a pure logical seperation in the map.

Holding "just a refernece" doesn't make it any more valid. 

The first rule that you should follow is try to reduce coupling between different logics.

When you have something that "must know everything" it soons turn into a god class or just a class with too much knowledge about different systems.

This makes harder to implement new features or replace existing systems.

For A* you'll need to know something, but if you want a different AI system? You'd have to hardcode properties all over again. 

Edited by WoopsASword

Share this post


Link to post
Share on other sites

As a minor nit, I'd probably change your string to a hash, generally there's no reason a string should be used internally anywhere.   This could decrease your Cell size by quite a bit.

I'd be changing it in the future, it's for simplicity and readability at the moment :) But you're absolutely right.

 

 

@Alberth - That's how I was thinking of implementing it, I just wasn't sure if it was over or under kill. 

 

@WoopsASword - The cell itself only contains pointers to objects. As in the active solid object in it. So for physical updates, they're handled outside the cell. The cell just happens to have access to what's in it for interaction purposes. I tried to lock everything to the grid though, for the sake of voiding real collision. The player/npc though is actually separate from the cell. What I have at the moment is more of a prototype, more the reason to see how others would do it and their thoughts. As for drawing textures, they're all stored on a single texture / tile map. I have a dictionary that holds info about about what part of that texture to draw / animate. 

 

Changing code / scrapping code / rewriting code is no issue, I'm just working out what will fit best before I add actual gameplay mechanics. I just want to make sure I'm heading in the right direction. 

 

---

 

@Juliean - There can be more than one Node in a cell, they're designed to be able to look at more than a single object. As for your guard and door example. In games like this I've played. They usually have 2 guards, or a guard that's scripted to quickly move in front of the player to block them. The game has no fast action or movement though, so projectiles and spawned objects have no issues fighting for room on the grid. I have pathfinding already in place as well, working fine with no issues. I do have all my level textures contained in a single texture. The string is just the key in the dictionary to pull out a certain texture. Etc "WOODWALL_TOPLEFT" would return me the source rectangle of the section I'm looking for, on my tilemap texture.

That's the issue, why the tile needs to know wherever it holds something or not?

A tile is a tile, a pure logical seperation in the map.

Holding "just a refernece" doesn't make it any more valid. 

The first rule that you should follow is try to reduce coupling between different logics.

When you have something that "must know everything" it soons turn into a god class or just a class with too much knowledge about different systems.

This makes harder to implement new features or replace existing systems.

For A* you'll need to know something, but if you want a different AI system? You'd have to hardcode properties all over again. 

 

I'm going to look at some other tile engines, see how they do things. Seeming as I want to make it much more large scale.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!