#Flexible code architecture

1 messages · Page 1 of 1 (latest)

wintry rampart
#

Game Dev (Unity).

I noticed that GTA San Andreas systems are so flexible that you're easily able to swap the playable character and it worked perfectly, even using each character proper animations when moving, running, etc. Even tho throughout the game you only play with one character only. San Andreas Multiplayer used this feature to allow you to change this skin. But this left me wondering why'd they design it like this in the first place if the game is only intended to be one character. In GTA 5 it would make sense but why the old ones with just 1 character.

So as a result, I've been looking about how game studios develop their games and their architecture and stuff like that, and how they opt for data driven architecture where new weapons, cars, characters are simply data files containing different info like which model to use, how many seats a car has and where each seat is, etc. and the engine automatically handles all of that. And they open interfaces that they use to build the game progession using a higher-level DSL, using methods like give_player_weapon or something similiar. Alongside that, they have self-initializing systems that require little to no manual setup. You just drag the player and it automatically sets up the character, camera, wires everything up and you're on your way to go, something that I struggle with.

I'd like to apply these principles in my game. I have good understanding of how Unity works but I suck in creating flexible code architecture. Most of my game systems are not self-initializing, meaning creating a new scene requires whole lot of wiring up even if the code is there. And alot of my stuff is hardcoded, pretty much nothing is data driven.

#

The question is, how do I learn the skill to create flexible architecture that can expand easily. This is not like web dev where they follow the same(or similar) patterns. Each game is fundamentally different, depending on the feature, some stuff can be data driven only while others have to have custom code.

I’m mainly struggling to find something that works across multiple systems that HAVE to talk to each other. I can’t seem to find something that works, and it’s not about you telling me what to do, but rather how to DESIGN something like that based on my game demands. I’ve been struggling for a few days trying to figure out how to structure it cuz my older project (even tho was an amazing one) was hell to work with.

#

P.S I'm not a beginner programmer, I have experience in other fields.

#

Mention me please <3

tame mica
wintry rampart
sullen mural
#

You can take "good" programming and architecture principles to any project regardless of the context. You can definitely go too far with them as well and code 100 interfaces instead of your actual game. Principles only stand to make your code easier to maintain, extend, test, and debug.

#

You can find 1000 different ways people will recommend you structure your game but it usually all goes back to the same few principles.

tame mica
wintry rampart
wintry rampart
# tame mica In the end it's up to what your project needs, and there's no single right answe...

Okay so heres a full breakdown.

Usually I had a PlayerController.cs and CameraController.cs and they have to talk to each other (shake when the player attacks or something).

What I'm trying to do is this:

  • First, have self initializing systems where I can drag like a simple object inside the scene and it will automatically be setup to play directly, no dragging references across the scene. This includes initializing the player controller, the camera controller, the UI for the game.
#
  • My player has magic spells that he can select from and then fire, each of them have their own different code (an example is launching a fireball, another is freezing surrounding entities). And each enemy has its own attacking mechanics, a gremlin is slow and attacks when ur near, a floating soul sucks ur soul from a further distance (with a ray appearing when u get close).
sullen mural
wintry rampart
#
  • A story progression script. In GTA games they use their own DSL scripting language for the missions with bindings for stuff like give_player_money or spawn_npc. Altho Im not gonna use a different language, I want an easy and flexible way/interface to do this.

Usually i do a normal script and i store a missionStage and i check every frame if the player stage is X and he's near specific point then set missionstage to X + 1 to avoid the frame check and do whatever supposed to do.

I want an easy way to script mission progression, showing instruction, when some parts being sequential (u have to reach A before trigging the next objective) and other being in paralell, (like go to A but also the npcs move while u go there, or having a conversation with an NPC)

#
  • A cutscene system. a good and flexible way to create cutscenes that, have multiple camera animations ( i do this using cinemachine), triggerable by the mission script i've said above.
    including a dialogue, a skip feature that allows me to set everything if the player skipped (like where the player should be or the npcs should be or how much health he has, etc).
wintry rampart
# sullen mural how to name and split files is not consequential on your architecture at all, bu...

To me it does.

I thought...
Ok lets make a Character.cs class, but for my player i have PlayerController.cs, but a controller is not a character so it shouldnt inherit from it.

ok then PlayerCharacter.cs right? ok but should that character file include logic for taking input and moving the player, or should it only hold values like health and stuff and another PlayerController.cs should deal with that.

Ok if we go with the former, then why does a Character take input while other characters (NPCs) don't? shouldnt all subclasses deal within same scope? And if I do that, should camera movement be part of it or a separate CameraController.cs, if its a separate file then why is there CameraController.cs and not PlayerController.cs

sullen mural
#

These are examples, not actual advice on how to structure the code exactly.

wintry rampart
#

in the player script i mean

sullen mural
#

what if you want to have two separate characters to control at the same time? Or you want to have two characters that you want to switch between?

#

As for the rest of the systems, focus on refining and challenging your assumptions. For example, if you're keeping just an int for changing the 'stage' what happens when the player goes out of sequence?

wintry rampart
#

its driving me crazy the past few days

wintry rampart
sullen mural
#

You can always try to forsee potential extensions but if you're also fighting the idea of the extensions then what's the point

sullen mural
#

Also, you're never gonna write perfect code the first time. Rarely happens. So experiment with it and design it multiple times to see the tradeoffs.

#

