RPG game engine reflexions

Page 1/4
| 2 | 3 | 4

By Metalion

Paladin (982)

Metalion's picture

14-05-2018, 09:05

Hi everyone,

I'd like to make a versatile RPG game engine in SCREEN5. The screens would be made of 8x8 tiles, but I'm wondering how to organize this correctly. For instance, there will be : walls, floors, doors, objects, things to interact with ...

So far I've found 2 options :
1) break down the 256 available tiles into families, therefore having a limited amount of tiles per family (eg. only 16 tiles for the walls, 16 walls for the floors ...)
2) add a second byte to specify the nature of the tile (eg. 3F 02 would be tile number 3F within the 2nd family of background tiles), therefore multiplying by 2 the data necessary to describe a screen

Is there other options ?
What's your experience ?

Thanks Smile

Login or register to post comments

By wolf_

Ambassador_ (9724)

wolf_'s picture

14-05-2018, 10:22

Ah, ye olde RPG-engine!

Ideas:

Store a tile in 9 or 10 bits so that you have access to 512 or 1024 tiles. With the remaining 6 or 7 bits you could define wall/walk and still have some bits left to add events to a tile (start dialogue, open chest, trigger a demo etc.).

Don't store individual tiles in your map, but store stamps/macros. A tree could have a size of 4x8 tiles (32 x 2 bytes = 64 bytes) when stored as a bunch of tiles, or you could store a stamp at a location, then you'll have one complete tree in memory, and then for each tree in your map only a few bytes for x, y, and a pointer to the macro. Same with large patches of grass, sea, a repeating patch of trees, a complete rooftop, a wall, a window etc.

Keep in mind that if your player is able to walk behind things (tree, round rooftop etc.) then you'll need a see-through mechanism. You could think of:
- tiles 0-63 = walkable
- tiles 64-127 = walkable with overlay, an extra tile without background from another location is then redrawn on top of the player, meaning you can stand behind a tree
- tiles 128 - 191 = not walkable
- tiles 192 - 255 = walkable with non-transparent overlay (player disappears completely behind it)

In any case: the biggest challenge isn't even the map, it's not even the demo engine, not even the text display, but everything together. Cool

By DarkSchneider

Paladin (771)

DarkSchneider's picture

14-05-2018, 13:09

Solid and non-solid. Interactive ones would probably be better to do them GameObjects. So they paint over the background, and gives you more flexibility for its behavior.

You could add a 3rd category for tiles, special. Then the code itself would do the required thing depending the number (i.e. spikes to get damage, or hole to fall down to the floor below).

By Grauw

Enlighted (7795)

Grauw's picture

14-05-2018, 13:21

Indeed you can associate collision properties with tiles. Doing this for pre-set tile ranges is the most compact storage method, but I think this gets annoying pretty quickly. I know Daemos ended up having various level-specific hacks in SMW to work around range restrictions as more levels were created (and would’ve become annoying to remap all existing levels). I’d say it’s easier to just make a 256-byte lookup table so you can freely set collision IDs (or handler pointers) based on a tile ID, without being restricted in your tile set layout.

However although collision does often map to specific tiles, if you want to have various triggers and such you’ll need to duplicate tiles for those, a bit of a waste if you don’t have so many already. What you can also do is to store the collision information in a completely different tile map layer, and just paint it over your background. This does mean doubling the tile map data size, but I think it can be quite convenient and flexible. I would personally be not so worried about the size.

Alternatively you could have a Tile object for each tile type, and then have the map be an array of tile references. This is what I do currently, in some ways it’s nice but maybe better to keep things simple at first. Benefit is I can add arbitrary properties to the tiles and have e.g. two tiles with different collision but the same bitmap, but whether it’s really worth the extra indirection...

Note that I’m personally a fan of 16x16 tiles... 8x8 tiles run out fairly quickly, are slower to copy to the screen, and require bigger tile maps. Though they are a natural choice if you want to have an 8x8 scroll. If you do use 8x8 tiles, a set of 256 might suffice but I would keep in mind the option to have 1024.

As for stamps, you could do that but then still I think in-memory it’s better to convert it to a tile map on load, otherwise it seems the scrolling code will be a pain. It also adds a fair amount of extra complexity and code which will take time to write and maintain. If you’re really strapped for memory I guess it could be a choice, but otherwise I would go for the simplest possible approach.

