RPG game engine reflexions

Page 3/4
1 | 2 | | 4

By Grauw

Enlighted (7321)

Grauw's picture

16-05-2018, 22:27

Talking about script, some suggestions on how to nicely script the scenario/quests/dialogues would be well appreciated. Preferably something low-effort but flexible… Maybe using macros, or plain code? Or is something interpreted better? Or condition-action pairs? And how to best store and query the state of the game progress?

By santiontanon

Hero (588)

santiontanon's picture

16-05-2018, 22:45

@Manuel: At the risk of hijacking the thread, we had big plans for MoG2 actually! in the Brain Games forums we had come up with a whole story line involving 4 playable characters (Popolon, Aphrodite, Pamperse and Selene (sister of Pamperse)), and a re-visit to the castle (but this time it would be in a ruinous state, with some parts flooded with water, some overgrown with vegetation, etc.), with some plot twists, etc. Maybe one day Smile Our original plan was for a PC game (since back then it was the "remake" period). But it'd make much more sense to do an MSX1/MSX2 game now!

By wolf_

Ambassador_ (9688)

wolf_'s picture

16-05-2018, 23:02

Grauw: I always had this idea about a kind of solid state machine. An array with big and small quests that contain 0 or 1. In my view: a text dialogue, aquiring an item, walking on a specific tile or location, defeating an enamy etc. should set specific quests to 0 or 1.

Like this SSM:

location: castle [0]
location: woods [0]
inventory: magic hat [1]
player level >=6 [1]
inventory: key [1]
inventory: bread [0]
inventory: soup [0]
inventory: orb [0]
inventory: book [0]
etc.

If going through a specific door requires you to have the magic hat, have >=6 exp and have a key, then this door should require these entries to all contain a 1. For that you don't need to script much.

If you need to show a wizzard that you have an orb, then currently the wizzard won't talk to you (or tells you to find the orb). So, the wizzard should somewhere require 'orb' to be 1.

You could allow certain dialogues only if certain quests in the SSM are fullfilled.

With this, you can run around the game and do things without much scripting (if any).

But hey, I'm a mere piano player, don't shoot me. ^_^

By Grauw

Enlighted (7321)

Grauw's picture

16-05-2018, 23:30

I see, so kind of a rule-based system with conditions… I guess I could define the keys as indices into a big state data object, followed by some comparison operators and a value, and then something that tells the game engine what to do.

…although that “something” is also not really clear in my head yet.

And I wonder how to look things up in that array quickly. Maybe associate every rule with at least a trigger collision ID (so everything must be triggered by a collider), so I can have an index table and do a tile-based lookup to only consider the rules which apply to my current location. Ok, that seems like a good combination of ideas… I’ll try it out.

By wolf_

Ambassador_ (9688)

wolf_'s picture

17-05-2018, 00:41

Finite State Machine, I meant... confused by a certain Konami game and a mixing console brand. Cool

By DarkSchneider

Paladin (716)

DarkSchneider's picture

17-05-2018, 10:58

The tools are a real pain, and easy to get stuck stealing your time. We moved so using already made tools, and we adapt to them, exporting the data to the engine format.
Notice that even we don't have on MSX a sprite mode 2 editor showing the OR operation. I though about a GIMP plugin, but not sure if they can show an operation in real time, as required.

Grauw wrote:

But then the question becomes, why are you making an engine? Smile Developing a generic engine means that features are added based on the programmer’s imagination rather than a practical use case, and it often ends up doing too much with too much abstraction. I see this in many frameworks. To avoid wasting my time on things that are not actually going to be used, and to keep the code simple and driven by need, frameworks are also something I’m not doing anymore.

Rather, I grow the code base organically as the game demands it, and then on the fly I extract reusable parts into a separate library. That’s how the "neonlib" that I’m using in my projects came into existence, essentially to consolidate the code copy/pasted between projects. The game I’m developing now has a nice core, but it’s still evolving based on the things I need. Once this is done and I start the next project, then I can extract the useful bits so that I have a good basis to start from and can go straight to implementing gameplay rather than scrolling or screensplits.

Not to say making an engine isn't fun or valuable, just, KISS and resist the temptation of abstraction and trying to fulfill every possible use case you can dream of. A restrictive engine which is quick to make and easy to use can be much more valuable than one which tries to take care of everything.

A concrete example, you know that putting spites on line 217 is a problem. You could make a sprite system which avoids this problem automatically, but the sprites code gets much more complex. Or you could say, this engine doesn't scroll vertically, or, it only scrolls in 2 pixel increments, or, the responsibility to work around it lies with the user. I chose the 2nd and 3rd option. But, people said, maybe sometimes you want to scroll by 1 pixel. That's what I mean, don't try to solve that, just say "Nope, sorry. Either just don't do that, or work around it yourself."

Well the reason is, do an engine, much work and blood, but then you have a game maker tool.

When the group met and decided to get into MSX development, curiously everyone had clear to do it with an engine (everyone put the same idea at the same time). There was multiple propositions, adventure engine (like Snatcher)... but I always wanted to use the MSX in a very little used way, more console-like style, at that moment what I wanted more is to make a Metroid. So I brought a code showing that currently is easy to do a scroll on MSX2. Seems the idea liked because the decision was unanimous. Then we started with the project (codename MSXtroid) and the engine that supports it.

Finally the engine was targeted to be the more generic, so with the same one could do a Metroid, Ninja Gaiden, Megaman, Gradius, Zelda (scroll version like SNES one), turn-based RPG or Penguin Adventure (yes, even this change). Think about something like Unity.

