Jump to content

  • Log In with Google      Sign In   
  • Create Account

Storing level data in grids

  • You cannot reply to this topic
7 replies to this topic

#1 Ikazrima   Members   -  Reputation: 122

Like
0Likes
Like

Posted 21 August 2014 - 12:25 AM

Hi all,

I am using an old game level data, and have managed to extract the relevant information.

The way the game stores the level is each has about 24 rooms in it , with every room made up of 3x10 tiles. The rooms are linked by having each room stores the link data of what room is on it's left, right, up and down.

Now, I'm thinking of storing all the rooms into a grid-based map (eg 10x10 rooms), without the need the store each links in each room.

What is the best way to store all of this grid data? I'm making this game to be mod friendly, so the player can change how big the level is by changing the grid size. Storing it in an array will make it static? I thought of using list, but I'm not sure what information should I store in it (whether I should store the x and y axis, etc.)

[Edit]

This is a 2d game, by the way. :)

The reason I'm trying to ditch this sort of linking because of in the old game, only one room is drawn at a time. I want to make my remake to have some sort of a continuous feeling sort of? I want to be able for the camera to follow the movement of the player instead of staying static (which is what I have right now. It follows the classic game feel in navigating the levels, one room at a time)

The other reason is I've never actually made a level editor before, and I was thinking of instead of only seeing and only able to modify one room at a time, why not made it one whole giant canvas so that I could implement some sort of a paint function to modify the tiles between different rooms.

[/Edit]

Thanks for your thoughts.


Edited by Ikazrima, 21 August 2014 - 02:14 AM.

Live by your actions, die by its consequences.

Sponsor:

#2 haegarr   Crossbones+   -  Reputation: 4309

Like
2Likes
Like

Posted 21 August 2014 - 01:59 AM

Explicitly modelled exits (and perhaps also entrees) grants a much greater flexibility:

1.) They allow the rooms to be stored in sequence in any order, since the rooms are linked.

2.) They allow also for not having an exit on a particular side.

3.) They allow to have more than a single exit on a particular side.

4.) They simply support for varying room forms and sizes.

5.) They give you a natural place where door locking happens.

6.) They give you a natural place for "look at exit" belonging data (if your game allows for that).

7.) They give you a place where specific onExit and onEnter handlers can be placed.

 

They allow for some spurious behavior, too:

8.) Conditional re-linking allows magic passages or adaptable mazes.

9.) Random choose from a set of entrees attached to a specific exit allows for spurious room sequels.

 

That said, I would not drop the mechanism of explicit exits / entrees without a good reason. However, you don't gave any detail in your opening post, so I may not aware of such good reasons you may have.


Edited by haegarr, 21 August 2014 - 02:01 AM.


#3 Ikazrima   Members   -  Reputation: 122

Like
1Likes
Like

Posted 21 August 2014 - 02:25 AM

Hi haegarr, thanks for your reply.

I've updated my first post to give you an idea of what I'm trying to do. Regarding your points, I can see why explicitly modelled exits is good. Thank you. :)

Actually I wanted to make an editor similar to this,
 RoomShaker1_big_0001.png

that's why I thought of storing the level structure in grids. If you could suggest a way on doing this without changing how the old level works, I'd appreciate it.


Live by your actions, die by its consequences.

#4 Ikazrima   Members   -  Reputation: 122

Like
0Likes
Like

Posted 23 August 2014 - 11:52 AM

