This repository has been archived by the owner on Jan 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 896
Coding rules
Jan Nekvapil edited this page Apr 19, 2016
·
1 revision
Following rules are important and mandatory. Please read them carefully and if you don’t understand ask your colleagues.
Naming Conventions
-
All our classes, structs and enums begin with My*
-
We use camel case for syntax
-
Private class members have prefix m_* and next following letter lower case (except abbr)
-
Method names always start with uppercase
-
Public class members/properties are written like method names
-
Consts or read-only structs are always with capital letters
-
When naming time variable, put in the name if it’s in millisecond or seconds
-
Use only alpha-numeric characters or underscore in filenames. This apply for class names, textures, models, etc. Basically: don’t use non-English letters and spaces.
-
Use positive naming convention where possible (Enable, Visible..) Don’t use DisabledSomething, HiddenSomething etc.
-
Avoid ugly words. Your code is your presentation and parts of code are even public!
Code Design
-
Rule number one is flexibility. Please don’t try to make excellent class design that is hard to change in future
-
Always consider that you WILL CHANGE your code in the future (my experience is that I change a lot, so I don’t spend time making funky abstract classes, abstract method and just spend time being design freak)
-
The above doesn’t mean we want dirty code. No. Clean code is important.
-
Also use abstract classes, virtual methods, etc when you feel it fits the place. But don’t try to force the design.
-
Do not use lambdas in performance code! They do allocations, break Edit & continue and are slow.
-
Do not use enumerators – they do allocations
-
Do not use enum/struct as dictionary key – it does allocations
-
Member order: fields, properties, indexers, events, static constructor, constructors, destructor, Dispose, other methods, conversion operators, explicitly implemented interface methods (use region per-interface)
-
Spacing: one empty line after method, one empty line after multi-line property / event / indexer
Enums
-
Do not remove enums, only add new and deprecate old (we want to keep backward compatibility)
-
Be careful when adding new enums in the middle of existing one (can break serialization)
-
Beware Enum.ToString(), because obfuscator change enum name and values (if not specified explicitly)
-
Specify enum values where possible, do not use same values in one enum
Optimization Rules
-
During active game don’t create new objects (instances of class) – because those objects are created on the heap and that can force GC to do a collection – and we don’t want it during player is playing.
-
New objects can be initialized only during level loading, menu navigation, etc. It’s good to call GC.Collect after that.
-
But it is OK to use “new” for creating “struct”. Structs are always created on the stack, so no GC problems. Of course only if struct doesn’t contain references or if it’s too huge.
-
Consider that struct is value so when passed to a method, this value is copied. Normally just live with this, but in highly used code or if struct is really huge, use “ref” version.
-
This applies also to strings. They are immutable, so every string concatenation creates new string in heap. Instead of string use StringBuilder – which is also a string but its size is pre-allocated. Beware that all string operations and even some StringBuilder methods do allocations.
-
Don’t allocate arrays/lists during game update/draw. Do it only during loading and then reuse this arrays (e.g. missiles, explosions, decals ...).
-
If you know in advance that you will need to allocate objects during a game (e.g. new missiles, new billboards, new projectiles, etc), use MyObjectsPool<>
-
Even if it’s ugly, sometimes is good to not use get/set for changing some object’s property but make that member public and change it directly. It should be a lot faster. If that member is only for public get and changing is private, then create private member and public GetPropertyXYZ()
-
Virtual methods – use only when necessary and when it suites the design (e.g. physics classes are inherited one from another, GUI uses inheriting – so those are good place). But rendering code doesn’t need virtual methods so it’s better to avoid them there.
-
Update* methods – do as few as possible calculations here, try to use eventhandler instead, cache, precomputed values, parallel raycasts instead.
-
When you need local array/list to store some results during update/draw, don’t allocate local array/list, use preferably static member array/list, reuse this array every time. When multiple threads uses your function, you can mark static array/list with ThreadStatic attribute (each thread has own array). ThreadStatic requires first use initialization pattern.
-
When using delegates, don’t create delegate every time you use it, make it member. When you pass function name to another function which requires delegate, you don’t create delegate, but internally it does!
Development Processes
-
While developing the game it’s recommended to run it in windowed mode as switching to full screen takes more time and debugging is complicated
-
Where possible use Debug.Assert().
-
Always check your input/output values and default enum values and assert if value is wrong
Commenting
-
Please look at actual source code and use same amount of comments.
-
Try to write self describing code. If you feel your code is not clear, write comment.
-
Most important things to comment are: why you did that, why you didn’t, what should know your collegue in future when he touches that place, etc. The reason for comment is to have more information that can’t fit in the syntax
-
Look for “IMPORTANT” comments. Always read them. Make your own if you feel you want to say something important.
Miscellaneous
-
All measures are in meters and kilograms
-
Export statistics in MB
Exception Handling
-
There is already made some exception handling – e.g. when unhandled exception occurs it is written to the log and message box to user is displayed
-
We don’t use try/catch much, especially not in rendering/update code. If something fails, then complete game fails.
-
Of course this rule doesn’t apply for IO operations (files, network, etc). But if we can’t read a texture – that’s a big error so game can’t continue. Same for any other error. Only situations like sending a packet, reading not-mandatory file, ... those are that we can catch and ignore.