I would also suggest to put the status area in the top or bottom of the screen with a screensplit... then you can use the vertical offset and horizontal adjust registers to accelerate the scrolling.

By wolf_

Ambassador_ (9724)

wolf_'s picture

14-05-2018, 13:38

Metalion hasn't specified 'scrolling'. Let me point out that Randar III doesn't scroll, and it's a great game to play.

By Metalion

Paladin (982)

Metalion's picture

14-05-2018, 15:08

Thanks already for all those idea (stamp, game_object). So if I read you right, guys, the main idea is to have globally 2 bytes per tile, either linked to the tile or not. The idea of painting the collision/behaviour map over the background map seems like a good one.

Indeed I have asked myself several times the question about the tiles' size (8x8 or 16x16), each of them having specific advantages.

And there will be no scrolling, it will be only a full screen change.

By Grauw

Enlighted (7795)

Grauw's picture

14-05-2018, 15:32

Keep it simple I guess would be my main advice Smile. Work iteratively. You can always complicate it later when needed. But lately I've had several times already where I made something overcomplicated, slow and a hassle to work with, plus a lot of time stuck in thoughts about the perfect design, only to throw it away later and replace it with something much simpler which did the job just fine with more speed and sometimes also more flexibility.

By hit9918

Prophet (2825)

hit9918's picture

14-05-2018, 15:53

Quote:

add a second byte to specify the nature of the tile

at this point you can just as well afford a 16bit nametable!
it can have more than 256 tiles
the nice thing is when the 16bit tile number is a z80 address and then the flags go directly like
bit 0,(hl)

to get at the pixel data
inc hl
ld e,(hl)
inc hl
ld d,(hl)

every tile number is an address of struct DB flags, DW pixels
it can give different flags to the same graphics

anyways how do you normaly calculate the address of the tiles pixels
tile number in L
ld h,0
add hl,hl
add hl,hl
add hl,hl
well that was multiply by 8 for msx1
but on screen 5 a tile has 4x8 bytes
but what if you want the tile in onscreen format for blitter
the pixel address is ???YYYYYXXX00000
ouch

meanwhile the struct can have all shit precalculated
DB flags, DB blitter SX, DB blitter SY

By DarkSchneider

Paladin (771)

DarkSchneider's picture

14-05-2018, 17:34

The idea of split gfx and behavior is tempting, but think it takes double space. So your maps should be halved compared to one single array. Is a hard decision.
In the case of 2 bytes, use separate arrays, this is because if not you can't use the INC instructions for iteration (well, you have to do 2 INCs).
So, think we have i.e.:
struct Tile {
BYTE gfx;
BYTE flags;
}
Tile map[];

This would be better like:
struct Map {
BYTE gfx[];
BYTE flags[]; // both same size
}
Map map;

Then flags could get values like:
1 = collides to up
2 = collides to right
4 = collides to down
8 = collides to left
16 = damage
...
128 = custom (gfx value dependant, the code reads the gfx value and use its own behavior)

You know, simply are ideas. But using double space...is a hard choice.

Also, is not easy to get a map editor that allows to set data per tile. And is extra work to set all those values when creating the maps. So think about it carefully.

As said, using only 1 byte and all the other stuff using GameObjects (doors, chests, etc.) placed at their corresponding location (like if it was a tile) could also be a good solution.

A good solution to handle the multiple direction collisions (up, right...), and also gives flexibility, is allow to set the ranges dinamically, instead defining them statically. So each area (map) could define its own ranges for each type of collision:
[all, up, right, down, left, horintally (both left and right), vertically].
Notice that they can get zero value.
Each range goes from the previous one to adding its value, starting from 0 for the all directions one (the first).

By Grauw

Enlighted (7795)

Grauw's picture

14-05-2018, 17:57

In Tiled it's pretty easy to set either custom per tile collision properties or have a separate collision layer. The hardest work is to have a conversion script to your tile map format for MSX Smile.

By Metalion

Paladin (982)

Metalion's picture

14-05-2018, 20:19

Collision / behaviour is one of the disadvantages of 16x16 tiles.
You loose some precision in the screen interaction, versus an 8x8 tile.

Page 1/4
| 2 | 3 | 4
My MSX profile