Presentations/OpenColloq/WS24_EntityComponentSystem/public/index.html

637 lines
26 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta name="generator" content="Hugo 0.139.0"><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=1313&amp;path=livereload" data-no-instant defer></script>
<meta charset="utf-8">
<title>Entity Component System - It&#39;s not a system</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><link rel="stylesheet" href="/reveal-js/dist/reset.css">
<link rel="stylesheet" href="/reveal-js/dist/reveal.css"><link rel="stylesheet" href="/reveal-js/dist/theme/black.css" id="theme">
<link rel="stylesheet" href="/highlight-js/default.min.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section><h1 id="entity-component-system">Entity Component System</h1>
</section><section>
<h2 id="what-is-an-ecs">What is (an) ECS?</h2>
<ul>
<li><span class='fragment '
>
unnecessary
</span></li>
<li><span class='fragment '
>
useful
</span></li>
<li><span class='fragment '
>
not a system
</span></li>
</ul>
<aside class="notes"><p>Talk about structure of presentation here:</p>
<ul>
<li>define terms like &ldquo;entity&rdquo;, &ldquo;component&rdquo;, &ldquo;system&rdquo;</li>
<li>go over other approaches to &ldquo;motivate&rdquo; ECS</li>
<li>main 3 game engines will be mentioned (Unity, Unreal, Godot)</li>
<li>talking about the level of programming engines, not games</li>
</ul>
</aside>
</section><section>
<h2 id="what-are-entities">What are entities?</h2>
<p><img src="lol.jpg" alt="lol"><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
</section><section>
<h2 id="what-are-entities-1">What are entities?</h2>
<p><img src="aoe.jpg" alt="aoe"><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
</section><section>
<h2 id="what-are-entities-2">What are entities?</h2>
<ul>
<li>Objects in a game (or simulation)</li>
<li>Can have different behaviours</li>
<li><span class='fragment '
>
Basically everything
</span></li>
</ul>
</section><section>
<h1 id="inheritance">INHERITANCE</h1>
</section>
<section data-shortcode-section>
<section data-noprocess data-shortcode-slide
data-transition="none">
<h2 id="inheritance">Inheritance</h2>
<div class="mermaid">graph TD;
Entity-->MoveableEntity;
Entity-->PhysicsEntity;
</div>
<aside class="notes"><p>Entity: Basic information like transform and mesh in our example
MoveableEntity: Entity with functions to move with and support animations
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity</p>
</aside>
</section>
<section data-noprocess data-shortcode-slide
data-transition="none">
<h2 id="inheritance-1">Inheritance</h2>
<div class="mermaid">graph TD;
Entity-->MoveableEntity;
Entity-->PhysicsEntity;
MoveableEntity-->Character;
PhysicsEntity-->BoxColliderEntity;
</div>
<aside class="notes"><p>Entity: Basic information like transform and mesh in our example
MoveableEntity: Entity with functions to move with and support animations
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity</p>
</aside>
</section>
<section data-noprocess data-shortcode-slide
data-transition="none">
<h2 id="inheritance-2">Inheritance</h2>
<div class="mermaid">graph TD;
Entity-->MoveableEntity;
Entity-->PhysicsEntity;
MoveableEntity-->Character;
Character-->Player;
Character-->NPC;
PhysicsEntity-->BoxColliderEntity;
</div>
<aside class="notes"><p>Entity: Basic information like transform and mesh in our example
MoveableEntity: Entity with functions to move with and support animations
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity</p>
</aside>
</section>
</section><section>
<h2 id="godot">Godot</h2>
<p><img src="./GodotInheritanceEditor.png" alt="GodotInheritance">
<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
</section><section>
<p><img src="godot_news.png" alt=""></p>
</section><section>
<h2 id="godot-code">Godot Code</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Node2D</span> <span style="color:#f92672">:</span> <span style="color:#66d9ef">public</span> CanvasItem {
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>.
</span></span><span style="display:flex;"><span>.
</span></span><span style="display:flex;"><span>.
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">PhysicsBody2D</span> <span style="color:#f92672">:</span> <span style="color:#66d9ef">public</span> CollisionObject2D {
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CharacterBody2D</span> <span style="color:#f92672">:</span> <span style="color:#66d9ef">public</span> PhysicsBody2D {
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
</section>
<section data-shortcode-section>
<section data-noprocess data-shortcode-slide
data-transition="none">
<h2 id="inheritance">Inheritance</h2>
<div class="mermaid">graph TD;
Entity-->MoveableEntity;
Entity-->PhysicsEntity;
MoveableEntity-->Character;
Character-->Player;
Character-->NPC;
PhysicsEntity-->BoxColliderEntity;
MoveableEntity-->Vehicle;
</div>
</section>
<section data-noprocess data-shortcode-slide
data-transition="none">
<h2 id="multiple-inheritance">Multiple Inheritance</h2>
<div class="mermaid">graph TD;
Entity-->MoveableEntity;
Entity-->PhysicsEntity;
MoveableEntity-->Character;
Character-->Player;
Character-->NPC;
PhysicsEntity-->BoxColliderEntity;
MoveableEntity-->Vehicle;
BoxColliderEntity-->Vehicle;
</div>
</section>
</section>
<section data-noprocess>
<h1>Godot</h1>
<div style="display: flex; flex-direction: row; justify-content: center; align-items: center;">
<img style="margin-right: 10%;" src="Godot_player_scene_nodes.webp">
<ul>
<li class="fragment" >uses hierarchy instead</li>
<li class="fragment" >child nodes as "components"</li>
</ul>
</div>
</section>
</section><section>
<h2 id="what-are-components">What are components?</h2>
<ul>
<li><span class='fragment '
>
Split entities from behaviour
</span></li>
<li><span class='fragment '
>
Data associated with a certain &#34;behaviour&#34;
</span></li>
</ul>
</section><section>
<h1 id="composition">COMPOSITION</h1>
</section><section>
<h1 id="composition-1">Composition</h1>
<div class="mermaid">graph LR;
EntityA-->BoxColliderComponent;
EntityA-->StaticMeshComponent;
EntityB-->SphereColliderComponent;
EntityB-->DynamicMeshComponent;
EntityB-->PlayerControllerComponent;
linkStyle default stroke:lime,stroke-width:4px;
</div>
</section><section>
<h2 id="composition-2">Composition</h2>
<ul>
<li><span class='fragment '
>
Entities have minimal data and behaviour
</span></li>
<li><span class='fragment '
>
Entities hold their components or references to them
</span></li>
</ul>
<span class='fragment ' ><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Component</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Entity</span> {
</span></span><span style="display:flex;"><span><span style="color:#75715e">//...
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">private</span><span style="color:#f92672">:</span>
</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>unordered_map<span style="color:#f92672">&lt;</span>std<span style="color:#f92672">::</span>type_info, Component<span style="color:#f92672">*&gt;</span> m_components;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></span>
<aside class="notes"><p>Wanted to have a look at Unreal Source code, but&hellip;</p>
</aside>
</section><section>
<p><img src="gnupolice_unreal.png" alt=""></p>
</section><section>
<h2 id="unreal">Unreal</h2>
<p>Code in Unreal&rsquo;s AActor class<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* All ActorComponents owned by this Actor. Stored as a Set as actors may have a large number of components
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* @see GetComponents()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
</span></span><span style="display:flex;"><span>TSet<span style="color:#f92672">&lt;</span>TObjectPtr<span style="color:#f92672">&lt;</span>UActorComponent<span style="color:#f92672">&gt;&gt;</span> OwnedComponents;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* Get all components derived from class &#39;ComponentType&#39; and fill in the OutComponents array with the result.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* It&#39;s recommended to use TArrays with a TInlineAllocator to potentially avoid memory allocation costs.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* TInlineComponentArray is defined to make this easier, for example:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* {
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* TInlineComponentArray&lt;UPrimitiveComponent*&gt; PrimComponents(Actor);
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* }
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* @param bIncludeFromChildActors If true then recurse in to ChildActor components and find components of the appropriate type in those Actors as well
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">template</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ComponentType</span>, <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AllocatorType</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> GetComponents(TArray<span style="color:#f92672">&lt;</span>ComponentType, AllocatorType<span style="color:#f92672">&gt;&amp;</span> OutComponents, <span style="color:#66d9ef">bool</span> bIncludeFromChildActors <span style="color:#f92672">=</span> false) <span style="color:#66d9ef">const</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">typedef</span> TPointedToType<span style="color:#f92672">&lt;</span>ComponentType<span style="color:#f92672">&gt;</span> T;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> OutComponents.Reset();
</span></span><span style="display:flex;"><span> ForEachComponent_Internal<span style="color:#f92672">&lt;</span>T<span style="color:#f92672">&gt;</span>(T<span style="color:#f92672">::</span>StaticClass(), bIncludeFromChildActors, [<span style="color:#f92672">&amp;</span>](T<span style="color:#f92672">*</span> InComp)
</span></span><span style="display:flex;"><span> {
</span></span><span style="display:flex;"><span> OutComponents.Add(InComp);
</span></span><span style="display:flex;"><span> });
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div>
<aside class="notes"><p>next, Unity, but&hellip;</p>
<p><em>b. Distributing Examples
You may Distribute Examples (including as modified by you) in Source Code or object code to any third party.</em></p>
</aside>
</section><section>
<p><img src="gnupolice_unity.png" alt=""></p>
</section><section>
<h2 id="unity">Unity</h2>
<p><img src="unity_inspector.jpg" alt=""><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<aside class="notes"><ul>
<li>can&rsquo;t confirm what Unity uses (no source found)</li>
<li>interface suggests composition</li>
<li>Unity DOTS?</li>
</ul>
</aside>
</section><section>
<p><img src="mario_ecs_castle.png" alt=""></p>
</section><section>
<h2 id="what-are-systems">What are systems?</h2>
<ul>
<li><span class='fragment '
>
███████████████████
</span></li>
<li><span class='fragment '
>
█████████████████
</span></li>
<li><span class='fragment '
>
████████████████████
</span></li>
</ul>
<aside class="notes"><p>We&rsquo;ll talk about it later.</p>
</aside>
</section><section>
<h1 id="entity-component-system-1">Entity Component System</h1>
</section><section>
<p><img src="dracula_ecs.png" alt=""></p>
<aside class="notes"><p>ECS is Data-Oriented rather than Object-Oriented</p>
</aside>
</section><section>
<h2 id="entity-component-system-2">Entity Component System</h2>
<ul>
<li><span class='fragment '
>
split components even more from entities
</span></li>
<li><span class='fragment '
>
entities are minimal data
</span></li>
<li><span class='fragment '
>
components store data associated with certain behaviours
</span></li>
<li><span class='fragment '
>
components aren&#39;t managed by their entities
</span></li>
</ul>
<aside class="notes"><ul>
<li></li>
<li>entities can just be ids</li>
<li>component manager</li>
</ul>
</aside>
</section><section>
<p><img src="zerowing_component_manager.png" alt=""></p>
</section><section>
<h2 id="what-are-systems-1">What are systems?</h2>
<ul>
<li><span class='fragment '
>
main way of interacting with components
</span></li>
<li><span class='fragment '
>
loop over every component of a type
</span></li>
<li><span class='fragment '
>
e.g. Rendering System, Physics System...
</span></li>
</ul>
<aside class="notes"><ul>
<li>due to systems, want to optimise for iterating over components of a type</li>
</ul>
</aside>
</section><section>
<h2 id="examples">Examples:</h2>
<ul>
<li><a href="https://unity.com/dots">Unity DOTS</a></li>
<li><a href="https://bevyengine.org/">Bevy</a></li>
<li><a href="https://github.com/skypjack/entt">EnTT</a></li>
</ul>
<span class='fragment ' ><blockquote>
<p>One thing known to most is that <em>EnTT</em> is also used in Minecraft.
Given that the game is available literally everywhere, I can confidently say that the library has been sufficiently tested on every platform that can come to mind.</p>
</blockquote>
</span>
<aside class="notes"><p>Bevy ECS used for <a href="https://store.steampowered.com/app/2198150/Tiny_Glade/">Tiny Glade</a></p>
</aside>
</section><section>
<h2 id="cache">Cache</h2>
<table>
<thead>
<tr>
<th>CPU</th>
<th>L1</th>
<th>L2</th>
<th>L3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Pentium N4200</td>
<td>96 KiB</td>
<td>128 KiB</td>
<td>2 MiB</td>
</tr>
<tr>
<td>i7 14700HX</td>
<td>1800 KB</td>
<td>28 MB</td>
<td>33 MB</td>
</tr>
</tbody>
</table>
<aside class="notes"><p>top: silas&rsquo; laptop
bottom: mine</p>
<p>Mine are probably also KiB/MiB, because Windows is doing Windows things</p>
<p>Cache Locality less important with newer cpus, but will probably still lead to benefits.
Storing data contigous should reduce cache misses, since accesses are more predictable.
Collider Component may have 3*float64 position + 4*float64 rotation + 3*float64 size + 10*float64 miscellanious = 160 Byte
300 of those = 48 KB
500 of those = 80 KB</p>
</aside>
</section><section>
<h2 id="how-to-implement-it-in-c">How to implement it in C++</h2>
<h3 id="entities">Entities:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#75715e">//one possibility
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">typedef</span> uint_32t UID;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> UID Entity;
</span></span></code></pre></div></section><section>
<h2 id="how-to-implement-it-in-c-1">How to implement it in C++</h2>
<h3 id="components">Components:</h3>
<p>A <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0429r9.pdf">std::flat_map</a> is a fitting datatype.</p>
<span class='fragment ' ><table>
<thead>
<tr>
<th>GCC libstdc++</th>
<th>Clang libc++</th>
<th>MSVC STL</th>
</tr>
</thead>
<tbody>
<tr>
<td>not implemented</td>
<td>partially implemented</td>
<td>not implemented</td>
</tr>
</tbody>
</table>
</span>
<p><sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></p>
</section><section>
<h2 id="how-to-implement-it-in-c-2">How to implement it in C++</h2>
<h3 id="components-1">Components:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ComponentManager</span>{
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">template</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">typename</span> comp_type<span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">requires</span> std<span style="color:#f92672">::</span>is_base_of<span style="color:#f92672">&lt;</span>Component, comp_type<span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span> foreachComponent(std<span style="color:#f92672">::</span>function func){
</span></span><span style="display:flex;"><span> <span style="color:#75715e">//...
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">template</span><span style="color:#f92672">&lt;</span><span style="color:#66d9ef">typename</span> comp_type<span style="color:#f92672">&gt;</span> <span style="color:#66d9ef">requires</span> std<span style="color:#f92672">::</span>is_base_of<span style="color:#f92672">&lt;</span>Component, comp_type<span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span> addComponentToEntity(Entity entity){
</span></span><span style="display:flex;"><span> <span style="color:#75715e">//...
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#75715e">//some type of ComponentMap store
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}
</span></span></code></pre></div>
<aside class="notes"><p>possible ComponentMap store:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span>std<span style="color:#f92672">::</span>unordered_map<span style="color:#f92672">&lt;</span>std<span style="color:#f92672">::</span><span style="color:#66d9ef">typeid</span>, std<span style="color:#f92672">::</span>size_t<span style="color:#f92672">&gt;</span> m_typeOffsetMap;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span><span style="color:#f92672">*</span> m_componentMaps;
</span></span></code></pre></div></aside>
</section><section>
<h2 id="how-to-implement-it-in-c-3">How to implement it in C++</h2>
<h3 id="componentmap">ComponentMap:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="nohighlight" data-noescape><span style="display:flex;"><span><span style="color:#66d9ef">template</span> <span style="color:#f92672">&lt;</span><span style="color:#66d9ef">typename</span> component_type<span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ComponentMap</span>
</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>vector<span style="color:#f92672">&lt;</span>component_type<span style="color:#f92672">&gt;</span> m_values;
</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>unordered_map<span style="color:#f92672">&lt;</span>Entity, size_type<span style="color:#f92672">&gt;</span> m_mapping;
</span></span></code></pre></div></section><section>
<p><img src="metroid_ending.gif" alt=""></p>
</section><section>
<h2 id="links">Links</h2>
<ul>
<li>Images from <a href="https://deathgenerator.com">deathgenerator.com</a></li>
<li>Helpful <a href="https://trepo.tuni.fi/bitstream/handle/123456789/27593/H%C3%A4rk%C3%B6nen.pdf">thesis by Toni Härkönen</a></li>
<li><a href="https://t-machine.org/index.php/2014/03/08/data-structures-for-entity-systems-contiguous-memory/">Data Structures for Entity Systems: Contiguous memory</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
</section><section>
<ol>
<li id="fn:1">
<p><a href="https://br.ign.com/league-of-legends-wild-rift/89123/feature/wild-rift-tudo-sobre-o-lol-mobile">https://br.ign.com/league-of-legends-wild-rift/89123/feature/wild-rift-tudo-sobre-o-lol-mobile</a> ; Image: Riot Games&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://pressakey.com/gameinfos,4981,screenshots,,,Age-of-Empires-Definitive-Edition,.html">https://pressakey.com/gameinfos,4981,screenshots,,,Age-of-Empires-Definitive-Edition,.html</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Screenshot: Godot Engine&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://github.com/godotengine/godot">https://github.com/godotengine/godot</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p><a href="https://docs.unity3d.com/6000.0/Documentation/Manual/UsingTheInspector.html">https://docs.unity3d.com/6000.0/Documentation/Manual/UsingTheInspector.html</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://en.cppreference.com/w/cpp/compiler">https://en.cppreference.com/w/cpp/compiler</a>_support/23&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
</section>
</div>
</div>
<script type="text/javascript" src=/reveal-hugo/object-assign.js></script>
<script src="/reveal-js/dist/reveal.js"></script>
<script type="text/javascript" src="/reveal-js/plugin/markdown/markdown.js"></script>
<script type="text/javascript" src="/reveal-js/plugin/highlight/highlight.js"></script>
<script type="text/javascript" src="/reveal-js/plugin/zoom/zoom.js"></script>
<script type="text/javascript" src="/reveal-js/plugin/notes/notes.js"></script>
<script type="text/javascript">
function camelize(map) {
if (map) {
Object.keys(map).forEach(function(k) {
newK = k.replace(/(\_\w)/g, function(m) { return m[1].toUpperCase() });
if (newK != k) {
map[newK] = map[k];
delete map[k];
}
});
}
return map;
}
var revealHugoDefaults = { center: true, controls: true, history: true, progress: true, transition: "slide" };
var revealHugoSiteParams = {};
var revealHugoPageParams = {};
var revealHugoPlugins = {
plugins: [RevealMarkdown,RevealHighlight,RevealZoom,RevealNotes]
};
var options = Object.assign({},
camelize(revealHugoDefaults),
camelize(revealHugoSiteParams),
camelize(revealHugoPageParams),
camelize(revealHugoPlugins));
Reveal.initialize(options);
</script>
<script type="text/javascript" src="/mermaid.min_16862243754454536095.js"></script>
<script type="text/javascript">
mermaid.initialize({startOnLoad: false});
let render = (event) => {
let mermaidElems = event.currentSlide.querySelectorAll('.mermaid');
if (!mermaidElems.length){
return
}
mermaidElems.forEach(mermaidElem => {
let processed = mermaidElem.getAttribute('data-processed');
if (!processed){
mermaid.init(undefined, mermaidElem);
}
});
};
render({currentSlide: Reveal.getCurrentSlide()});
Reveal.on('slidechanged', render);
Reveal.on('ready', render);
</script>
</body>
</html>