Eventually you'll have a mental library of 'solved problems' and you'll know how to generalize past experience to new tasks/problems.

placid bronze
#

for example a parent player object that spawn/holds a model in a child gameobject and gets a reference to the animator to play the current one

storm coral
# sullen mural Also, you're never gonna write perfect code the first time. Rarely happens. So e...

Correction: you are never gonna write perfect code the first time, you could go back a hundred times and improve things

Striving for the "perfect" architecture is a major reason people procrastinate their projects, caught between feeling like they want to do it perfect and they want to progress ending in progress paralysis cause they neither want to progress unless its perfect, nor work on scaffoling that doesnt feel like progress 😄

prime dock
wintry rampart
#

yeah but each character has its own animation controller

wintry rampart
#

or is it the opposite

#

or how is it structure

#

and also how would i have self initialziing systems without having to drag and drop each single thing

prime dock
#

Each Character has a Brain Component.

wintry rampart
#

and a property for the character

#

that seems like something id use

#

thanks

prime dock
#

Obviously, the Brain is 1<->1 with the Character.

wintry rampart
#

and also for the AIBrain how do u structure it so that they can either wander around like a normal npc, follow a specific path when called, attack a certain enemy or just automatically pick an enemy surrounding it and shit

prime dock
#

Or make multiple brain type

prime dock
wintry rampart
# prime dock private void Reset() { ... }

what i mean is that the those are drag-and-drop components, so i have to reference it in the inspector either way, is there a way to reference the default one without dragging it in inspector

storm coral
storm coral
#

private void OnValidate() {
  _rigidbody ??= GetComponent<Rigidbody>();
}
#

for example like that

wintry rampart
#

thats not what i meant

#
public class Character : MonoBehavior {

    public Brain brain;

    
}

and Brain could be scriptable object

#

i have to drag it

storm coral
#

yes you can also search for that in OnValidate

wintry rampart
#

how would i search it

storm coral
#

You can query the AssetDatabase

wintry rampart
#

isnt that bad tho

storm coral
#

if you do it in editor runtime no

#

it will basically do the drag & drop for you

wintry rampart
#

yeah but it has to search it

quick wind
# wintry rampart i have to drag it

is there a problem with having to drag it in? yes you're going to have to setup objects in a specific way if you want them setup a specific way

storm coral
#

yes, once while you attach the script, never again afterwards

wintry rampart
quick wind
storm coral
#

then just drag the prefab into each scene

#

the prefab will retain the reference to the scriptable object

quick wind
#

i do find it somewhat weird though if you're using a Brain as a scriptable object. this would imply the brain has no mutable data at all

storm coral
#

well its perfectly ok not to tweak brain parameters at runtime anymore

wintry rampart
#

yeah but what about component that talk with each other, i have a canvas with UI that the player has to talk to and if i make a prefab for the player and prefab for the canvas i still have to wire them manually

quick wind
storm coral
quick wind
#

this could still be done in a prefab anyways

#

it seems like you're overthinking a lot of the setup simply because its manual work. If you have tons of unique characters, all with different logic, then you have to set that up somehow. theres no magic solution where you can avoid defining what a character can do

#

you plan to have tons of stuff, thus you have tons of work to do

wintry rampart
#

u cant expect map designers to connect all these

quick wind
#

I never stated a map designer would be doing it either. I'm specifically saying this is work for you to do. If you want many characters, you need to manually define the logic that each one can do. That's by dragging in references or adding components, then making that a prefab.
Whoever creates your map would only care about the prefabs or creating custom spawn locations, which at the end would be a script referencing a prefab

prime dock
wintry rampart
#

Or enemy for example. I need a reference to the player. Even if both are prefabs, since they're different game objects the references between them won't be saved

tame mica
wintry rampart
tame mica
#

There are many different find(gameobject/object/component) methods that unity provides, then you could have your own system that would provide easy access to various objects via singletons or static fields.

#

There are many different ways, depending on your specific use case.

wintry rampart
#

Yeah but those also require the objects existingm. Like finding a canvas if it doesn't exist is an issue. Meaning I have to manually drag and drop the canvas.

#

I was thinking something like putting a spawn point and everything initializes

tame mica
#

You don't have to drag and drop it. You can create it via code.

wintry rampart
tame mica
#

And set up the references via code, yes.

wintry rampart
#

Lovely

#

Another thing

#

Should the systems be decoupled? Like should I actually reference the UI slider for health in the player script or use some sort of event driven architecture broadcasting health change event? Or unity events maybe?

#

And then a UI controller would listen and set accordingly

tame mica
#

Ideally, you want to decouple things. Especially ui from game logic.
But it depends on your game complexity. Some simple games are fine with hard coded/manual assigned references. Implementing a complex system in this case would be a waste of time.
In more complex games, there are many different approaches. You can have model-view kind of system with events or callbacks and/or various components registering with the ui so that it listens to their value updates, etc...
Again, heavily depends on your project.

wintry rampart
#

Are unity events slow?

quick wind
tame mica
#

And it's probably not something you should worry about anyway.

wintry rampart
#

The setup was so bad it was hell setting up a player In a new scene e

#

At one point it was easier to clone a map then delete the map objects and work from there just to avoid setting it up

wintry rampart
tame mica
wintry rampart
tame mica
quick wind
tame mica
#

Instead of worrying about certain api performance, worry about how much you're calling it an in out circumstances.

#

Ultimately, don't worry about performance, until you have an actual problem