5
\$\begingroup\$

For a detailed survival RPG, the data that needs to be managed can easily become overwhelming if approached in an ad hoc manner.

First, you may want to do away with HP and instead have a system of wounds, where various body parts can be specifically injured and each injury requires individual attention. Attacks can be targeted and the effect of an injury depends on its location and how well it is treated.

The next obvious step is to manage clothing so that each piece of clothing covers particular body parts and provides particular armor values to each part. We also need to keep track of clothing conflicts, where two pieces of clothing try to cover the same area and so they can't be worn together, except when they are designed to be worn under or over other clothing.

In addition, there could be magical effects on certain body parts, or perhaps claws or spikes could be added. Perhaps various limbs could be replaced by cyborg parts, or magical parts. Even worse, perhaps there are creatures alternate body plans with more or fewer than the usual limbs.

Each limb can be divided into parts, so for example a leg consists of a thigh, a knee, a lower leg, and a foot. We want to manage those parts individually, but we also want to remember that together they represent a leg. We might need this so that targeted attacks aren't forced to be overly specific and we can provide players with notifications that doesn't give excessive detail.

For example, in the game "Slaves to Armok" you can sometimes get messages about some particular toe, finger, or ear being hit. This is clearly too much detail for the middle of battle. We wouldn't want be forced to give that sort of detail because we're not storing the fact that these detailed parts add up to a greater whole. At the same time, a strict hierarchy of parts wouldn't be right, because two arms together make up "the arms" of a character, yet each arm individually is part of either the "the left side" or "the right side" of the character, and we'd want to keep track of these relationships so we can provide appropriate messages to the player.

We'd also want all this data to be stored sparsely. For example, if you're facing twenty goblins, there's no point in individually storing every limb and detail for each goblin when they are all identical. We want to store a prototypical goblin in one place, then each individual goblin can be represented only by how it differs from the prototype. Further, the prototype goblin could be represented by how it differs from the prototype human. This is not just to save memory, but also to allow the game to know what makes each character special so it can give the player relevant messages. The game could mention "the goblin with the head wound" or "the goblin with the spiked glove" because that's exactly how those goblins are represented in memory.

Obviously one shouldn't jump blindly into designing such a game, solving each problem as it arises. This level of complicated data needs a database-style system to keep all the details organized, yet a simple relational database doesn't provide an obvious solution. Could something like an Entity System be the right approach?

Is there a known strategy for managing this sort of data that experienced game developers would always use for making this sort of game?

\$\endgroup\$
  • \$\begingroup\$ I think you need to lay out your options, try them one by one in a prototype of the game you intend to make, and see what fits best to your situation. \$\endgroup\$ – Vaillancourt Aug 27 '17 at 0:34
  • 1
    \$\begingroup\$ This kind of resembles RimWorld. You could have a look at it \$\endgroup\$ – Mibac Aug 29 '17 at 17:43
2
\$\begingroup\$

This is not a complete answer since as others here have noted, this question is rather broad. But I just wanted to give you some pointers.

body parts / clothing / enhancements

This is the core of your system. I think what you want here is a nice hierarchical message dispatch system that tells "owning" parts that a subpart is damaged, e.g. maybe you cannot raise a hammer if one or more fingers are broken. This also allows dispatch from finger up through hand through arm through shoulder to main body. The main body can dispatch to larger game controllers to say, "look, this guy can't attack (because he has a broken finger)". You can also shut down any actions on the subparts by deactivating the larger part, so if actor's arm is in a sling, they're probably not going to be using any fingers anyway. I strongly recommend you implement hierarchies of control.

The clothing exclusion system is really just one of breaking the down the body into all areas e.g. arm, leg but also including boundary areas e.g. cuff, waist, collar, and ensuring on any attempt to don new gear, that none of these are conflicting. Bitflags/bitfields/bitmasks would be a fast way to check what's wearable, in one(?) op.

Grouping right and left arm into "arms" is a just a layer you write over the top of all this.

We'd also want all this data to be stored sparsely.

The best you can do then is have one instance of each, and ref these using pointers, which tend to be either 32- or 64-bit (4-8 bytes) depending on platform. Actually, you can do slightly better: You can set up an 8- or 16-bit keyed array (256 or 16384 elements) which you then key into with an unsigned byte or a unsigned short. This keeps your index size down, allowing you to store more indices per CPU word. You will probably also want all the originals to be contiguous in memory.

See also composition of singleton objects that act as prototypes (more on composition below).

For example, if you're facing twenty goblins, there's no point in individually storing every limb and detail for each goblin when they are all identical. We want to store a prototypical goblin in one place

So compose your prototypes and keep them aside. See more below.

Further, the prototype goblin could be represented by how it differs from the prototype human.

Even though superclass/subclass might seem the right relationship here, don't do that as you will lock yourself into a corner later on. Rather compose your prototypal objects and diff them: assign a numeric (or string) ID to each body part, then take a hash over the whole body's collection of parts. That hash allows you to compare actor species; if hash/species differs, you can thereafter numerically compare individual body parts which is very fast, especially with vectorised code.

It could actually be very informative for you to study JavaScript's prototypal inheritance system for what you're trying to do here. It's an almost-perfect fit. It is fairly trivial to implement similar in another language, provided you understand the concept.

Obviously one shouldn't jump blindly into designing such a game

No, but you'd be hard put to know exactly what the most efficient approach is until you've tested several options extensively! That's exactly why you should follow others' advice and get prototyping. It's impossible for anyone here to give you a best-fit architectural approach, because that would rely on how all the different aspects of your design come together - which can only be garnered by extensive experimentation. Start simple and don't worry about efficiency yet.


(clear) "Hierachies of control"

A pattern so common I'm not sure it's really named. It ensures control flows remains sane / avoids spaghetti. You have a series of control classes, say, Game, Body, Arm, Hand, Finger (increasingly fine-grained). Game has functions that calls Body's functions; same for Body and Arm, etc,. down the line; it may not be update, but other named functions e.g. Arm might call Hand.wield. The hierarchy is respected in the sense that you try only to have direct parents (or at least ancestors) speak to children, and children back up to their direct parents (sometimes using loose coupling so there are no direct refs to parents). You can have children speaking to grandparents and/or vice versa, but that makes the control flow harder to follow since you are skipping levels of the tree. You also want to make sure that communications for the system as a whole come out of the top of the tree, which in this case is Body; don't have e.g. Hand dispatching messages out to supersystems.

Basically, Body is the interface to the outside world through which you are channelling all outgoing information, thus making it easy to keep a strict eye on what's going on with actors. Ultimately though, where and whether you skip levels is up to developer discretion, since it does cause mirroring of function definitions at higher levels if you are rigourous with this approach throughout.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Is "hierarchies of control" a design pattern that one can learn more about? A link to more information would be nice, if so, because googling it doesn't give immediate results. \$\endgroup\$ – Geo Aug 27 '17 at 8:49
  • \$\begingroup\$ @Geo Fair question; see edit. \$\endgroup\$ – Engineer Aug 27 '17 at 9:59
  • 1
    \$\begingroup\$ @Geo Loose coupling solves a couple of problems: No cyclic references (which is a problem in some languages), and it allows you to not have to assume the parent is any given type, which is useful when refactoring, or when wanting code where a given thing may be attached to different parent types (imagine a tentacle that could be attached to a torso or a head). Basically it's about flexibility. \$\endgroup\$ – Engineer Aug 27 '17 at 10:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.