But, as you notice, it can't be (or not recommended) to be the all-of-everything. It is an open-featured engine, but with limits. Currently targeting SC4 (my favorite mode, the real game mode) gameplay loaded by areas, using SC5 for the layout area (where also the in-game events are shown). The good thing is like the logic is treated apart, in the future new modules could be added, i.e. SC5/7/8 to do conversational adventures.
By this way, an open-featured engine but defining limitations, you can solve some aspects like the sprite at line 217 (as in SC4 don't scroll to that line). In the future features could be added, but well that is the future.

It can be fun to make the engine, much software engineering and design, and when it works can be exciting (even when you see the results like text on the output console).
Also, we always look for the general way, but preserving the performance, then abstraction but with no speed cost. After getting something that works, simplify it removing all the layers to the minimal required ones, at the end the same that you need for the direct way. Simply put indirect calls for the objects, but that is not really a concern. Even doing directly, I think is not a good idea to hardcode the calls for every object, zero flexibility.

Grauw wrote:

Talking about script, some suggestions on how to nicely script the scenario/quests/dialogues would be well appreciated. Preferably something low-effort but flexible… Maybe using macros, or plain code? Or is something interpreted better? Or condition-action pairs? And how to best store and query the state of the game progress?

For scripting, use ALWAYS numbers, instead names. If you later want to specify in the specific game, define constants. This allow easy modifications, even from game to game, allowing easily to re-design the gameplay aspects.
We reduced the names to minimal, and more common, like x, y, life...very few. And, in any case, if an object does not use them like that, well it always can use for its own purposes, are usable bytes anyway.
Then, those numbers are converted using a look-up table (LUT) to its corresponding, could be load a resource (like an event), or code (a script), an item, anything.
Create a global structure for common data, and area local structure to store each area specific data, i.e. each character talk "position" (to show the corresponding text), if an already opened door or chest must remain opened...
Execute a script attached on each area load, that would read these strcutures and would modify the area itself after just loading, so you would play it in its current state. You could also execute a script on exit, if you think you need to do some work at that point (maybe freeing dynamic memory reserved on the start script).
You can simply save and restore sates by the fixed objects order (again using numbers). So if a character is the 3rd object inserted in the area, you know, it is easy to track it. Simply be sure the order is always the same (you don't put the fixed objects in random order each time).

We can look at Xak like example. The doors are simply objects, when you collides with it, it opens, this is change its tile and remove its collision. Then just above the door one, there is another object, that is simply a tile gfx and a collision, when you collide with it, depending on the object type, it triggers an event, shows a shop, or loads another area.

By Metalion

Paladin (961)

Metalion's picture

17-05-2018, 13:06

wolf_ wrote:

My problem usually starts with the dedicated editors I have to make. So, I end up making editors instead. ^_^

Oh yes ... Been there, done that !

But to tell you the truth, I did start this thread for a RPG game engine, but NOT a generic one. My idea is to build a RPG game engine and use it myself for 2 ou 3 games, which will share the same context and universe. So a part of your reflexions might not really apply (although they are really interesting).

I do not try to be generic, just to find a good solution within my context of use.

Smile

By DarkSchneider

Paladin (716)

DarkSchneider's picture

17-05-2018, 13:33

If you do some parts more generic can be used for different types of RPG. I recommend:

- Try to adapt your engine to use already made external tools (PC ones), simply doing converters to your engine data format.

- For the scripting part, always think about numbers, arrays, and how you can do things with them, like the example of the doors and events of a Xak I put before. As you see with something a bit more generic (object), you can do many things, like event handling, shops, portals to new areas, and more. No need to specify "a door", "a chest", "a shop point", "a talking point", and the so many variants that could have by its own. And easily expandable in the future.

By Grauw

Enlighted (7321)

Grauw's picture

17-05-2018, 14:10

Hey DarkSchneider, thanks for your elaboration, it’s definitely helping my thought process Smile.

Btw, actually there’s one thing I generally find even better than numeric IDs + constants + look-up tables (really enums & switches), and that’s direct references. Certainly on modern platforms this is one of my common practices to always favour references, on MSX it can increase the size from a byte to a word, so that may sometimes be a reason not to, but I still think it’s a good idea in general.

All my tools convert to asm code, so if there is some named object, it produces an assembler symbol with that name. This is what I do currently for tiles at least, and alhough currently my collision still works based on numbers, I’m probably going to change it to references as well.

As for local vs. persistent data, I’m currently thinking to just query my scene’s object structure instead of having a separate storage for data, so I can keep the data grouped in their a logical place. And then use serialisation and deserialisation to determine what is persistent and what is not.

By DarkSchneider

Paladin (716)

DarkSchneider's picture

17-05-2018, 17:00

In modern systems I also use references AKA names, but on a modest system like MSX I decided to simplify to numbers because they can be compared and changed on the fly at a much lower cost. In other words, the modest Z80 handles them better. Think comparing a string vs an integer number, on a modern system is not a concern (even on mobile ARM systems), on the Z80, doing it at load or initialization time is not a concern too, but in real time is something different.

Also, numbers fit better for converting from already made tools (not all of them allows to set words as objects data) to engine data. I.e. we currently use the tool Mappy ( http://www.tilemap.co.uk/mappy.php ) for maps, it allows to set integers as object data, but not strings. If I put a chest, I can easily assign the object it contains with a number-to-number (as they are the same), but string-to-number can become more complex.

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