Game Engines 2021W Lecture 13

From Soma-notes
Revision as of 09:12, 4 March 2021 by Soma (talk | contribs) (Created page with "<pre> Lecture 13 ---------- Godot categorizes its elements differently than other game engines - nodes & scenes vs much more complex divisions (entities, prefabs, worlds, et...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Lecture 13
----------

Godot categorizes its elements differently than other game engines
 - nodes & scenes vs much more complex divisions (entities, prefabs, worlds, etc)

The more complex divisions come from entity-component architectures, or
entity component systems architectures

Games care about performance

cache-friendly code?

Modern computer architecture, memory
 - CPUs are MUCH faster than RAM
   - thus, we have caches: faster memory between RAM and the CPU
   - different kinds, L1, L2, L3
     - L1 is smaller and faster than L2

If your code is going to go fast, it should be cache friendly

Classic object-oriented code (can be) very cache unfriendly

(ECS is a path to cache friendly code, basically)

How do you use cache most effectively?  Key insight:
 - data is loaded into cache in bulk
 - request one byte, get 64 bytes or more (cache lines)

How cache behaves is a black box
 - very complex

To get good cache performance, you want spatial and temporal locality
 T: if x is used, it is likely x is used again sooner rather than later
 S: if x is used, y is used where y is close to x

Imagine a for loop traversing an array
 - while accessing element 1, elements 2, 3, and 4 may be loaded into cache when 1 is loaded
 - so access to 2, 3, and 4 will be much faster <- spatial locality
 - but, if you accessed the array randomly, will have to go to main memory
   much more frequently

Main memory has high latency but also high bandwidth
 - takes a while to get one byte, but gets lots of data for each access
   - you never just get one byte

Never underestimate the bandwidth of a truck or a boat with LOTS of hard drives (spinning or SSD)
 - but its latency is crap, a week to get the first byte

bandwidth is average bytes per second, latency is time for first byte (or roundtrip cost)

latency matters for games, i.e., how long does the system take to respond to pressing a button
 - measure of responsiveness

Classic objects are, from a storage point of view, just structs
Imagine doing an operation on lots of objects
 - only need a few properties of each object
 - this is very cache-unfriendly, because you aren't using most of the object
    - but whole objects will be put into cache
    - load 512 bytes but only use 16
    - waste of bandwidth

ECS is an architecture to turn this around to make it cache friendly
(assuming you do operations on small portions of objects at once)

instead, split up the objects into components, and keep components in arrays
  - so, if you loop through components, you'll be cache friendly

Unify components using "entities", i.e., a unique ID to group togother components

Instead of an object with properties ID, A, B, C, and D, instead you have
 - array of A's
 - array of B's
 - array of C's
 - array of D's
 - each element of the arrays also has ID
   - or use the array index as the ID

So, looping through A's is very fast

The "system" part is the code that processes each property
  - i.e., physics system just deals with physics-related properties,
  - because they are stored separately, can be accessed all at once,
    fast, without looking at the other data associated with the entities

Godot doesn't do this because it isn't so simple for developers
 - less generality

But its objects are at a higher level, really just an interface

Underlying servers can be cache friendly as you like
 - e.g., physics server

Really, ECS is a pattern of has-a OO, rather than is-a OO (inheritance)

Note that JavaScript is very has-a OO (why it has no real classes)

ECS is a game dev specific pattern to "data oriented" code