No love? :(
I'll give a cookie *an imaginary one* :)


Live by your actions, die by its consequences.

#5 haegarr   Crossbones+   -  Reputation: 4309

Like
1Likes
Like

Posted 24 August 2014 - 04:50 AM

I'm quite not sure what your goals are. The original mechanics seems me to be a 2D map (called "room") in side view, build by predefined tiles, a non moving sight, where explicitly modeled exits are used to switch over to the next room. You want a concept where switching rooms is no longer done, but the sight is moving so that the player avatar is more or less centered on the screen every time, and portions of the level (e.g. formerly other rooms) scroll in synchronous to the movement.

 

First issue may be that you deprive yourself of going into the 3rd dimension. An explicit exit may not only lead up, down, left, or right, but also backwards and forwards, and it allows to use an elevator or stairs in the backdrop (I remember such a feature in this kind of games).

 

Second issue is that, although you don't need exits from room to room in a level if you simply follow the concept "one room one level", you still have to model the transit from one level to the next.

 

Now coming to the question of how to store the data.

 

First of, notice that the data format in the editor and the data format in the game need not be identical. If you think about the different requirements in those use cases, you probably see that a structure suitable for the one case is not so suitable in the other. In the editor, you want to check whether a place is covered, move tiles around, check for validity / playability, and so on. During gameplay you are interested in whether movement in a direction is possible, a trigger must be fired, and so on. This means that the editor need to either distinguish between saving a project from saving a game level, or it needs to interpret the data in another way than the game engine.

 

Second, you have to decide whether you want to use blobs or regular structures. In the former case you load the level data and that's it. This is called "in-place loading". It shortens load time (okay, not to do much in that kind of game anyhow) since preparation is already done by the editor before saving, but it may require a more sophisticated addressing scheme. The latter case (regular structures) means to load data into a buffer, and building a new structure from it during interpreting the data. For example, you make a std::map (when using C++) from it, where the key in the map is given by the tile index.

 

Third, you have to think on the density of the map: How many holes may be there (i.e. where no tile is placed simply because the player cannot reach that tiles anyway)? A full grid makes sense mainly if holes are rare and small. For a sparsely covered map a linking scheme would be more efficient.

 

In a game like shown probably neither load time nor memory footprint are hard conditions, so probably any way will work. My personal preference is to "compile" editor data into game data, and to use in-place loadable blobs for game data.

 


... a way on doing this without changing how the old level works ...

What features exactly you want to preserve?



#6 Ikazrima   Members   -  Reputation: 122

Like
0Likes
Like

Posted 24 August 2014 - 10:01 PM

The original game uses regular structures, and I've successfully replicated it. I've no problem in placing and constructing each levels using the old level data, which stores tiles indices.

Let's just say that I'm stuck on this part,

[--][O][O]
[O][O][O]

I want to place a new room I've created on the [--] grid, and I can't for the love of God figure out how the heck do I automate the process of linking the new room to the rooms below and right side.

If I don't use a grid-style editor, I can insert a new room based on an existing one, where I would just need to have an option to place the room on up,down,left and right of a selected room. It solves the linking to one room (lets say the room below of it), but not the rooms on its other sides.

I can eliminate the problem above just by doing manual linking, but I prefer if the player puts a room somewhere it will initially links with all the other rooms surrounding it.

I have tried using raycast, but the problem is that in a room there are certain parts where the tiles are empty, so the raycast might not hit anything even if there's a room next to it.

This seems like such a silly matter that I've been stuck on for quite a while. :(

Now about the feature that I want to preserve, it is that I want the user to have the option of navigating the rooms like the old game if they wish so. Based on your explanation, I think it is best for me to keep the linking structure. This is because the old game have many user created levels that have this 'magic links' for maze purposes. I'm trying to make the game as much compatible with previously created custom levels.

Again, thanks for your informative response.


Live by your actions, die by its consequences.

#7 haegarr   Crossbones+   -  Reputation: 4309

Like
2Likes
Like

Posted 25 August 2014 - 02:19 AM

I want to place a new room I've created on the [--] grid, and I can't for the love of God figure out how the heck do I automate the process of linking the new room to the rooms below and right side. ...

We're speaking of editor functionality here. What programming language do you use to program the editor? I'm using some pseudo code in the following:

 

Possibility 1: 2D array

 

Allocate a 2D array with the size specified within the level creation dialog, say N by M cells. The array stores pointers to Room structure instances. Initially the array elements are all set to nil, denoting that no room is associated with that cell. Each cell in the grid uses 2 numbers as address, directly useable as index into the 2D array. If a new room is placed at index (n,m), then the editor checks for neighbored rooms as follows:

if (n>0 and array2d[n-1, m] != nil ) then "room to the left exists";
if (n<N-1 and array2d[n+1, m] != nil ) then "room to the right exists";
if (m>0 and array2d[n, m-1] != nil ) then "room above exists";
if (m<M-1 and array2d[n, m+1] != nil ) then "room below exists";

What "room ... exists" may mean is explained below.

 

Possibility 2: 1D array

 

Perhaps 2D array are not your friend. There is this little trick with calculates a 1D array index from a 2D index. For a grid of N by M cells, an index (n,m) can be used to calculate

i := n * M + m

or alternatively

i := m * N + n

for an array of size N*M, of course.

 

Since this just is the indexing scheme, it can be hidden up until directly accessing the array, so the usage is the same as in possibility 1.

 

Possibility 3: associative map

 

The standard library of your programming environment supports an associative container, usually called a map or sometimes also dictionary. Such a map associates a key with a value. The key is the 2D index like above, or perhaps better the 1D index as shown above, while the value is a Room structure instance. A map has as many entries as rooms actually exist (as opposed to an array which has as many entries as cells are specified, i.e. equal to the amount of possibly existing rooms).

 

Asking a map for the existence of a room is a bit easier since an "index out of bounds" cannot occur. 

if (map(index(n-1, m)) != nil ) then "room to the left exists";
if (map(index(n+1, m)) != nil ) then "room to the right exists";
if (map(index(n, m-1)) != nil ) then "room above exists";
if (map(index(n, m+1)) != nil ) then "room below exists"; 

Again, what "room ... exists" may mean is explained below.

 

Possibility 4: sequence / vector

 

This possibility uses a self growing linear storage. As opposed to an array solution, there is not an entry for each cell but only for each existing room. The Room structure itself has a field that stores its own 2D or 1D index. Whenever you want to know whether a room exists, you iterate the sequence and compare the values of the stored room index fields with the given index. If such search is implemented as routine "lookup", it looks like so:

if (seq.kookup(n-1,m) != nil) then "room to the left exists";
...

And now ...

 

"room ... exists" in detail

 

So, when the above code enters an "room ... exists", you have to store the link correct inside the Room structure. Again, I don't know how this link should look like. You may store the pointer to the other room directly, or the 2D or 1D index. If we use "storage" for one of the possibilities shown above, that may look like so: 

if (storage(n, m))
    then "there is already a room in that cell"
    else {
        Room* newRoom = createRoom(n, m);
        Room* neighbor = nil;
        // looking to the left ...
        neighbor = storage(n-1, m);
        if (neighbor != nil)
            then {
                newRoom.leftNeighbor = neighbor;
                neighbor.rightNeighbor = newRoom;
            }
        // looking to the right ...
        neighbor = storage(n+1, m);
        if (neighbor != nil)
            then {
                newRoom.rightNeighbor = neighbor;
                neighbor.leftNeighbor = newRoom;
            }
        ... similarly for above and below ...
    }
}

Edited by haegarr, 25 August 2014 - 04:18 AM.


#8 Ikazrima   Members   -  Reputation: 122

Like
0Likes
Like

Posted 26 August 2014 - 10:18 AM

I'm using C#, and figure out it would be neat if I integrate the editor directly into the game.

At first I was thinking of making the grid like a cartesian plane [having the centre to be (0,0) instead of the top-left corner to be (0,0)]. This was what driving me nuts a bit, which comes back to my original question on what to store. My thoughts were going like this:- if I make the grid in 2d array, how do I move the centre grid (0,0) to the new index in the array should the player change the grid size? (I'm killing this question on my mind right very now.)

Reading your post, it all make sense now. I'm ditching my old thoughts, and will try to go with suggestion number 1, but may be using list instead of array since I still want to maintain the dynamic structure of the level grids.

Thanks very much for your post. I will get back to you once I've made progress and stumble on another bump. wink.png


Live by your actions, die by its consequences.





PARTNERS