larspensjo, on 13 Mar 2013 - 16:03, said:In many ways, there are the same problem as with any big software. When the number of lines go above some level, you have to use various methods. In principle, you divide the big project into smaller ones, and try to keep them as independent as possible.
proanim, on 13 Mar 2013 - 10:01, said:
What is done when programming something that is large FPS/TPS project?
I have often called this process "modularization", mostly as the project is (ideally) broken down mostly into large-scale modular components (or "black boxes").
ideally, parts will interact primarily via an API of some sort, and will avoid interacting with data which is internal to the component in question.
there are some tradeoffs which can often be made in terms of how "opaque" an API is made, where increasing opaqueness will often better isolate parts of the system, but at the cost of typically making it more painful to use (and making the choice of abstractions more significant regarding the general usability of the API).
one major one here is often the client/server split.
There are specific issues with large games. The render engine, for example, usually have to be managed as a complex system of its own.
There are ways to manage complex game logic. One such is the use of Entity-Component-System pattern, decision trees, etc.
There are also various ways to use data flow control, separation into scripting languages, etc.
I am sure other can add some major structuring methods.
where, the client-end mostly handles user-input and rendering, and the server mostly manages things like game logic.
often there is no direct communication across this split (even for single player games), as pretty much all communication will often be via message passing (often done at the level of sending object positions and various sorts of events).
then beyond this, each will be broken down, for example (partly using my engine architecture as a reference):
** low-level (texture management, dealing with shaders, maybe things like text and the console, ...)
** high-level (world rendering, loading and rendering various types of objects, ...)
** inner renderer (code involved directly with handling and rendering geometry)
** outer renderer (code which is generally more scene-level and managerial)
* user-input handling (camera, etc)
* 2D drawing (HUD, etc...).
* client-side networking stuff (processing delta messages, sending impulse events)
** entity system
*** AI (various algos, ...)
*** game logic and scripts
as well as other things (part of the engine but not specific to the client or server):
common (code which is shared between the client and server ends):
* voxel terrain stuff
* brush-geometry stuff
* low-level console stuff (cvars, various console commands, the console-based text editor interface, ...)
general infrastructure (around 2/3 of the engine codebase, *1):
* VFS (Virtual File System, creates a virtual Unix-style directory tree for game data);
* dynamic type-system and object-system stuff (mostly used by script code)
** reflection-related metadata database stuff (used for script <-> C interfacing, ...)
*** this is actually the main user of memory at engine startup at present.
*** structurally, its contents resemble the Windows Registry, consisting mostly of a tree of key/value pairs.
* garbage collector
* dynamic assembler / linker (used for script-VM, ...)
** (used mostly for the JIT and for various other mostly procedurally-generated code)
* script VM
** JIT compiler
** interpreter logic
** bytecode compiler
** script parser
* stuff like vector-math code, ...
typically the AIs and game-logic is mostly implemented using finite-state-machines and timers.
some number of triggers are also used, where a trigger is basically a non-solid bounding box which if anything touches it, it will invoke a callback.
to some extent, there are also "sequenced events", which are basically sort of like batch-files, but will execute commands on a timer (which in my case may also contain globs of script code to be executed as well). ADD: typically delays are explicit, waiting for a certain amount of time before executing the next command, and may run commands either sequentially or set up groups to run in parallel, ...
*1: despite the renderer using the majority of the execution time, it is only about 10% of the code. around 20% of the code mostly goes into the server end, and ~ 70% goes mostly into general infrastructure stuff, a big chunk of which is related to my scripting VM (arguably a bit large / overkill for the task, but oh well...).
I had before compared this with Doom 3 (a similar sized codebase), where IIRC the majority of the code seems to be in the renderer, with most everything else as a smaller part of the pie.