<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title> - Devil Dahu developers blog</title>
	<link href="https://devildahu.ch/devlog/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://devildahu.ch/devlog/"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2023-08-11T00:00:00+00:00</updated>
	<id>https://devildahu.ch/devlog/atom.xml</id>
	<entry xml:lang="en">
		<title>A year of bevy, past and future</title>
		<published>2023-08-11T00:00:00+00:00</published>
		<updated>2023-08-11T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/bevy-3-years/" type="text/html"/>
		<id>https://devildahu.ch/devlog/bevy-3-years/</id>
		<content type="html">&lt;p&gt;Recently, &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;&quot;&gt;bevy&lt;&#x2F;a&gt; celebrated its &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;news&#x2F;bevys-third-birthday&#x2F;&quot;&gt;third anniversary&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I (Nicola) started using bevy around November 2021. This was under the impulse
of our &lt;em&gt;project mushroom&lt;&#x2F;em&gt; prototype. Since then, I invested myself more and more
in bevy. I contributed large features such as &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;news&#x2F;bevy-0-11&#x2F;#morph-targets&quot;&gt;morph targets&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;news&#x2F;bevy-0-11&#x2F;#parallax-mapping&quot;&gt;parallax mapping&lt;&#x2F;a&gt;, and I created useful plugins such as
&lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;bevy-debug-text-overlay&quot;&gt;&lt;code&gt;bevy-debug-text-overlay&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;bevy_scene_hook&quot;&gt;&lt;code&gt;bevy-scene-hook&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I also take a lot of time reviewing and giving feedback on
community-provided pull requests. During the last 12 months, according to
GitHub, I submitted &lt;strong&gt;200 PR reviews&lt;&#x2F;strong&gt; on bevy projects and &lt;strong&gt;opened 90 pull
requests&lt;&#x2F;strong&gt;. This means I am responsible for 5% of all bevy PRs in the past year,
and reviewed 10% of them (though GitHub might count multiple reviews on the
same PR).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-did-bevy-evolve-in-the-past-12-months&quot;&gt;How did bevy evolve in the past 12 months?&lt;&#x2F;h2&gt;
&lt;p&gt;I’m spending way too much time on bevy for my own good. While my wallet doesn’t
thank me for that, I have a clear idea of the health of the project.&lt;&#x2F;p&gt;
&lt;p&gt;So let’s share here what I see.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;code-reviews&quot;&gt;Code reviews&lt;&#x2F;h3&gt;
&lt;p&gt;I was impressed at the speed at which bevy was capable of processing pull
requests and integrate them. However, in the past three months, I see a drastic
slowdown in PR reviews. I think a lot of active members are focusing
on other things currently and don’t have as much time to review code.&lt;&#x2F;p&gt;
&lt;p&gt;It’s a shame, because this is blocking amazing features such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8808&quot;&gt;Cosmic text integration&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8784&quot;&gt;GPU picking&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8453&quot;&gt;System stepping (aka: time machine)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8308&quot;&gt;dynamic queries (aka: efficient script queries)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;5121&quot;&gt;archetype invariants&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;6161&quot;&gt;batched queries (aka: SIMD query iters)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’m also frustrated with the snail pace at which my own PRs gets reviewed. It’s
sad to open a PR or design suggestion and get no feedback on it for several weeks.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve no solution for this. I review &lt;em&gt;a lot&lt;&#x2F;em&gt; of PRs and it’s not
enough to compensate the PRs I open! The only option I see is a call to
action: &lt;strong&gt;please review bevy PRs&lt;&#x2F;strong&gt;, it will make bevy move much
faster, and it might attract more contributors who themselves may become
reviewers in time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rendering&quot;&gt;Rendering&lt;&#x2F;h3&gt;
&lt;p&gt;I’m extremely surprised at the insane speed at which bevy’s renderer progressed
in the past twelve months.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve no background in graphic programming, yet my most meaningful contributions
to bevy are rendering features.&lt;&#x2F;p&gt;
&lt;p&gt;This is thanks to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;superdump&quot;&gt;Rob&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sponsors&#x2F;james7132&quot;&gt;James&lt;&#x2F;a&gt;, and their excellent support in
introducing me to bevy’s gnarly rendering system.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, I think anyone who worked on bevy’s rendering system understands how
complex and error prone the code is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;discussions&#x2F;9036#discussioncomment-6350112&quot;&gt;&lt;strong&gt;Nine&lt;&#x2F;strong&gt; layers of very indirect abstractions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;issues&#x2F;9019&quot;&gt;Awfully cryptic error messages&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I wrote down in the bevy GitHub discussion forum a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;discussions&#x2F;9036#discussioncomment-6350112&quot;&gt;“guide” on how to navigate
the render code&lt;&#x2F;a&gt;, but it’s still incomplete and glosses over
major concepts.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ui&quot;&gt;UI&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;bevy_ui&lt;&#x2F;code&gt; has been seeing steady improvement in the past few months thanks to
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ickshonpe&#x2F;&quot;&gt;ickshonpe&lt;&#x2F;a&gt;. Current day bevy UI might look bad, but you don’t realize how
&lt;em&gt;awful&lt;&#x2F;em&gt; it was 12 months ago, especially looking at the internals. Thank you
ickshonpe for improving &lt;code&gt;bevy_ui&lt;&#x2F;code&gt; internals! It’s a very thankless work, they
deserve the shout out.&lt;&#x2F;p&gt;
&lt;p&gt;A bevy of bevy plugins exists to make handling UI easier. I’m personally
responsible for a few of those. Recently, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bytestring-net&#x2F;bevy-lunex&quot;&gt;lumex&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; came
out. Both try to abstract UI from UI rendering. I think it’s a viable path.
Re-using the sprite renderer also has the advantage of culling a lot of
duplicate code.&lt;&#x2F;p&gt;
&lt;p&gt;It’s also important to note &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;bevy_ui_dsl&quot;&gt;&lt;code&gt;bevy-ui-dsl&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. It was a breakthrough in bevy UI
declaration ergonomics, &lt;code&gt;cuicui_dsl&lt;&#x2F;code&gt; is mostly derived from &lt;code&gt;bevy-ui-dsl&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;&#x2F;h3&gt;
&lt;p&gt;Performance and code size has been steadily declining in the past 12 months.
It’s currently difficult to know how much performance impact your PR has, and
it’s currently too burdensome to benchmark changes outside of perf-focused PRs.
We need to have better benchmarking (or any benchmarking at all) in order to
avoid the trap of steady bloat and perf decline.&lt;&#x2F;p&gt;
&lt;p&gt;Other engines fell out of relevance partially due to this kind of bloat.
This is a threat to bevy and we should be careful to avoid it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-next-for-bevy&quot;&gt;What’s next for bevy&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ui-1&quot;&gt;UI&lt;&#x2F;h3&gt;
&lt;p&gt;I suspect bevy is going to see a lot of change in UI in the near future.&lt;&#x2F;p&gt;
&lt;p&gt;ickshonpe has been doing stellar work on bevy’s UI.
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IDEDARY&quot;&gt;IDEDARY&lt;&#x2F;a&gt; ported their &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bytestring-net&#x2F;bevy-lunex&quot;&gt;longstanding game UI toolkit&lt;&#x2F;a&gt; recently to bevy.
I broke ground on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;cuicui&#x2F;tree&#x2F;main&#x2F;richtext&quot;&gt;&lt;code&gt;cuicui_richtext&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and started work on &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
Cart mentioned they want to focus on UI next.&lt;&#x2F;p&gt;
&lt;p&gt;I really hope we get an ECS-based solution for UI state. The only
difference between storing state in the ECS and passing state to a sort of
react&#x2F;tauri-like framework is that you won’t be able to query UI state outside
of UI code.&lt;&#x2F;p&gt;
&lt;p&gt;My wish list for UI is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Easy, hot reloadable, UI declaration syntax. Should have the ability to
integrate with rust logic, while not itself containing logic (so that it is
hot-reloadable)&lt;&#x2F;li&gt;
&lt;li&gt;A rust-based UI declaration API with good error messages and trivial
layouting algo, such that it’s easy to know the end result from the code
(yes, this is the &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; tagline)&lt;&#x2F;li&gt;
&lt;li&gt;Tool to build visually a UI. But the tool in question should follow closely
the UI declaration syntax&lt;&#x2F;li&gt;
&lt;li&gt;Debugging tools similar to &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;A way to use UI with sprites, and maybe within 3D worlds if possible. (also
a &lt;a href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;cuicui_layout&quot;&gt;&lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; tagline)&lt;&#x2F;li&gt;
&lt;li&gt;Good integration in ECS, so that interoperability between bevy systems and
the UI are trivial (I have in mind the &lt;code&gt;cuicui_bevy_fab&lt;&#x2F;code&gt; query system).&lt;&#x2F;li&gt;
&lt;li&gt;Way to &lt;em&gt;also&lt;&#x2F;em&gt; define logic based on inlined rust code (not sure why people
think it’s mutually exclusive with bevy systems)&lt;&#x2F;li&gt;
&lt;li&gt;Amazing richtext module (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;cuicui&#x2F;tree&#x2F;main&#x2F;richtext&quot;&gt;&lt;code&gt;cuicui_richtext&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; &lt;em&gt;cough cough&lt;&#x2F;em&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Setting up gamepad and keyboard-based UI navigation without headaches.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;What&amp;#x27;s the plan for your UI crates?&lt;&#x2F;h4&gt;
		&lt;p&gt;&lt;code&gt;bevy-ui-navigation&lt;&#x2F;code&gt; should be split up, so that it focuses entirely on
keyboard&#x2F;gamepad driven navigation, and leave pointer-based UI to other crates.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;cuicui_richtext&lt;&#x2F;code&gt; is on hiatus. Its scope has exploded and I’m not sure what the
way forward is.&lt;&#x2F;p&gt;
&lt;p&gt;I’m still working on &lt;code&gt;cuicui_layout&lt;&#x2F;code&gt;. I’m working on an &lt;em&gt;even better&lt;&#x2F;em&gt; debugging
view, with more detailed text information on container state. A hot-reloadable
UI declaration syntax is on the roadmap.&lt;&#x2F;p&gt;
&lt;p&gt;Currently I’m taken up in other duties and progress on those crates are stalled
for the next month or so.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;reflection&quot;&gt;Reflection&lt;&#x2F;h3&gt;
&lt;p&gt;I also see a lot of potential for reflection. Currently it depends a lot on
rust’s trait objects. This is safe and easy to validate. But I see a future
where &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; works on a much lower level, leveraging pointer offsets
and memory layout.&lt;&#x2F;p&gt;
&lt;p&gt;This would make &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; viable on a much broader set of use cases. I
suspect it could help us reduce the binary size of bevy apps, as a lot of the
code size (10%) are instantiation of generic functions, such as &lt;code&gt;FromType&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;
and &lt;code&gt;App::init_resource&lt;&#x2F;code&gt;. Hopefully we can move most of the code into erased
function that works on bits rather than specific types.&lt;&#x2F;p&gt;
&lt;p&gt;My wish list for reflection:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamic queries: makes it possible to construct in non-rust code queries,
submit them to bevy and get &lt;code&gt;&amp;amp;dyn Reflect&lt;&#x2F;code&gt; in response.&lt;&#x2F;li&gt;
&lt;li&gt;Offset-based field dereference. So that accessing a field of a struct is
literally as efficient as just doing it in rust. Currently it calls a
dynamic trait object method. With path-based reflection, it may do it several
times.&lt;&#x2F;li&gt;
&lt;li&gt;Fast, efficient World se&#x2F;deser based on reflection. I designed &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;bvyfst&quot;&gt;&lt;code&gt;bvyfst&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; as
a testbed for a max performance bevy scene format, but it requires deriving
additional stuff on components.&lt;&#x2F;li&gt;
&lt;li&gt;The Unique Reflect RFC is implemented.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;What&amp;#x27;s up with unique reflect?&lt;&#x2F;h4&gt;
		&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;rfcs&#x2F;pull&#x2F;56&quot;&gt;Unique Reflect RFC&lt;&#x2F;a&gt; is more a set of guidelines on how to think and
document &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; features. I’m already satisfied with it, in that it has
been helpful to bevy contributors to design and document their code.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;rendering-1&quot;&gt;Rendering&lt;&#x2F;h3&gt;
&lt;p&gt;There is still two major rendering PRs open: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8006&quot;&gt;PCF shadows&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;8015&quot;&gt;light transmission&lt;&#x2F;a&gt;. They will be merged quickly before 0.12. Those are
amazing features to have!&lt;&#x2F;p&gt;
&lt;p&gt;Otherwise, I think it’s time to rethink bevy’s rendering system. Griffin worked
on a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;pull&#x2F;9258&quot;&gt;deferred renderer&lt;&#x2F;a&gt; for bevy. JMS55 have been considering ways to simplify
our gnarly rendering systems. My personal wish list is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A less indirect rendering approach, make obvious when rendering code runs&lt;&#x2F;li&gt;
&lt;li&gt;Shortcuts for bind group &amp;amp; bind group layout creation. Currently, most of the rendering
code is bind group creation boilerplate.&lt;&#x2F;li&gt;
&lt;li&gt;Better handling of shader defs. We could track what bind group layout each
shader def requires, so that errors are more easily surfaced.&lt;&#x2F;li&gt;
&lt;li&gt;Vertex attribute generation. This is a requirement for arbitrary morph
targets.&lt;&#x2F;li&gt;
&lt;li&gt;Better error messages. I suspect keeping track of bind groups, entity and
comparing them to the shader of render pipeline would be very helpful. But in
a prefect world, we would track and tell the users which line (in rust and
their shader) is causing the error.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Strangely, I have the presentiment that such improvements are dependent on
better understanding of what would make a great bevy UI framework, and better
reflection.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Why I&amp;#x27;m not working on adding parallax mapping to the prepass&lt;&#x2F;h4&gt;
		&lt;p&gt;Ideally we run parallax mapping in the prepass. We would update the depth
buffer so that shadow mapping, TAA, SSAO, and proper object occlusion follows
the visuals of the geometry with parallax mapping applied. But parallax
mapping is fairly costly, and running it once per shadow-casting source, and
bloating the perpass with it is bad.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;editor&quot;&gt;Editor&lt;&#x2F;h3&gt;
&lt;p&gt;The editor is blocked on better UI. There has been a lot of discussion on the
editor. Whether it should use IPC or be an in-game bevy plugin. What design
guidelines to follow, etc. However, for my part, I refuse to partake in such
speculative discussions before the UI story is resolved.&lt;&#x2F;p&gt;
&lt;p&gt;I designed the &lt;a href=&quot;&#x2F;devlog&#x2F;making-of-klod-tech&#x2F;&quot;&gt;klod editor&lt;&#x2F;a&gt; so I may comment on it. To me, the Klod editor was
useful because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It let me place visually objects in scenes, fixing up at the last minute
levels I designed in Blender.&lt;&#x2F;li&gt;
&lt;li&gt;I could extend it to bring my own key mapping (I prefer Blender’s keymaps)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;gizmos&quot;&gt;Gizmos&lt;&#x2F;h3&gt;
&lt;p&gt;Bevy’s gizmos are still very limited. As a result, gizmos from one plugin do
not play well with gizmos from other plugins. As more crates adopt gizmos, we
might see more and more conflicts. My &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;issues&#x2F;9400&quot;&gt;amazing gizmos tracking issue&lt;&#x2F;a&gt;
is already a wish list, so I won’t write one here.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-bevy-book&quot;&gt;The bevy book&lt;&#x2F;h3&gt;
&lt;p&gt;This has been cooking &lt;em&gt;forever&lt;&#x2F;em&gt; and it’s a major failure of the project IMO.
But we finally started work on it, and I’m expecting to see an amazing
high quality guide for newcomers taking shape in the next 12 months.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bevy-ci&quot;&gt;Bevy CI&lt;&#x2F;h3&gt;
&lt;p&gt;I think bevy has now outgrown the capabilities of GitHub CI and needs dedicated
CI hardware. I would love to see a bevy build server for the following reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Faster CI for PRs &amp;amp; merges. Faster site deployment, all the goodies!&lt;&#x2F;li&gt;
&lt;li&gt;Regular benchmarks to track bevy’s performance and compiled binary size. We
do love graphs, let’s make graphs.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rustc has an excellent benchmarking setup, and it would be lovely if we had a
similar one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-short&quot;&gt;In short&lt;&#x2F;h2&gt;
&lt;p&gt;Bevy has been moving forward at an incredible pace. The only negative thing I can
say about it is that it didn’t move &lt;em&gt;even faster&lt;&#x2F;em&gt;. It’s already an
&lt;em&gt;incredible pace&lt;&#x2F;em&gt; because it’s far beyond any expectation. So it would be
ridiculous to complain about it not being faster.&lt;&#x2F;p&gt;
&lt;p&gt;I have nothing but positive things to say of cart and the community. Just
“let’s go!!!”&lt;&#x2F;p&gt;
&lt;p&gt;And remember, &lt;strong&gt;please review bevy PRs!!!!!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Our dev environment</title>
		<published>2023-02-26T00:00:00+00:00</published>
		<updated>2023-02-26T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/fossil-setup/" type="text/html"/>
		<id>https://devildahu.ch/devlog/fossil-setup/</id>
		<content type="html">&lt;p&gt;A setup post this week, because I’ve really no progress to report on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fossil&quot;&gt;Fossil&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;fossil-scm.org&#x2F;home&quot;&gt;Fossil&lt;&#x2F;a&gt; is a source code management system similar to &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;&quot;&gt;git&lt;&#x2F;a&gt;.
Unlike git, it integrates project management features like bug tracking, wikis,
and account access control. It’s very much like github, but you can manage it
yourself.&lt;&#x2F;p&gt;
&lt;p&gt;Our &lt;a href=&quot;https:&#x2F;&#x2F;www.nearlyfreespeech.net&#x2F;&quot;&gt;web host&lt;&#x2F;a&gt; comes with &lt;em&gt;fossil preinstalled&lt;&#x2F;em&gt;. Issue is that at the
time I didn’t know it, so it took me a while to get there. But once I figured I
could just use the preinstalled version, it went as simply as it could.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;timeline.png&quot;
  alt=&quot;A screenshot of the necking fossil project timeline, with a site style
  similar to this one, the timeline stops at exactly the 2023-02-19&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;Once I got things setup, &lt;em&gt;of course&lt;&#x2F;em&gt;, the first thing I did was personalize the
CSS. As you can see, I went ham.&lt;&#x2F;p&gt;
&lt;p&gt;In terms of source code version control, fossil doesn’t change much from git.
It is opinionated toward trunk-based development, and automatically syncs
before commit. Otherwise, the most important difference is the absence of a
staging area.
But for solo dev, it’s not that different.&lt;&#x2F;p&gt;
&lt;p&gt;In terms of project management. I didn’t have the opportunity to use the wiki
and tickets. However, unlike gitlab, fossil is extremely efficient. And unlike
gitea, it runs as a CGI script. Which means I can use it on my host provider.
Fossil, furthermore, is fully open source: No gated functionalities,
no artificial limitations.
It has an expansively fine-grained user access control panel,
and a way to sync them between repositories.&lt;&#x2F;p&gt;
&lt;p&gt;For game development, fossil is lacking large file support. I’m currently using
the “untracked files” feature to publish (internally) the assets with the dev
game executable.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally, tracking of assets goes beyond source control, and is integrated
into the game executable as much as source control.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;discord&quot;&gt;Discord&lt;&#x2F;h2&gt;
&lt;p&gt;devildahu exists mostly as a discord server where we coordinate our efforts.
(note that we also have &lt;a href=&quot;https:&#x2F;&#x2F;discord.gg&#x2F;7YDVBdw5c6&quot;&gt;a public discord server&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The little programming I did this week involved creating a bot to post fossil
timeline updates to our discord server.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 220px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;discord.png&quot;
  alt=&quot;Screenshot of a lot of messages made by a discord bot&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The bot is just a rust program running once per hour on the web host that
calls the fossil executable like so: &lt;code&gt;fossil rss&lt;&#x2F;code&gt; and posts to a
&lt;a href=&quot;https:&#x2F;&#x2F;support.discord.com&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;228383668&quot;&gt;discord webhook&lt;&#x2F;a&gt; a summary. Using a rss
parsing crate, I read the relevant metadatas and, with serde, converts them
into the POST payload for the line item.&lt;&#x2F;p&gt;
&lt;p&gt;This enable us to know what each other is working on. Because &lt;del&gt;I’m terribly
obsessive and want to know everything my friends do&lt;&#x2F;del&gt; it allows to build trust
by making our work and contribution to the team visible. Hopefully motivate
each other to contribute more, and know where to focus our contributions.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>2023 devlog 3</title>
		<published>2023-02-19T00:00:00+00:00</published>
		<updated>2023-02-19T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/necking-3/" type="text/html"/>
		<id>https://devildahu.ch/devlog/necking-3/</id>
		<content type="html">&lt;p&gt;Third weekly devildahu devlog, the last one is &lt;a href=&quot;&#x2F;devlog&#x2F;necking-2&#x2F;&quot;&gt;available here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is going to be short, as I burnt a bit out and kept 3 days for myself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bevy-mod-cuicui&quot;&gt;&lt;code&gt;bevy_mod_cuicui&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As promised last week, I spent more time thinking about UI in bevy.&lt;&#x2F;p&gt;
&lt;p&gt;After the last post, which helped me better understand what I wanted, I quickly
came to the conclusion that I didn’t want to make a UI framework.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to keep in the bevy spirit, create primitives and build UI on top of
those primitives. An integrated framework solution, not only is antithetical to
bevy’s goals, but also antithetical to my own principles.&lt;&#x2F;p&gt;
&lt;p&gt;I was designing the &lt;code&gt;Prefab&lt;&#x2F;code&gt; interface for &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bevy_mod_cuicui&quot;&gt;&lt;code&gt;bevy_mod_cuicui&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, but I came to
the conclusion, such an interface wasn’t needed (while not exactly useless). My
current assessment is that I just want several ways to “spawn” or “specify” an
UI:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I want a way to define my UI through a simple text format, I want this to be
composable, and extensible through bevy’s &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;bevy_reflect&#x2F;latest&#x2F;bevy_reflect&#x2F;&quot;&gt;&lt;code&gt;Reflect&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; trait.&lt;&#x2F;li&gt;
&lt;li&gt;I want a concise but beautiful by-default way of specifying a tree of UI
elements. Ideally, this is composable, extensible and type-safe.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Those two ways are not mutually exclusive, but they are definitively unrelated.&lt;&#x2F;p&gt;
&lt;p&gt;This is pretty much the result of half a second of through after last devlog.
It really took me more time to write this section than go to this conclusion.&lt;&#x2F;p&gt;
&lt;p&gt;So I went back to an older abandoned project of mine (I tend to accumulate
those)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bevy-kdl-ui&quot;&gt;&lt;code&gt;bevy-kdl-ui&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;bevy-kdl-ui&quot;&gt;&lt;code&gt;bevy-kdl-ui&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; was my first attempt at solving the bevy ui problem. The
premise was informed by insights that I seem to have forgotten:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How great it was to use a LISP interpreter for defining state machines for
project mushroom. As I could use LISP macros to make state machine declarations
composable, without writing any parsing code.
(for my defence, a similar system was used in The Last of Us)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Prefab&lt;&#x2F;code&gt;s (meaning: a tree of ECS entities with collections of components)
can be expressed as a macro, parameters as macro parameters, etc. All the
work could be done before deserialization.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I actually spent a lot of efforts on &lt;code&gt;bevy-kdl-ui&lt;&#x2F;code&gt; before abandoning it.
But I still think this model may help, so I went to it and tried to at least
get a minimal working version (if even extremely buggy, slow and limited) to
see if I could iterate on it and start building a collection of widgets on top
of it.&lt;&#x2F;p&gt;
&lt;p&gt;In the space of 3 days, I gorked the code, then wrote a bevy loader for the
deserialization format that already worked (thanks to an excellent test suit).&lt;&#x2F;p&gt;
&lt;p&gt;I wrote an example, but never ran it. It feels very unpleasant working on it.
Every functionality I added needed very ugly hacks (for example,
the loader doesn’t use bevy’s loading system due to dependency management, it
also isn’t asynchronous, due to the complexity of managing a cache of loaded
templates). So of course, most of the code I write is marked for refactoring,
it just feels wrong.&lt;&#x2F;p&gt;
&lt;p&gt;As a result I didn’t do much more. I hope to get back on track for next week.&lt;&#x2F;p&gt;
&lt;p&gt;(you may be interested in this blog’s [rss] feed)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Necking devlog 2</title>
		<published>2023-02-12T00:00:00+00:00</published>
		<updated>2023-02-12T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/necking-2/" type="text/html"/>
		<id>https://devildahu.ch/devlog/necking-2/</id>
		<content type="html">&lt;p&gt;Second weekly devildahu devlog, the first one is &lt;a href=&quot;&#x2F;devlog&#x2F;necking-1&#x2F;&quot;&gt;available here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;necking&quot;&gt;Necking&lt;&#x2F;h2&gt;
&lt;p&gt;This week, I only dedicated 3 days to Necking, and three very short days at
that.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to make Necking more editable to enable less technical members of the
team to play with parameters of the game, and especially load arbitrary models
for the giraffes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;scene-reload&quot;&gt;Scene reload&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;bevyengine.org&#x2F;&quot;&gt;bevy&lt;&#x2F;a&gt; ostensibly supports hot reloading.
However, hot reloading in bevy is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevyengine&#x2F;bevy&#x2F;issues&#x2F;3759&quot;&gt;broken for scenes&lt;&#x2F;a&gt;.
This is a problem, since giraffes are loaded as scenes, this bug would 
prevent loading live new giraffe models.&lt;&#x2F;p&gt;
&lt;p&gt;Solving this involved two things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Have some sort of management of scenes to keep track of spawned entities
related to a scene.&lt;&#x2F;li&gt;
&lt;li&gt;Writing hot-reloading code.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;For (1) I was already using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;bevy-scene-hook&quot;&gt;&lt;code&gt;bevy-scene-hook&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. However, as implemented, it
didn’t allow for reloading. So I created a &lt;code&gt;reload&lt;&#x2F;code&gt; module, mostly a copy of
the original code, but with handling for respawning and despawing.&lt;&#x2F;p&gt;
&lt;p&gt;For (2), I started by shamelessly copying the bevy code for hot-reloading,
it’s about 30 lines of code. It’s nothing more than creating a
&lt;code&gt;RecommendedWatcher&lt;&#x2F;code&gt; from the &lt;a href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;notify&quot;&gt;notify crate&lt;&#x2F;a&gt;, establishing a communication
channel between it and a bevy system and reacting to events it sends.&lt;&#x2F;p&gt;
&lt;p&gt;I kept this code, and when receiving an event, I set the &lt;code&gt;ReloadSate&lt;&#x2F;code&gt; component
from the newly created &lt;code&gt;reload&lt;&#x2F;code&gt; module of &lt;code&gt;bevy-scene-hook&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parametrization&quot;&gt;Parametrization&lt;&#x2F;h3&gt;
&lt;p&gt;I’ve been a great fan of &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;c&#x2F;sora_sakurai_en&#x2F;videos&quot;&gt;Sakurai’s series on video games&lt;&#x2F;a&gt;.
He explains in one of those videos that he uses an &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=nGaajB8m5Q0&quot;&gt;Excel Add-In to manage
all the parameters&lt;&#x2F;a&gt; (damage, time, cancel frames etc.)
of the Smash Bross characters.&lt;&#x2F;p&gt;
&lt;p&gt;Necking had a lot of parameters hardcoded. But as a good programmer, I avoid
just sprinkling the code with arbitrary values. Most of the parameters, even if
hardcoded, were named and centralized as a series of &lt;code&gt;const&lt;&#x2F;code&gt; definitions.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Hot programming tip&lt;&#x2F;h4&gt;
		&lt;p&gt;If in your code, you see a literal value within a function such as &lt;code&gt;0.132&lt;&#x2F;code&gt;
(something extremely specific), it is probably worthwhile to replace it with a
constant. Naming things help build a semantic narrative around what your code
is doing.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore if in the future, you need to
re-use the same value, you can simply use the variable name rather than
copy&#x2F;paste the value:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; What is 12.344???
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;do_the_foobar&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;position&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; Vec3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  position&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;12.344&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; much better,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; I know that I&amp;#39;m adding RETICULAR_OFFSET to `x`!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RETICULAR_OFFSET&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;12.344&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;do_the_foobar&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;position&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; Vec3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  position&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span&gt;RETICULAR_OFFSET&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My goal was to get rid of all those &lt;code&gt;const&lt;&#x2F;code&gt;s and replace them with a bevy
resource that I would load at startup from an external file.&lt;&#x2F;p&gt;
&lt;p&gt;I also wanted to be able to &lt;em&gt;write&lt;&#x2F;em&gt; a template file, ideally with default
values taken from the &lt;code&gt;const&lt;&#x2F;code&gt;s pre-existing values.&lt;&#x2F;p&gt;
&lt;p&gt;It was almost straightforward. I decided to create a &lt;code&gt;struct Parameters&lt;&#x2F;code&gt; per
bevy plugin&#x2F;rust module that used to rely on hardcoded &lt;code&gt;const&lt;&#x2F;code&gt; values.&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;#[&lt;&#x2F;span&gt;&lt;span&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;Clone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Debug&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Resource&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Default&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;#[&lt;&#x2F;span&gt;&lt;span&gt;cfg_attr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;feature &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;Reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; FromReflect&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;))]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span&gt;Parameters &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;controls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;scheme&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;cam&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;input_mapping&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Mapping,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;models&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Models,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;scheme &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;#[&lt;&#x2F;span&gt;&lt;span&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;Clone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Debug&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Resource&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Default&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;#[&lt;&#x2F;span&gt;&lt;span&gt;cfg_attr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;feature &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;Reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; FromReflect&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;))]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;super&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Parameters &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;      giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;      tongue&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;tongue&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Parameters,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;neck &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;super&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Parameters &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      idle_stiffness_multiplier&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;      idle_damping_multiplier&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;      moving_stiffness_multiplier&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;giraffe &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;cam &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, in systems defined in those plugins, I would add a &lt;code&gt;Res&amp;lt;Parameters&amp;gt;&lt;&#x2F;code&gt; to
access the parameters, instead of directly using a &lt;code&gt;const&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This worked fairly well, the rust module privacy system also aligns very
nicely with this. In a module, I needed to access the root &lt;code&gt;Parameters&lt;&#x2F;code&gt; fields,
so the root’s field needed to be public, but each individual module
&lt;code&gt;Parameters&lt;&#x2F;code&gt; could keep their field private, hence limiting what can be
influenced by which field, resulting in much more robust code.&lt;&#x2F;p&gt;
&lt;p&gt;A snag was the hook for spawning giraffes. The physics parameters for the neck
are used in the &lt;code&gt;scheme::neck&lt;&#x2F;code&gt; module, but also in the &lt;code&gt;neck&lt;&#x2F;code&gt; module, where the
giraffe is spawned.&lt;&#x2F;p&gt;
&lt;p&gt;I simply made those parameters public across the whole game, so that I could
use them in both places. The cleaner solution would have been to get rid of
that &lt;code&gt;neck&lt;&#x2F;code&gt; module, but I didn’t have time for that.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;serializing-parameters&quot;&gt;Serializing parameters&lt;&#x2F;h3&gt;
&lt;p&gt;Only thing left to do was reading and writing to a file the parameters, so that
they could be changed by anyone with a text editor.&lt;&#x2F;p&gt;
&lt;p&gt;I hit a snag here. I relied on bevy’s &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; for serialization, this is
because &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; is readily available. The standard rust crate for
serialization is &lt;code&gt;serde&lt;&#x2F;code&gt;, but it has the reputation of drastically slowing
down compile time.&lt;&#x2F;p&gt;
&lt;p&gt;I then used the &lt;a href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;toml&quot;&gt;&lt;code&gt;toml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate for the parameters file.
When I first launched the game to write the
default list of parameters, I hit a very generic error. It said something along
the line of “enums are not supported” without further details. I recalled that once
upon a time, &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt; didn’t support serialization of &lt;code&gt;enum&lt;&#x2F;code&gt;s. But having myself
reviewed the code that added support for &lt;code&gt;enum&lt;&#x2F;code&gt;s in &lt;code&gt;bevy_reflect&lt;&#x2F;code&gt;, I was very
surprised to encounter this error now!&lt;&#x2F;p&gt;
&lt;p&gt;Turned out the error emanated from the &lt;a href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;toml&quot;&gt;&lt;code&gt;toml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate, indeed, the
doc string for the &lt;code&gt;toml::ser::Serializer&lt;&#x2F;code&gt; struct has a line explaining that
&lt;code&gt;toml&lt;&#x2F;code&gt; doesn’t support enums (It would have been judicious to advertise that
limitation in the README or the crate-level doc string, or having a better
error message).&lt;&#x2F;p&gt;
&lt;p&gt;In my &lt;code&gt;Parameters&lt;&#x2F;code&gt;, I only had a single &lt;code&gt;enum&lt;&#x2F;code&gt;, for custom input:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;KmKey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    Mouse&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;MouseButton&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    Key&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;KeyCode&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I needed to replace this. I immediately thought of two options:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use a &lt;code&gt;struct&lt;&#x2F;code&gt; with two &lt;code&gt;Option&lt;&#x2F;code&gt; fields, one for mouse buttons, one for
keyboard keys.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;MouseButton&lt;&#x2F;code&gt; and &lt;code&gt;KeyCode&lt;&#x2F;code&gt; being two enums, merge them in a giga-enum.
Precisely, what &lt;a href=&quot;https:&#x2F;&#x2F;lib.rs&#x2F;crates&#x2F;toml&quot;&gt;&lt;code&gt;toml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; doesn’t support are enums with data, &lt;code&gt;KeyCode&lt;&#x2F;code&gt; and
&lt;code&gt;MouseButton&lt;&#x2F;code&gt; are what rust calls “C-like enums”, they do not have
associated data, so making a large enum would work.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I opted for (2), &lt;code&gt;KeyCode&lt;&#x2F;code&gt; is a very large enum, but whatever eh! If at any
point &lt;code&gt;KeyCode&lt;&#x2F;code&gt; or &lt;code&gt;MouseButton&lt;&#x2F;code&gt; in bevy changes, I’ll have a compilation error
allowing me to update the enum. This is thanks to rust’ exhaustiveness check.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-february-game&quot;&gt;The February game&lt;&#x2F;h2&gt;
&lt;p&gt;I solicited game ideas in the devildahu discord chat for the 3 weeks project.
Brinzer posted his detailed design doc of &lt;strong&gt;PointFusion&lt;&#x2F;strong&gt;, a 2d Ik-driven game.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not sure it’s possible to complete it in 3 weeks, so you might not hear
much more of it until the distant future.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cuicui&quot;&gt;Cuicui&lt;&#x2F;h2&gt;
&lt;p&gt;In the meantime, between two games projects, I thought it would be productive
to focus on my UI framework, &lt;code&gt;bevy_mod_cuicui&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A very naive thought.&lt;&#x2F;p&gt;
&lt;p&gt;I spent the past 4 days writing design documentation, just to know what code to
write for it! I always feel “so close” to getting somewhere, yet at each point
in time, I am seemingly as far from a solution as I was at any given moment in
the past.&lt;&#x2F;p&gt;
&lt;p&gt;I think this stems from me not having an exact idea of what I want to do with
&lt;code&gt;bevy_mod_cuicui&lt;&#x2F;code&gt;. How much flexibility should it have? What should it do?&lt;&#x2F;p&gt;
&lt;p&gt;After 4 days though, I’m convinced (as I was 2 days ago though) that I’ve
a vague – if not clear – idea of what I want.&lt;&#x2F;p&gt;
&lt;p&gt;Bevy and ECS’s strength is in modularity. I don’t really want to write a UI
framework. UI frameworks have a tendency to be totalitarian, they deal poorly
with things that exist outside of them. This is the antithesis of what I want
to do. I want to empower people, give more possibilities.&lt;&#x2F;p&gt;
&lt;p&gt;My current plan is to simply write a few systems, that, if used together,
enable a pleasant UI experience in bevy:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The layout algorithm I mentioned &lt;a href=&quot;&#x2F;devlog&#x2F;necking-1&#x2F;&quot;&gt;last week&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;code&gt;Prefab&lt;&#x2F;code&gt; trait to spawn things into the ECS, despawn them and query their
current state.&lt;&#x2F;li&gt;
&lt;li&gt;A set of &lt;code&gt;Prefab&lt;&#x2F;code&gt;s to build UI elements that are a composition of
entities.&lt;&#x2F;li&gt;
&lt;li&gt;A QT-inspired signaling system, where functions associated with certain
entities can be “activated” and read the state of children entities to do
things.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I’m still not sure for (4). The goal is to avoid footguns and enable developers
to reason locally (avoid having to think holistically, accidentally mixing
several instances of the UI elements)&lt;&#x2F;p&gt;
&lt;p&gt;I’ll probably need an ultimate layer of coating on this. Raw, it will still be
painful to use, so I expect to add something like a macro to thread together
multiple UI elements.&lt;&#x2F;p&gt;
&lt;p&gt;Turns out making a UI framework is as difficult as people say.&lt;&#x2F;p&gt;
&lt;p&gt;(you may be interested in this blog’s &lt;a href=&quot;&#x2F;devlog&#x2F;atom.xml&quot;&gt;rss&lt;&#x2F;a&gt; feed)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Necking devlog 1</title>
		<published>2023-02-05T00:00:00+00:00</published>
		<updated>2023-02-05T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/necking-1/" type="text/html"/>
		<id>https://devildahu.ch/devlog/necking-1/</id>
		<content type="html">&lt;p&gt;I’m Nicola. This is the beginning of devildahu’s weekly devlog. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;necking&quot;&gt;Necking&lt;&#x2F;h2&gt;
&lt;p&gt;We are working on Necking.
Necking is a competitive&#x2F;cooperative 1-on-1 online game where players are
giraffes and fight for male dominance in the giraffe way.&lt;&#x2F;p&gt;
&lt;p&gt;Necking is the way
male giraffes fight each other to assert dominance.
Level of violence during necking vary widely, going from drawing blood,
including quick one-tap-and-its-over and even reaching the zone of affection
where it’s difficult to tell if the giraffes are hitting each other or
tenderly caressing.&lt;&#x2F;p&gt;
&lt;p&gt;Necking started as a project in late December 2021, after watching an animal
documentary on giraffes. So that’s a bit more than a year ago.
I’ve been contributing to it on and off for the past year. I’ve
picked up at a faster pace development about two weeks ago (19th of January)&lt;&#x2F;p&gt;
&lt;p&gt;I had stopped work on the project around July 2022, in the middle of a
migration.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;custom-joint-system&quot;&gt;Custom joint system&lt;&#x2F;h3&gt;
&lt;p&gt;Initially, the game used custom joint physics, built on the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jcornaz&#x2F;heron&quot;&gt;heron&lt;&#x2F;a&gt;
collision detection library (it is a physics library, but at the time, we only
used the collision detection). In 2022, &lt;a href=&quot;https:&#x2F;&#x2F;rapier.rs&#x2F;&quot;&gt;rapier&lt;&#x2F;a&gt; (a popular rust physics library)
got a really good integration with &lt;a href=&quot;bevyengine.org&#x2F;&quot;&gt;bevy&lt;&#x2F;a&gt; and I decided to migrate to it.&lt;&#x2F;p&gt;
&lt;p&gt;The joint physics looked great but didn’t have credible or enjoyable physics at
all, which is a major issue for a physics-based video game.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;capsule_giraffes.jpg&quot;
  alt=&quot;Three giraffes fighting, the giraffes are made of a large yellow box and
  seven default capsule 3d shapes for neck, the heads are also just a single
  box&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;neck-diagram.jpg&quot;
  alt=&quot;3d Diagram describing how input on a X&#x2F;Y axis can be translated into
  a capsule rotation&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 600px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;serial-tilt-explanation.svg&quot;
  alt=&quot;Diagram showing how to compute the position of the N-th capsule in a
  chain of capsules based on a given input&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;migrating-to-rapier&quot;&gt;Migrating to rapier&lt;&#x2F;h3&gt;
&lt;p&gt;In the week of the 19th I spent most of my time reimplementing existing
features. Notably mouse controls. I also rewrote the way input is translated
into actions (of course, since that’s the part that touches the physics).&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;mouse-picking.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;mouse picking&lt;&#x2F;p&gt;
&lt;h3 id=&quot;target-indicator&quot;&gt;Target indicator&lt;&#x2F;h3&gt;
&lt;p&gt;I added little arrows to show in which direction the neck is tilting.
I felt that the movement was very difficult to read without the arrows. The
arrows represent the “target” position of the neck, the one the giraffe tries
to reach, but due to its limited strength, and being pushed by the other
giraffe, won’t necessarily be the exact position of the neck.
So what is shown on screen doesn’t reflect exactly the player input. This is
really bad, it feels wrong and sluggish, there is a dissociation between input
and effect. Adding the arrows shows to the player as soon as possible that the
game registered their input. It feels &lt;em&gt;just right&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bevy-controls-design&quot;&gt;Bevy controls design&lt;&#x2F;h3&gt;
&lt;p&gt;On a more technical aspect. I completely rewrote the &lt;em&gt;controls&lt;&#x2F;em&gt; system. This
involved transforming a single component representing all possible input
methods, including AI and Network controlled giraffes, into many different
components, four (4) per input methods.&lt;&#x2F;p&gt;
&lt;p&gt;It’s a bit weird and contrary to what I’m used to do, but it actually works
extremely well. There is a component to control each neck vertebra using mouse,
using the left stick, the right stick, etc. There is a component for each way
to control the whole giraffe body, etc. There are even 3 different components
to control the tongue of the giraffe!&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub mod &lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub mod &lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub mod &lt;&#x2F;span&gt;&lt;span&gt;tongue&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;..
&lt;&#x2F;span&gt;&lt;span&gt;        app&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;init_resource&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;Dragging&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;gt;()
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;apply_left_stick&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;apply_right_stick&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;apply_stick_move_stiffness&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;apply_mouse&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;reset_mouse&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;neck&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;apply_mouse_move_stiffness&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;controller_cam_update&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;before&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;keyboard_cam_update&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;before&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;keyboard_move&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;before&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;giraffe&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;controller_move&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;before&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tongue&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;gp_move&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;add_system&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tongue&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;keyboard_move&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bevy-ui&quot;&gt;Bevy UI&lt;&#x2F;h3&gt;
&lt;p&gt;I also rewrote the UI. The last draft used my library, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;bevy-ui-build-macros&quot;&gt;bevy-ui-build-macros&lt;&#x2F;a&gt;.
It is a monstrosity, please do not use it.&lt;&#x2F;p&gt;
&lt;p&gt;Because it is a monstrosity, I had
to switch to something different. The default way to define UI in bevy is a
catastrophe, so I needed something else to replace my ungodly macro.
Recently, someone posted in the bevy discord
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Anti-Alias&#x2F;bevy_ui_dsl&quot;&gt;bevy_ui_dsl&lt;&#x2F;a&gt;. I used this, but it felt like it didn’t improve much on the
default experience.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, once I could just press spacebar twice to start the game, I left that
on the side and focused on gameplay. There is still so much other stuff to do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;second-week&quot;&gt;Second week&lt;&#x2F;h2&gt;
&lt;p&gt;All of that was in the first week of the development resumption. I could now
focus on actual gameplay.&lt;&#x2F;p&gt;
&lt;p&gt;I added movement. The giraffe controls exactly like a tank. This required
changing the camera point of view to a more classic video-gamey position. I
first wanted to make the game look like a documentary using trope documentary
camera sequences (long shot with zooms, pans, and even maybe commentary on top,
in the vein of &lt;a href=&quot;https:&#x2F;&#x2F;powerhoof.itch.io&#x2F;regular-human-basketball&quot;&gt;Regular Human Basketball&lt;&#x2F;a&gt;). Maybe I’ll go back to this in the
future, but currently, the over-the-shoulder cam makes more sense, as a
gamer, it’s a bit easier to pick up.&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;movement.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;First movement design, since then, the giraffes have slowed down.&lt;&#x2F;p&gt;
&lt;p&gt;Now that the giraffes could move, I needed a way to prevent them from occupying
the same space.&lt;&#x2F;p&gt;
&lt;p&gt;I used the &lt;a href=&quot;https:&#x2F;&#x2F;rapier.rs&#x2F;docs&#x2F;user_guides&#x2F;bevy_plugin&#x2F;character_controller&#x2F;&quot;&gt;rapier character controller&lt;&#x2F;a&gt;, I had to fiddle a lot with it. I
was using a horizontally laid capsule for the giraffe body. 
This resulted in giraffes just climbing each other as soon as they touched.
This behavior is actually seen sometimes in nature when two males neck each other
(yes, in a sexual manner).
But that’s not what I want (at least yet) for my game, and anyway they don’t do
it all the time.&lt;&#x2F;p&gt;
&lt;p&gt;Also once they were not in the same plane anymore, that was it, they were either half
buried in the ground or floating in space, with no way to get back on firm
ground.&lt;&#x2F;p&gt;
&lt;p&gt;I had to adjust the giraffe collider so that they couldn’t climb each other.
I used a rounded cuboid, but it took time to get to it, more on that later.&lt;&#x2F;p&gt;
&lt;p&gt;Even with a cuboid, there is still a major problem!
The rapier character controller doesn’t
support rotation. This is fine if you are using a classic shape for controller
such as the vertical capsule; it has a circular footprint, and therefore
rotation doesn’t change the space the shape occupies. But giraffes (very much
like tanks) do have more of a rectangular footprint, hence rotation is
meaningful.&lt;&#x2F;p&gt;
&lt;p&gt;So when you rotate, it’s still fairly easy to occupy the same space as another
giraffe. I’ve not implemented anything to fix that yet though.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;overlap_skinned.jpg&quot;
  alt=&quot;Two giraffes occupying the same space&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;overlap_wireframe.jpg&quot;
  alt=&quot;Same image, but without models, it shows the physics shape used for the
  giraffes&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;tongue-controls&quot;&gt;Tongue controls&lt;&#x2F;h3&gt;
&lt;p&gt;Giraffes have funny tongues! ahahah! Of course, the natural consequence is
that the tongue &lt;strong&gt;must&lt;&#x2F;strong&gt; be a central element of gameplay. Players &lt;strong&gt;must&lt;&#x2F;strong&gt; be
able to control the tongue and do funny things with it.
Otherwise, might as well use cats with long necks instead of giraffes, come on.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Cool giraffe fact&lt;&#x2F;h4&gt;
		&lt;p&gt;(I’ve a list of 20 cool giraffe facts, might as well start dropping them now)&lt;&#x2F;p&gt;
&lt;p&gt;Giraffe tongues are about 45cm long (18 inch). It is extremely prehensile, since
it must be able to pick out acacia leaves from its surrounding thorns.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;But here is the bummer. We are now using &lt;strong&gt;rapier&lt;&#x2F;strong&gt; for joints. This allows me
to specify joints (ragdoll physics) for more than just the 7 neck vertebrae.
It looks great on the tongue, ears and ossicones (the horn-looking things).
It was very hard to specify the joint parameters so that they work well
with the model, but I already solved this last year.&lt;&#x2F;p&gt;
&lt;p&gt;But now, to move the tongue, I need to move the joint linking the tongue to the
head, change its parameters to something else. The “root” of the tongue would
move to the inside of the head and the rest of it would follow up. I needed to
find the right joint parameters to express “the inside of the head”.&lt;&#x2F;p&gt;
&lt;p&gt;As it is, I would need to change a little bit the code, compile (1s) restart
the game and look at the tongue (10s) to see the result. It simply is not
feasible in any reasonable time, and it’s extremely tedious and I care for
myself at least a bit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;component-mirror&quot;&gt;Component Mirror&lt;&#x2F;h2&gt;
&lt;p&gt;The way I adjust minor values for components in bevy, is using
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy-inspector-egui&quot;&gt;bevy-inspector-egui&lt;&#x2F;a&gt;. It allows me to modify at runtime some component values
and the copy them back into the source code. Problem: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy-inspector-egui&quot;&gt;bevy-inspector-egui&lt;&#x2F;a&gt;
requires libraries to implement bevy’s &lt;code&gt;Reflect&lt;&#x2F;code&gt; interface. Rapier joints and
collider shapes do not, and cannot implement bevy’s &lt;code&gt;Reflect&lt;&#x2F;code&gt; trait.&lt;&#x2F;p&gt;
&lt;p&gt;So I made &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bevy_mod_component_mirror&quot;&gt;bevy_mod_component_mirror&lt;&#x2F;a&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;In this crate, I define “mirrors” of the joint. They are just structures that
can be created from rapier’s joints and colliders, can be modified, implement
bevy’s &lt;code&gt;Reflect&lt;&#x2F;code&gt; trait and can update the joints and colliders with the
modified values.&lt;&#x2F;p&gt;
&lt;p&gt;As a bonus, the joints structure is much more plain and understandable than
the actual rapier joints and collider shape &lt;code&gt;struct&lt;&#x2F;code&gt;. This is because rapier’s
&lt;code&gt;struct&lt;&#x2F;code&gt; definition is informed foremost with speed in mind, at the expanse of
readability.&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;tongue.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;BLeeeehhrrrrrpppppps, boinyongyongsluuuurp, bleeeeehhhhrp, boinyongyongsluuuuuurp…&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cuicui&quot;&gt;Cuicui&lt;&#x2F;h2&gt;
&lt;p&gt;Now that the burning question of the tongue was solved, I decided to go back to
the game menu.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 680px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;necking-menu.jpg&quot;
  alt=&quot;a menu with two very large ugly checkboxes and tinny text&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The player must be able to chose how many giraffes there are, what controls to
use, if they are online, etc. Also we have a basic options menu.&lt;&#x2F;p&gt;
&lt;p&gt;I hope this doesn’t sound like a lot, because those are very limited options.
But even then, it’s impossible to accomplish using &lt;code&gt;bevy_ui&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I also wanted the text to be outlined, but again, impossible in &lt;code&gt;bevy_ui&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Placing elements in &lt;code&gt;bevy_ui&lt;&#x2F;code&gt; is also a struggle, the layout model (Flexbox)
relies a lot on implicit parameters, it’s very hard to get an idea of how
things will look when you write the code. And even using something like
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy-inspector-egui&quot;&gt;bevy-inspector-egui&lt;&#x2F;a&gt;, it is hard to understand what is going on.
bevy-inspector-egui fairs poorly with &lt;code&gt;bevy_ui&lt;&#x2F;code&gt;, because the Flexbox components
have a lot of parameters and it quickly becomes a struggle to manage them.&lt;&#x2F;p&gt;
&lt;p&gt;Well, this simply means &lt;code&gt;bevy_ui&lt;&#x2F;code&gt; is not usable for necking. At least right now.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enters Cuicui&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Cuicui is the name for the &lt;em&gt;UI framework&lt;&#x2F;em&gt; I’m developing. Over the
past 18 months, I’ve accumulated a lot of opinions on how a good bevy UI
framework would look like. And cuicui is the concretization of those opinions.&lt;&#x2F;p&gt;
&lt;p&gt;Most notably:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Prefab&lt;&#x2F;code&gt; system inspired by &lt;a href=&quot;https:&#x2F;&#x2F;gibonus.itch.io&#x2F;bone-klod&quot;&gt;Bone Klod&lt;&#x2F;a&gt;’s scene design for widgets. A recent
innovation by bevy discord user Nionidh enables &lt;em&gt;composable &lt;code&gt;Prefab&lt;&#x2F;code&gt;s&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Cuicui layout, a layout algorithm your grandma could understand (ok, depends
on your grandma) It emits a useful error when the constraints you specified are wrong,
and it is easy to gork, you’ll be able to know the final layout from
looking at source code.&lt;&#x2F;li&gt;
&lt;li&gt;Reuses bevy’s 2d Rendering. Now that bevy supports &lt;code&gt;RenderLayers&lt;&#x2F;code&gt;, there is
no reason to split UI and sprites. It also allows us to re-use pre-existing
crates. Go ahead, add particles to your UI, add dynamic 2d lights or
jump-flood outlines, or even animate it. You can do all of that in cuicui.&lt;&#x2F;li&gt;
&lt;li&gt;Give back control to users. Specifically, the &lt;code&gt;Transform&lt;&#x2F;code&gt; can be manipulated.&lt;&#x2F;li&gt;
&lt;li&gt;More than a button widgets.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cuicui-layout&quot;&gt;Cuicui layout&lt;&#x2F;h3&gt;
&lt;p&gt;Those are not empty promises, cuicui layout already exists.&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;cuicui_layout.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;Demonstration of cuicui layout.&lt;&#x2F;p&gt;
&lt;p&gt;This took a bit more than a day to get working, and half a day to write
documentation and a type-safe wrapper to construct a layout tree
(the compiler yells at you if you make an invalid layout).&lt;&#x2F;p&gt;
&lt;p&gt;The cuicui source code is available &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bevy_mod_cuicui&quot;&gt;here&lt;&#x2F;a&gt; (will be licensed under permissive
apache 2.0).&lt;&#x2F;p&gt;
&lt;p&gt;The docs explaining the layout algorithm is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bevy_mod_cuicui&#x2F;blob&#x2F;73634f91c45f91b78cad89b65d9093cc5e4dfb5b&#x2F;src&#x2F;layout&#x2F;typed.rs#L61-L133&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The plan for next week is to work up to Wednesday on Necking and start work on
a 3 weeks-and-it’s-done-I-promise game. See you next Sunday for another devlog.&lt;&#x2F;p&gt;
&lt;p&gt;(you may be interested in this blog’s &lt;a href=&quot;&#x2F;devlog&#x2F;atom.xml&quot;&gt;rss&lt;&#x2F;a&gt; feed)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Architecture of a GBA game — gssa</title>
		<published>2022-11-14T00:00:00+00:00</published>
		<updated>2022-11-14T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/gba-c-to-rust-2/" type="text/html"/>
		<id>https://devildahu.ch/devlog/gba-c-to-rust-2/</id>
		<content type="html">&lt;p&gt;This is part 2 of a series of blog posts on developing GSSA. The &lt;a href=&quot;..&#x2F;gba-c-to-rust&#x2F;&quot;&gt;first part&lt;&#x2F;a&gt; introduced why I
ended up rewriting a C game in Rust for a 20 years old console.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Acronyms and characters&lt;&#x2F;h4&gt;
		&lt;ul&gt;
&lt;li&gt;GBA: The &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Game_Boy_Advance&quot;&gt;Game Boy Advance&lt;&#x2F;a&gt; a 20 years old hand-held game console with a CPU
clock of 16MHz and 340KB of internal memory (my phone, slightly smaller than
a GBA, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Moore%27s_law&quot;&gt;has eight 2GHz CPUs (×1000) and 6GB (×17650) of internal memory&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;VRAM: Video RAM, the memory to which you must send your stuff to change pixels on the screen&lt;&#x2F;li&gt;
&lt;li&gt;UB: Undefined Behavior, things that a C compiler assumes a C programmer
will never do, that oddly every C programmer do all the time, and result
in nasty hair-tearing bugs (proven made-up fact: there is an inverse
correlation between hair line and years lived while owning &lt;em&gt;“The C Programming
Language”&lt;&#x2F;em&gt; by Kernighan and Ritchie)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mgba.io&#x2F;&quot;&gt;&lt;code&gt;mgba&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;: an accurate GBA emulator.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;gssa-rs&quot;&gt;GSSA&lt;&#x2F;a&gt;: &lt;em&gt;Generic Space Shooter Advance&lt;&#x2F;em&gt; a game for the GBA I wrote for a uni assignment
in 2018, tried to rewrite in rust in 2020, and independently rewrote a
second time in rust in 2022 (not to be confused with a Swiss pacifist NGO)&lt;&#x2F;li&gt;
&lt;li&gt;Mr. Leone: The lecturer of the systems programming lecture I followed in 2018&lt;&#x2F;li&gt;
&lt;li&gt;The little UBs: The author’s nasal demons, mostly manifested as broken games&lt;&#x2F;li&gt;
&lt;li&gt;The author: clearly someone who needs to touch grass, calls himself “cyber-hippie”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;This is where I narrate how I actually implement the menu in my first rewrite
of 2020 in rust.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;architecture&quot;&gt;Architecture&lt;&#x2F;h3&gt;
&lt;p&gt;A neophyte wrote the GSSA C code. Myself,
writing a large program, not only for the first time in C,
but for the first time in any language.&lt;&#x2F;p&gt;
&lt;p&gt;In 2020, I’m different.
I wrote &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;friendsketch&quot;&gt;a whole frontend app&lt;&#x2F;a&gt; in elm, and the corresponding backend in rust.
2020 me is also an enterprise™ developer.
I am an acolyte of data driven programming, I’ve been the midwife of many
software, seeing them from birth to their maturity.&lt;&#x2F;p&gt;
&lt;p&gt;The C version of GSSA was a struggle. How to structure code? I had never seen
game or C code before. I wrote most of the code in public transport, on a shitty
1st gen Microsoft surface, with the shitty “surface cover” finger-numbing keyboard.
I didn’t know &lt;code&gt;git&lt;&#x2F;code&gt;. I wrote regressions I took days to fix.
Remember, it took weeks to fix the code to run &lt;code&gt;mgba&lt;&#x2F;code&gt;, the accurate GBA emulator.&lt;&#x2F;p&gt;
&lt;p&gt;Dread fills me. What will I see? I’ve gazed in the abyss of legacy enterprise™
code. I’ve seen a massive visual basic app, I’ve seen a compiler written seemingly
as an exercise of how to write the most confusing chain of JavaScript callbacks,
unspeakable blasphemy, chtonic incantations that somehow a computer can parse,
let alone a human being.
Someone with less fortitude would have not survived, not with their sanity intact.
Will I gaze into my own code, and witness my own spawn as a monstrosity?&lt;&#x2F;p&gt;
&lt;p&gt;Curiously no.&lt;&#x2F;p&gt;
&lt;p&gt;There are &lt;code&gt;goto&lt;&#x2F;code&gt;s, the code may have more magic numbers and mutable globals
than local variables, I abuse criminally the C pre-processor,
and the code is indeed a barely working pile of little UBs riddled with bugs.&lt;&#x2F;p&gt;
&lt;p&gt;But I can read it. It is clean, I understand the purpose and intent of everything,
architectural design decisions are documented,
the code is structured coherently, using common patterns.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, it’s almost better than the code I write today 🥲&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;tldr&lt;&#x2F;h4&gt;
		&lt;p&gt;&lt;code&gt;bug ridden&lt;&#x2F;code&gt; does &lt;strong&gt;not&lt;&#x2F;strong&gt; imply &lt;code&gt;bad code&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore &lt;code&gt;bad code&lt;&#x2F;code&gt; does &lt;strong&gt;not&lt;&#x2F;strong&gt; imply &lt;code&gt;bug ridden&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;experience&lt;&#x2F;code&gt; does &lt;strong&gt;not&lt;&#x2F;strong&gt; imply &lt;code&gt;better code&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The design principle is clear: ownership of control flow.
I structured the GSSA code like a bunch of happy little games that wait their
turn and take the helm and drive exclusively the entirety of the console.&lt;&#x2F;p&gt;
&lt;p&gt;The main menu code looks like this:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; main.c
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(;;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;bootMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;gameState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;playGame&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;gameState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; mainmenu.c
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;bootMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;GameState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;globalState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(;;) {
&lt;&#x2F;span&gt;&lt;span&gt;        frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= (&lt;&#x2F;span&gt;&lt;span&gt;frameCount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) % (&lt;&#x2F;span&gt;&lt;span&gt;BLANK_SEC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; BLANK_SEC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;     &amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; BOOT_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;Press Start&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; BOOT_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;CHECK_INPUT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;KEY_START&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)) {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;srand&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;frameCount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; gameMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        WAIT_BLANK&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;gameMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;TST_FG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;curKeys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;KEY_A&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)) { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;Changes submenu.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot; &amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;switch &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;Exits the game menu loop
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; BEGIN_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;goes to game
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; SHIP_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; shipMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; CHEAT_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; cheatMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;shipMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;cheatMenu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;bootMenu()&lt;&#x2F;code&gt; handles the initial screens,
including ship selection, difficulty selection, cheat code menu, and the title card.
Each one of those represent a different screen.
Each screen has a corresponding loop, when the user changes screen,
a &lt;code&gt;goto&lt;&#x2F;code&gt; goes to the selected screen’s loop.&lt;&#x2F;p&gt;
&lt;p&gt;Without &lt;code&gt;goto&lt;&#x2F;code&gt;, we bloat the stack,
we enter a new context whenever we enter or exit a menu,
potentially leading to a stack overflow on the poor GBA’s tinny memory.
This implies giving up the concept of functions, but it works.&lt;&#x2F;p&gt;
&lt;p&gt;The C GSSA uses liberally mutable global variables.
I pick arbitrary location in memory and split them
between all the happy little games:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;OAMCLONE_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;03004000
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;oamClone &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;((&lt;&#x2F;span&gt;&lt;span&gt;spriteTag&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;*)&lt;&#x2F;span&gt;&lt;span&gt; OAMCLONE_MEM&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ... in another c header
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; a single value of size sizeof(PlayerShip)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;PSHIP_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;OAMCLONE_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ sizeof(&lt;&#x2F;span&gt;&lt;span&gt;spriteTag&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; An array of size MAX_BULLET * sizeof(ActiveBullet)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;ACTIVBULLET_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;PSHIP_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ sizeof(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) *&lt;&#x2F;span&gt;&lt;span&gt; MAX_BULLET &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; An array of size MAX_ENNEMY * sizeof(ActiveEnnemy)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;ACTIVENNEMY_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;ACTIVBULLET_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ sizeof(&lt;&#x2F;span&gt;&lt;span&gt;ActiveBullet&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) *&lt;&#x2F;span&gt;&lt;span&gt; MAX_BULLET&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; An array of size MAX_PICKUP * sizeof(ActivePickup)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;ACTIVPICKUP_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;ACTIVENNEMY_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ sizeof(&lt;&#x2F;span&gt;&lt;span&gt;ActiveEnnemy&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) *&lt;&#x2F;span&gt;&lt;span&gt; MAX_ENNEMY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; In main.c
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GAMESTATE_MEM &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;03003F00
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    GameState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; gameState &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= (&lt;&#x2F;span&gt;&lt;span&gt;GameState&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;*)&lt;&#x2F;span&gt;&lt;span&gt; GAMESTATE_MEM&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’m sure a few readers ground their teeth to dust seeing this code.
But on the GBA it is fine. Remember? No OS, just GSSA running on the hardware.
Only risk is for the stack to grow so much they overwrite the hardcoded memory.
(Though apparently I was an “ennemy” of spelling when I wrote this)&lt;&#x2F;p&gt;
&lt;p&gt;This is what I learned from Mr Leone’s lecture:
some memory regions are faster to read&#x2F;write than others,
so make sure to use the fast ones for critical data structures.&lt;&#x2F;p&gt;
&lt;p&gt;So how will I write the rust version?&lt;&#x2F;p&gt;
&lt;p&gt;No such code in my rewrite.
I’ll leave it to the compiler to do the hard work of picking
where to place my beloved data structures.
(In any case, I will specify the stack memory position in the &lt;code&gt;linker.ld&lt;&#x2F;code&gt; file,
this tells the linker which addresses to use for what purpose)&lt;&#x2F;p&gt;
&lt;p&gt;The acolyte of &lt;em&gt;data-driven programming&lt;&#x2F;em&gt; (DDP) than I am now has lost the ability
to reason in terms of control flow.&lt;&#x2F;p&gt;
&lt;p&gt;DDP is all about data structures.
I first define the game state, and design code as transformations on the state.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;GameState&lt;&#x2F;code&gt; is now an enum,
each variant relevant to a different point in the game.
Each variant its own little state,
all describing what to draw on screen
and what the next state is based on button input.&lt;&#x2F;p&gt;
&lt;p&gt;There is a single loop,
that looks at the state and call its corresponding &lt;code&gt;draw&lt;&#x2F;code&gt; and &lt;code&gt;update&lt;&#x2F;code&gt; methods.&lt;&#x2F;p&gt;
&lt;p&gt;I need to split &lt;code&gt;draw&lt;&#x2F;code&gt; and &lt;code&gt;update&lt;&#x2F;code&gt; on the GBA,
changing VRAM memory at a narrow specific interval,
otherwise, I’ll see ugly screen tearing.&lt;&#x2F;p&gt;
&lt;p&gt;This is the elm architecture.
The &lt;a href=&quot;https:&#x2F;&#x2F;rationalwiki.org&#x2F;wiki&#x2F;Cargo_cult&quot;&gt;discarded cargo&lt;&#x2F;a&gt;, filled with bobbles of another kind of civilisation,
that I picked up at university
and to this day still praise as gospel of clean code.
Regardless, I have other better reasons to idolize &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch01-03-hello-cargo.html&quot;&gt;&lt;code&gt;cargo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (my savior).&lt;&#x2F;p&gt;
&lt;p&gt;In fact, there is a bit more to that.
I can split the &lt;code&gt;GameState&lt;&#x2F;code&gt; in two:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Mutable data changing with the game progression&lt;&#x2F;li&gt;
&lt;li&gt;Purely descriptive constant data (text positions in menus, menu text, player speed, etc.)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Constants will replace all the magic values.
This is more code, but I don’t have to uncover what &lt;code&gt;5&lt;&#x2F;code&gt; or &lt;code&gt;10&lt;&#x2F;code&gt; means.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 550px));&quot;&gt;
		&lt;img src=&quot;main_menu.webp&quot; alt=&quot;GSSA&#x27;s main menu&quot; style=&quot;image-rendering:pixelated&quot;&#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;MAIN_MENU&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;Menu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;gt; =&lt;&#x2F;span&gt;&lt;span&gt; Menu &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    entries&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;BEGIN GAME !!!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;Ship select&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;Code zone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;],
&lt;&#x2F;span&gt;&lt;span&gt;    pos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    dir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;MenuDir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Verti&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A &lt;code&gt;Menu&lt;&#x2F;code&gt; tells me how to draw
something based on the global &lt;code&gt;GameState&lt;&#x2F;code&gt;. Each struct has a &lt;code&gt;draw&lt;&#x2F;code&gt; method that
takes as argument everything that is mutable  and it needs to know. In the
case of &lt;code&gt;Menu&lt;&#x2F;code&gt; the signature of &lt;code&gt;draw&lt;&#x2F;code&gt; is as follow:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;selected&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Sbb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(where &lt;code&gt;tile_map&lt;&#x2F;code&gt; is going to be a point to the location in memory we need to
write to to display things, it has nothing to do with the Schweizerische
Bundesbahnen) &lt;&#x2F;p&gt;
&lt;p&gt;This architecture greatly reduces the size of what is going to be passed
around in drawing and updating routines (the state), which is necessary for
performance reasons. One positive side effect of this is that the menus are
entirely declaratively defined.&lt;&#x2F;p&gt;
&lt;p&gt;The corresponding C code fails to decouple drawing from updating, but on the
flip side, is dead easy to understand:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;BEGIN GAME !!!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;  BEGIN_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;Ship Select&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;     SHIP_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;  MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;Code zone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;       CHEAT_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yes, you’ll find magic numbers all around the code, this is quite ugly, but
not a difficulty to code comprehension.&lt;&#x2F;p&gt;
&lt;p&gt;There is more to it though. The blinking cursor. The damn blinking cursor.
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Microsoft&#x2F;vscode&#x2F;issues&#x2F;22900&quot;&gt;You think it’s easy?&lt;&#x2F;a&gt;
My &lt;code&gt;draw&lt;&#x2F;code&gt; method only has access to the current state,
but I need to erase the cursor at the previous position.&lt;&#x2F;p&gt;
&lt;p&gt;The cursor is not in the struct definition of &lt;code&gt;Menu&lt;&#x2F;code&gt;, it can’t since the
cursor position changes and &lt;code&gt;Menu&lt;&#x2F;code&gt; is immutable. The cursor must be part of the
&lt;code&gt;GameState&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;With the C model, the menu has an internal state updated
every frames, and draws based on that state in the same loop:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= (&lt;&#x2F;span&gt;&lt;span&gt;frameCount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) %&lt;&#x2F;span&gt;&lt;span&gt; BLANK_SEC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;||&lt;&#x2F;span&gt;&lt;span&gt; frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;4800&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; curPos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;2400 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;||&lt;&#x2F;span&gt;&lt;span&gt; frameCount &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;7200&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot; &amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; curPos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This snippet is repeated in every submenu loops.&lt;&#x2F;p&gt;
&lt;p&gt;With the rust model, the cursor is represented as a text box:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cursor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;pos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)) -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; TextBox &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    TextBox &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;text&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span&gt;pos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;blink_rate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fac863;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;30&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the update:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;update&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;cycle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;selected&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;Diff&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Sbb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; selected&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;changed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cursor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cursor_pos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;selected&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;prev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cursor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cursor_pos&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;selected&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;current&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;update&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;cycle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;More precisely, the blinking happens in the &lt;code&gt;TextBox::update&lt;&#x2F;code&gt; method:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;update&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;cycle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Sbb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fac863;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;blink_rate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;blink_rate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tick &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; cycle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;%&lt;&#x2F;span&gt;&lt;span&gt; blink_rate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; tick &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt; tick &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; blink_rate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;tile_map&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s a bit more verbose.&lt;&#x2F;p&gt;
&lt;p&gt;Note the &lt;code&gt;Diff&lt;&#x2F;code&gt; for the &lt;code&gt;selected&lt;&#x2F;code&gt; entry. I need to know the previous
state to clear the cursor if it changed position. I can do that, because
&lt;code&gt;update&lt;&#x2F;code&gt; is not &lt;em&gt;updating&lt;&#x2F;em&gt; &lt;code&gt;self&lt;&#x2F;code&gt; (notice the &lt;code&gt;&amp;amp;self&lt;&#x2F;code&gt;, non-mutable!) it is
creating a new &lt;code&gt;self&lt;&#x2F;code&gt;, this way, the old &lt;code&gt;self&lt;&#x2F;code&gt; is kept around, and can be used
later to compare new and old value, and execute code when relevant.&lt;&#x2F;p&gt;
&lt;p&gt;This doubles memory requirement, but for simple menus, this works great and the
memory footprint is tinny enough to not be a worry.&lt;&#x2F;p&gt;
&lt;p&gt;The C code has the following snippet wherever it needs to change the cursor
position:&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;TST_FG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;curKeys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; KEY_UP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot; &amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= (&lt;&#x2F;span&gt;&lt;span&gt;currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; FIRST_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)?&lt;&#x2F;span&gt;&lt;span&gt; LAST_ROW &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:    (&lt;&#x2F;span&gt;&lt;span&gt;currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;TST_FG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;curKeys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; KEY_DOWN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot; &amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= (&lt;&#x2F;span&gt;&lt;span&gt;currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; LAST_ROW&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;)?&lt;&#x2F;span&gt;&lt;span&gt; FIRST_ROW &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:    (&lt;&#x2F;span&gt;&lt;span&gt;currentRow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;drawText&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; currentRow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt; MAIN_SBB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This demonstrates also the unabashed mixing between state change and drawing in the C version.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;let-s-try-this-again&quot;&gt;Let’s try this again&lt;&#x2F;h2&gt;
&lt;p&gt;Forget everything you just read. Or rather, let me forget that I ever wrote
that. The year is now 2022, no hoverboards, just even dimmer hopes, and me,
a bored dude, alone with his computer. And I do what most lone bored dude with
computers do: rewrite a C GBA game in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;This time I take a different approach. My first action is to &lt;strong&gt;split hardware
access and game code&lt;&#x2F;strong&gt;, this is called a &lt;strong&gt;HAL&lt;&#x2F;strong&gt; (hardware abstraction layer).
I call it &lt;code&gt;haldvance&lt;&#x2F;code&gt;, because I am a victim of puns.&lt;&#x2F;p&gt;
&lt;p&gt;The second decision I make, is to use a MVC approach. I first design the data,
and then, I… I mean I just spent a thousand words telling you about that, but
for me this was a new and innovative solution.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;architecture-bis&quot;&gt;Architecture bis&lt;&#x2F;h3&gt;
&lt;p&gt;Oh, but in the mean time, I forgot about all this fancy “diffing” I nicely
described earlier. My &lt;code&gt;update&lt;&#x2F;code&gt; methods take a &lt;code&gt;&amp;amp;mut self&lt;&#x2F;code&gt;, and the previous
state is not kept track of.&lt;&#x2F;p&gt;
&lt;p&gt;The split between &lt;code&gt;draw&lt;&#x2F;code&gt; and &lt;code&gt;update&lt;&#x2F;code&gt; has become my nemesis. Why?
When I change from one state to another, this typically requires “exceptional”
&lt;code&gt;draw&lt;&#x2F;code&gt; operations. For example, when starting the game, I change the video
mode, generate a star map and load the game’s sprites into video memory. But
here is the question: How do I know that I “just entered” the game
state? I only have the current state, outside of any context of changes.&lt;&#x2F;p&gt;
&lt;p&gt;Oh I see several solutions to this, but I made the mistake of trying to solve
it before thinking about it. Here are the possibilities:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Callbacks. Create an API where you can return optionally a callback to run in
the &lt;code&gt;draw&lt;&#x2F;code&gt; interval&lt;&#x2F;li&gt;
&lt;li&gt;Diff again.&lt;&#x2F;li&gt;
&lt;li&gt;A generic state machine, where I can query whether state was
updated&#x2F;entered&#x2F;left.&lt;&#x2F;li&gt;
&lt;li&gt;Just keep a struct with a bunch of flags and check them every time&lt;&#x2F;li&gt;
&lt;li&gt;Build a more principled version of the naive “ownership of loops” design I
used in the C GSSA&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I initially went with callbacks. My game currently uses this design. It
probably kills perfs by preventing potential inlining. But more than that, it
only partially solves the issue, because now I have to surface callbacks from
inner functions, handle conflicts of callbacks… Fun in perspective.&lt;&#x2F;p&gt;
&lt;p&gt;Disaster, my prophetic faith in DDP is shook. Maybe I should take another
approach? This is a question for another time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hal-elujah&quot;&gt;HAL (elujah)&lt;&#x2F;h3&gt;
&lt;p&gt;Now let’s talk about the HAL.&lt;&#x2F;p&gt;
&lt;p&gt;Generally, designing and writing a completely generic, fully documented,
opinionated and flexible library API takes much more time than going at the
hardware with a raw hammer and accepting your hardware access bugs will surface
all around your game logic.&lt;&#x2F;p&gt;
&lt;p&gt;For reference, currently the HAL is 2K lines of code with over 800 lines of
documentation, while the game itself is about 1K lines of code (suspicious,
he doesn’t say how much doc the game has).&lt;&#x2F;p&gt;
&lt;p&gt;And development is sluggish: every time I add a functionality, I have to first
design an API for it, and wrap the hardware, thinking about the cheapest
way of doing it, thinking of edge cases, explore rust features
allowing them, and all of that is before I even get started writing game code,
which itself is a slog, because this 2nd rust rewrite started with a crippling
architectural decision.&lt;&#x2F;p&gt;
&lt;p&gt;Ah! But at least the separation between gameplay and hardware code did help me
understand in isolation why certain things do not work. It’s also so much
easier to read, and as I write the HAL, I’m writing an exhaustive manual on
how to write GBA games in Rust, with directions in the more hairy parts of the
API.&lt;&#x2F;p&gt;
&lt;p&gt;The HAL is great, but I worry it’s a massive waste of time, we are talking
about an abstraction layer for a 20 years old console. And why? Just because.
A weird obsession.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;and-more&quot;&gt;And more&lt;&#x2F;h3&gt;
&lt;p&gt;Now my second rewrite reached feature parity with the first one. Ah,
accidentally. It is time to start making strides toward feature parity with
&lt;strong&gt;The C Version&lt;&#x2F;strong&gt;. Fun in perspective, to the next post!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Rewriting a GBA game in Rust — gssa</title>
		<published>2022-11-07T00:00:00+00:00</published>
		<updated>2022-11-07T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/gba-c-to-rust/" type="text/html"/>
		<id>https://devildahu.ch/devlog/gba-c-to-rust/</id>
		<content type="html">&lt;p&gt;I’m Nicola, I’ll discuss how I converted a C game written as a student
assignment into Rust, and tell you about all the friends (later
referred as “little UBs”) I made along the way.&lt;&#x2F;p&gt;
&lt;p&gt;The year is 2018, as assignment in professor Leone’s systems programming class,
I write a game for the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Game_Boy_Advance&quot;&gt;Game Boy Advance&lt;&#x2F;a&gt; (GBA), a console released in 2001,
without any operating system, a blazing fast CPU of 16.8 MHz,
a mind-bending 256Kb of RAM (it ought to be enough for everyone) and a
fantastical memory-mapped (mmio) interface to program graphics, audio,
basically everything the GBA can do.&lt;&#x2F;p&gt;
&lt;p&gt;In short, the perfect device to teach bare-metal programming.&lt;&#x2F;p&gt;
&lt;p&gt;In the year 2018, I write my first significant C program.
A game for the GBA, I called it “Generic Space Shooter Advance” (GSSA).
A stinky pile of undefined behavior (UB). UB is what you get when you write
C code the C compiler can assume could never possibly exist
(about one out of every three lines of C ever written).
It is such a stinky pile, in fact, that for a while,
it only worked on inaccurate GBA emulators,
until I spent about 2 weeks to suss out
where I was accessing invalid memory addresses (hint: in way too many places).&lt;&#x2F;p&gt;
&lt;p&gt;After those two weeks, I could finally play GSSA on &lt;code&gt;mgba&lt;&#x2F;code&gt; (an accurate GBA emulator).
Yet, when I opened the live memory view of &lt;code&gt;mgba&lt;&#x2F;code&gt;,
I could see random bits in memory being swapped for no apparent reasons,
but since it didn’t touch the bits of memory containing my game data or the mmio
registers, my game worked (kinda).&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;gssa.gif&quot; style=&quot;image-rendering:pixelated&quot;
  alt=&quot;Gameplay of GSSA, navigating menu, moving player shooting bullets that can be upgraded, crashing at times, with visible screen tearing&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The development of the game was over.&lt;&#x2F;p&gt;
&lt;p&gt;A shame we never learned about UB at uni (sorry Mr Leone).&lt;&#x2F;p&gt;
&lt;p&gt;The year is 2020, one year in my first job as scala developer, trying to fight
the existential dread of spending most of my waking hours helping make the world
a worse place, working on a depressingly slow virtualized dev machine,
where every key presses is followed by a 500ms coffee break before even altering
anything on screen. I now know elm, Haskell, scala and rust.
I’ve read “Expert C programming” twice, I now can see some of the previously
invisible UBs that plagued my game, all the little UBs, here in front of me,
sneering, provoking, spitting me, telling me “You’ll never catch us!”&lt;&#x2F;p&gt;
&lt;p&gt;I hate it, I despise them.&lt;&#x2F;p&gt;
&lt;p&gt;I learn about &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-console&#x2F;gba&quot;&gt;the gba crate&lt;&#x2F;a&gt;. Finally, an escape hatch.
A way to live in the impossible world I always wanted to live,
the world where I make the best selling GBA game,
without constantly fighting the little UBs of the C tribe.&lt;&#x2F;p&gt;
&lt;p&gt;A way to escape the morose every day life of an investment bank developer,
I can enter again a world without allocations, without an unknowable Garbage Collector
that somehow makes all my program eat about 500MB of RAM at minimum
(not a problem, just spin up a new prod server, say my colleagues).&lt;&#x2F;p&gt;
&lt;p&gt;I feel like playing &lt;a href=&quot;https:&#x2F;&#x2F;store.steampowered.com&#x2F;app&#x2F;370360&#x2F;TIS100&quot;&gt;TIS-100&lt;&#x2F;a&gt; again, but this time I can write it on my resume.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s port GSSA to Rust, call it gssa-rs,
free it from the tyranny of the little UBs, and brag about it on the internet.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;Look at that, look at those setup instructions, so terse, so simple.&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;rustup install nightly
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;rustup +nightly component add rust-src
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;sudo apt-get install binutils-arm-none-eabi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;# copy an example from the github.com&#x2F;rust-console&#x2F;gba repository
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;# Add gba as a dependency to the Cargo.toml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cargo run
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It works! Just like that, I even get full code completion and a working
package manager, &lt;code&gt;cargo&lt;&#x2F;code&gt; my love, my savior.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;The sbt exorcism&lt;&#x2F;h4&gt;
		&lt;p&gt;Begone &lt;a href=&quot;https:&#x2F;&#x2F;docs.scala-lang.org&#x2F;overviews&#x2F;scala-book&#x2F;scala-build-tool-sbt.html&quot;&gt;&lt;code&gt;sbt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, my calvary, my daily ordeal for the sins of scala.&lt;&#x2F;p&gt;
&lt;p&gt;Begone the 10 seconds startup time, the excruciating compilation times.&lt;&#x2F;p&gt;
&lt;p&gt;Begone &lt;code&gt;sbt&lt;&#x2F;code&gt;’s cryptic configuration, each dependency an additional shibboleth,
each compilation target an incantation, each error message a gnomic curse.&lt;&#x2F;p&gt;
&lt;p&gt;Begone &lt;code&gt;sbt&lt;&#x2F;code&gt;, the oxymoronically named build tool.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;Oh what is this, a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-console&#x2F;gba&#x2F;issues&#x2F;92&quot;&gt;compilation error&lt;&#x2F;a&gt; in my rust dependency?
Hmm, a change to the rust &lt;code&gt;asm!&lt;&#x2F;code&gt; macro.
This, the &lt;code&gt;swi&lt;&#x2F;code&gt; instruction, I did learn in Mr Leone’s lecture.
A requirement to summon the GBA’s BIOS functions.&lt;&#x2F;p&gt;
&lt;p&gt;Despite my unreasonably zealous belief, rust still manages to amaze me:
Now, even &lt;a href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;inside-rust&#x2F;2020&#x2F;06&#x2F;08&#x2F;new-inline-asm.html&quot;&gt;writing inline assembly is safe(ish)&lt;&#x2F;a&gt;.
A &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-console&#x2F;gba&#x2F;pull&#x2F;93&quot;&gt;quick fix&lt;&#x2F;a&gt;, a quick merge.&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;     asm!(&#x2F;* ASM *&#x2F; &amp;quot;swi 0x06&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;         :&#x2F;* OUT *&#x2F; &amp;quot;={r0}&amp;quot;(div_out), &amp;quot;={r1}&amp;quot;(rem_out)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;         :&#x2F;* INP *&#x2F; &amp;quot;{r0}&amp;quot;(numerator), &amp;quot;{r1}&amp;quot;(denominator)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;         :&#x2F;* CLO *&#x2F; &amp;quot;r3&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;         :&#x2F;* OPT *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;     asm!(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;         &amp;quot;swi 0x06&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;         inout(&amp;quot;r0&amp;quot;) numerator =&amp;gt; div_out,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;         inout(&amp;quot;r1&amp;quot;) denominator =&amp;gt; rem_out,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;         out(&amp;quot;r3&amp;quot;) _,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;         options(nostack, nomem),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#99c794;&quot;&gt;     );
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;making-the-game&quot;&gt;Making the game&lt;&#x2F;h2&gt;
&lt;p&gt;Now is the time, little UBs. Watch out. Your time is up, time to demolish
your house of card, and each little nook of my C code you hide yourselves in.&lt;&#x2F;p&gt;
&lt;p&gt;Time to rebuild GSSA on sounder foundations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sprites-and-color-palettes&quot;&gt;Sprites and color palettes&lt;&#x2F;h3&gt;
&lt;p&gt;I have sprites, the GBA video processor needs those sprites in video memory (VRAM).
I need the sprites to be in the game ROM.&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;img src=&quot;menu_tileset.png&quot; alt=&quot;GSSA&#x27;s main menu tiles&quot; style=&quot;image-rendering:pixelated&quot;&#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;In C, using DevkitPro, it’s easy.
Add the binary to a &lt;code&gt;resource&lt;&#x2F;code&gt; directory,
then add &lt;code&gt;resource&lt;&#x2F;code&gt; to Devkit’s &lt;a href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;nicopap&#x2F;gssa&#x2F;-&#x2F;blob&#x2F;master&#x2F;Makefile&quot;&gt;&lt;code&gt;Makefile&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;’s &lt;code&gt;DATA&lt;&#x2F;code&gt; list.
You then can &lt;code&gt;#include &amp;quot;menuset_til_bin.h&amp;quot;&lt;&#x2F;code&gt; in the C’s header file
(this is fine 🥲).&lt;&#x2F;p&gt;
&lt;p&gt;How to do this in Rust? Looks like &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;macro.include_bytes.html&quot;&gt;&lt;code&gt;include_bytes!&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; it is.
So let’s replace those &lt;code&gt;_bin&lt;&#x2F;code&gt;s with &lt;code&gt;include_bytes!&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width monospaced&quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre style=&quot;background-color:#2b2c2f;color:#cccece;&quot;&gt;&lt;code&gt;&lt;span&gt;error[E0080]: it is undefined behavior to use this value
&lt;&#x2F;span&gt;&lt;span&gt;   --&amp;gt; src&#x2F;assets.rs:138:5
&lt;&#x2F;span&gt;&lt;span&gt;    |
&lt;&#x2F;span&gt;&lt;span&gt;138 |     pub(crate) const menuset_til: &amp;amp;[Color; 12288] = unsafe {
&lt;&#x2F;span&gt;&lt;span&gt;139 |         transmute(include_bytes!(&amp;quot;..&#x2F;resources&#x2F;menuset_til.bin&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.data.data:
&lt;&#x2F;span&gt;&lt;span&gt;    | encountered an unaligned reference (required 2 byte alignment but found 1)
&lt;&#x2F;span&gt;&lt;span&gt;    |
&lt;&#x2F;span&gt;&lt;span&gt;    = note: The rules on what exactly is undefined behavior aren&amp;#39;t clear, so this check might be
&lt;&#x2F;span&gt;&lt;span&gt;      overzealous. Please open an issue on the rustc repository if you believe it should not be
&lt;&#x2F;span&gt;&lt;span&gt;      considered undefined behavior.
&lt;&#x2F;span&gt;&lt;span&gt;    = note: the raw bytes of the constant (size: 64, align: 4) {
&lt;&#x2F;span&gt;&lt;span&gt;                0x00 │ ╾─alloc26─╼ 06 00 00 00 ╾alloc381─╼ 00 00 00 00 │ ╾──╼....╾──╼....
&lt;&#x2F;span&gt;&lt;span&gt;                0x10 │ ╾─alloc27─╼ 06 00 00 00 ╾alloc390─╼ 00 00 00 00 │ ╾──╼....╾──╼....
&lt;&#x2F;span&gt;&lt;span&gt;                0x20 │ ╾─alloc28─╼ 06 00 00 00 ╾alloc399─╼ 00 00 00 00 │ ╾──╼....╾──╼....
&lt;&#x2F;span&gt;&lt;span&gt;                0x30 │ ╾─alloc29─╼ 06 00 00 00 ╾alloc408─╼ 00 00 00 00 │ ╾──╼....╾──╼....
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;ROGNTU&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Gaston_%28comics%29#The_office_co-workers&quot;&gt;DJU&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What even is this? Why is rust showing me circuit diagrams with random numbers now?&lt;&#x2F;p&gt;
&lt;p&gt;Ok, let’s just store the sprites in an array of bytes (&lt;code&gt;&amp;amp;[u8]&lt;&#x2F;code&gt;)
instead of an array of &lt;code&gt;Color&lt;&#x2F;code&gt;s, aka “shorts,” or &lt;code&gt;u16&lt;&#x2F;code&gt; (&lt;code&gt;&amp;amp;[Color]&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;broken_mainmenu.png&quot; style=&quot;image-rendering:pixelated&quot;
  alt=&quot;A title card screen, but with one column of pixel out of two missing&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Honestly&lt;&#x2F;h4&gt;
		&lt;p&gt;To get the previous screenshot, I reverted to the version of the game
and compiler used before fixing this bug.&lt;&#x2F;p&gt;
&lt;p&gt;But I never managed to reproduce the bug. The screenshot is actually an artist
interpretation, edited from the “working” version.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;Now my menu is broken! I’ve seen this in the C version.
It was easy to solve, just move around some unrelated variables and it works again!&lt;&#x2F;p&gt;
&lt;p&gt;No such luck with rust, let’s take closer attention to rust’s error message:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;error[E0080]: it is &lt;strong&gt;undefined behavior&lt;&#x2F;strong&gt; to use this value&lt;&#x2F;p&gt;
&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;p&gt;constructing invalid value at .0.data.data: encountered an &lt;strong&gt;unaligned
reference&lt;&#x2F;strong&gt; (required 2 byte alignment but found 1)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It’s an UB! Rustc ruthlessly (rustlessly huehue) seizes the little UB jerk,
and slay it without giving it the opportunity to make your life a misery
(that is, until you work around it without paying attention).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;unaligned reference&lt;&#x2F;strong&gt;. Yes, this we learned about in Mr Leone’s lectures.&lt;&#x2F;p&gt;
&lt;p&gt;Alignment, this is important for the GBA processor, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ARM7#ARM7TDMI&quot;&gt;ARM7TDMI&lt;&#x2F;a&gt;.
To write data to VRAM, you &lt;strong&gt;must&lt;&#x2F;strong&gt; only use 2 byte length store instructions.
1 byte length stores will still write 2 bytes,
storing one and an undefined value in the other (normally, it should be the same
value repeated twice, but for some reasons I ended up with one out of two values
zeroed out).&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;macro.include_bytes.html&quot;&gt;workaround&lt;&#x2F;a&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;gssa-rs&#x2F;blob&#x2F;ebbbf248ebd669a7ffd00f5fd9a22d899c565c31&#x2F;include_const_aligned&#x2F;src&#x2F;lib.rs&quot;&gt;a bit involved&lt;&#x2F;a&gt;, but here it is, UB-free title screen!&lt;&#x2F;p&gt;
&lt;div class=&quot;limit_element_width&quot; style=&quot;width:calc(min(100%, 480px));&quot;&gt;
		&lt;p&gt;&lt;img
  src=&quot;fixed_mainmenu.png&quot; style=&quot;image-rendering:pixelated&quot;
  alt=&quot;The same screen as shown before, but beautiful in its fullness, without any missing columns&quot;
&#x2F;&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;To be perfectly fair, I did solve it more correctly in the C version,
using the GBA &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Direct_memory_access&quot;&gt;DMA&lt;&#x2F;a&gt; for writing to VRAM.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;No nonsense tl;dr&lt;&#x2F;h4&gt;
		&lt;p&gt;Even knowing about alignment didn’t stop me from ignoring it when storing to
memory in C.&lt;&#x2F;p&gt;
&lt;p&gt;Compiler errors help catch, &lt;em&gt;and understand&lt;&#x2F;em&gt; bugs before they even exist.
Rust’s high quality error messages help understand what caused the error
and actually put in practice your knowledge to write correct code.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h2 id=&quot;history-repeats-itself&quot;&gt;History repeats itself&lt;&#x2F;h2&gt;
&lt;p&gt;The year is now 2022.&lt;&#x2F;p&gt;
&lt;p&gt;I vanquished my dread, I now left my salaried job and I spend the day contributing
to an open source game engine. I’ve become a cyber-hippie. &lt;strong&gt;Kumbaya!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Two weeks away from keyboard. I pick up my unworn laptop.
I bore myself quickly from the lacking literature I picked up departing.
I find an old abandoned project, gssa-rs.
Very rustic, it compiles, I can run it on &lt;code&gt;mgba&lt;&#x2F;code&gt;,
but it is nothing more than the title screen.
Ah! Time to hone my skill on embedded rust and finally complete this dream of mine.
I’m free now, I can do it.
I go all in, writing a full hardware abstraction layer (HAL),
pick apart GBA documentations, and in the last 12 hours,
get around to implement menus beyond the title screen.&lt;&#x2F;p&gt;
&lt;p&gt;Back from the trip, I discover on my desktop PC a major uncommitted set of changes
on the local copy of the gssa-rs repository.
The five days of intensive programming I did in vacation were the programmer’s
first sin: “Duplicated effort.”
Perusing the code, I find eerily familiar 2 years old solutions
to problems I had just two days ago.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t remember any of this. Oh, what is this entry in my notebook?
A 300 lines document describing my experience converting GSSA to rust,
dated September 2020.
In fact, it is this very article (before editing).&lt;&#x2F;p&gt;
&lt;p&gt;Amazing! Sure, a sin, but an opportunity as well.
I get a peek at how I would solve the exact same problem at a 2 year interval.
Did my experience since then changed the way write code?
Do I write better code, worse code?&lt;&#x2F;p&gt;
&lt;p&gt;What I think of my 2020 code, I’ll leave for a later post.&lt;&#x2F;p&gt;
&lt;p&gt;(you may be interested in this blog’s &lt;a href=&quot;&#x2F;devlog&#x2F;atom.xml&quot;&gt;rss&lt;&#x2F;a&gt; feed)&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Teaser&lt;&#x2F;h4&gt;
		&lt;blockquote&gt;
&lt;p&gt;Dread fills me. What will I see? I’ve gazed in the abyss of legacy entreprise™
code. I’ve seen a massive visual basic app, I’ve seen a compiler written seemingly
as an exercise of how to write the most confusing chain of Javascript callbacks,
unspeakable blasphemy, chtonic incantations that somehow a computer can parse,
let alone a human being.
Someone with less fortitude would have not survived, not with their sanity intact.
Will I gaze into my own code, and witness my own spawn as a monstruosity?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;

&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Video game essence</title>
		<published>2022-09-27T00:00:00+00:00</published>
		<updated>2022-09-27T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/game-essence/" type="text/html"/>
		<id>https://devildahu.ch/devlog/game-essence/</id>
		<content type="html">&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;disclaimer&lt;&#x2F;h4&gt;
		&lt;p&gt;Devil Dahu or Nicola (the author) has no affiliation what-so-ever with
Sakurai, Nintendo, HAL or anyone.&lt;&#x2F;p&gt;
&lt;p&gt;This blog is usually technical, this post is very handwavy and abstract,
but it touches to the soul of games and I wanted to share it.&lt;&#x2F;p&gt;
&lt;p&gt;(tldr at the end)&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;I’ve a feel for games. A deep belief, I need to share it.&lt;&#x2F;p&gt;
&lt;p&gt;Well, more specifically,
it is &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Masahiro_Sakurai&quot;&gt;Masahiro Sakurai&lt;&#x2F;a&gt;’s video on &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=BFGkFHb2lBw&quot;&gt;game essence&lt;&#x2F;a&gt; that prompted me.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t agree with Sakurai on what Game Essence is.&lt;&#x2F;p&gt;
&lt;p&gt;This is mostly a play on word and a way of looking at games,
so it’s not of much practical applications,
pretty much only good for occupying disk space and inking paper.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, close this browser tab if you don’t want it to also occupy
your precious limited time on earth, because I’m going deep.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-game-essence&quot;&gt;What is Game Essence?&lt;&#x2F;h2&gt;
&lt;p&gt;To Sakurai, Game Essence,
far from being a brand of perfume smelling of cheap alcohol and sweat,
is an extension of the “Risk&#x2F;Reward” equation.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is the Risk&#x2F;Reward equation?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Risk&#x2F;Reward is a classic video game design idea.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll defer to Sakurai on this one, see &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=FXqEykD5Ub4&quot;&gt;his video&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see this model applied to existing video games:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Super Mario Bros&lt;&#x2F;em&gt;: To defeat enemy and progress (reward) you need to get
closer to enemies.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Space Invader&lt;&#x2F;em&gt;: Same really, but on the Y axis.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Sekiro&lt;&#x2F;em&gt;: sic.&lt;&#x2F;li&gt;
&lt;li&gt;RPGs of all sort: When dungeon-crawling, you need to go deeper to get more loot,
but you risk defeat by encountering unexpected enemies.
(Darkest Dungeon is the ultimate incarnation of that)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But Risk&#x2F;Reward is clearly absent from a lot of great games.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Baba is You&lt;&#x2F;em&gt;: Where is the risk, what is the reward? More puzzles,
the completely inexistent story and lore?
(same applies to &lt;em&gt;The Witness&lt;&#x2F;em&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Return of The Obra Dinn&lt;&#x2F;em&gt;: There is simply no risk involved,
guessing incorrectly does nothing,
guessing correctly is just the opportunity to focus on another
murder mystery to solve.
Story is more than contingent to gameplay.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sakurai &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=TYh5SJb5gWk&quot;&gt;says this&lt;&#x2F;a&gt;:
What is important is the balance of tension an relief.
In a puzzle game, the tension is the closed door,
the unsolved puzzle gating further progress.&lt;&#x2F;p&gt;
&lt;p&gt;The player gets relief by solving the puzzle,
which the puzzle game generally rewards with… more puzzles.&lt;&#x2F;p&gt;
&lt;p&gt;The Essence of a game is then
how the game decides to present that Risk&#x2F;Reward equation to the player.&lt;&#x2F;p&gt;
&lt;p&gt;Sakurai’s model is pretty good, but I have a different way of looking at it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-game-is-a-language&quot;&gt;A game is a language&lt;&#x2F;h2&gt;
&lt;p&gt;Game is play, play is interaction between people.
Fun is understanding and gaining a new shared understanding with a playmate.&lt;&#x2F;p&gt;
&lt;p&gt;The developer of a puzzle game creates a new language,
like the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cryptophasia&quot;&gt;private languages&lt;&#x2F;a&gt; some twins develop.
This new language the player discovers with bafflement,
this is something they never saw before.
Solving puzzles is learning a new language,
grokking its grammar and discovering its vocabulary.&lt;&#x2F;p&gt;
&lt;p&gt;Learning a language shared between themselves and the developer only.
A secret and precious connection, a break up from isolation.&lt;&#x2F;p&gt;
&lt;p&gt;Similar to &lt;em&gt;Noita&lt;&#x2F;em&gt;’s magic wand system.
Literally a grammar: The reverse polish notation.
And a language: With nouns, adjectives, verbs and adverbs.&lt;&#x2F;p&gt;
&lt;p&gt;Action games are languages too.
Languages in a different register.
This is the language that the model of Risk&#x2F;Reward describes.
It is a language of threats and rewards.
The game speaks in urgent tones to the player,
the player replies with groans: “How am I supposed to beat that?”
And hopefully, later, other groans: &lt;strong&gt;“I did it! VICTORY!”&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;But ultimately, victory is this:
finally understanding the language of the game and speaking it yourself.&lt;&#x2F;p&gt;
&lt;p&gt;Or maybe it’s the game giving up and just letting the player through,
not a hard game, just a reproduction of a template that is known to sell.&lt;&#x2F;p&gt;
&lt;p&gt;Each player will find their own language.
What the game is, is not exactly a language,
but a seed for a shared understanding,
from which sprouts a language unique to the combination of the player and the game.&lt;&#x2F;p&gt;
&lt;p&gt;Playing a game is speaking with the developer.
A game is a language through which the player and the developer communicate,
through which they negotiate, argue, laugh, cry, care,
remember good old times or ponder on life.&lt;&#x2F;p&gt;
&lt;p&gt;A game is a unique personal connection,
a connection stronger than words or pantomime,
that unite player and developer.&lt;&#x2F;p&gt;
&lt;p&gt;Tension, Squeeze&#x2F;Release, Risk&#x2F;Reward, game flow are dull incomplete models.
They help understand some games, but at the price of fleecing them of their beauty.
They are crude models of human communication.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;game-essence-is-flavor&quot;&gt;Game Essence is flavor&lt;&#x2F;h2&gt;
&lt;p&gt;Where does this leave Game Essence?&lt;&#x2F;p&gt;
&lt;p&gt;Game essence is what makes a game unique
and places it in relation to other existing games.
I call it &lt;em&gt;flavor&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A developer is an alchemist, picking up existing game flavors,
breaking them into their elemental constituents, game design atoms, &lt;em&gt;aromas&lt;&#x2F;em&gt;,
and mixing them back into something new and unique.
A new flavor, with its own bitterness and sweetness,
each player appreciating it differently,
according to their own personal history and innate preferences.&lt;&#x2F;p&gt;
&lt;p&gt;Developers stand on the shoulders of giants.
Even genre-defining games like
&lt;em&gt;Dark Souls&lt;&#x2F;em&gt;, &lt;em&gt;Spelunky&lt;&#x2F;em&gt; or &lt;em&gt;Slay the Spire&lt;&#x2F;em&gt;
are but mere copy of pre-existing games.&lt;&#x2F;p&gt;
&lt;p&gt;Split &lt;em&gt;Super Mario World&lt;&#x2F;em&gt; in its constituent parts, take most of it;
Split &lt;em&gt;Rogue&lt;&#x2F;em&gt; in its  constituent parts, take some of it.
Mix them, you get &lt;em&gt;Spelunky&lt;&#x2F;em&gt;.
Something fundamentally unoriginal, yet completely new and innovative.&lt;&#x2F;p&gt;
&lt;p&gt;Those are genre-defining games.
The new mix of aromas created a new completely distinct and compelling flavor.&lt;&#x2F;p&gt;
&lt;p&gt;We have not just a new flavor, but a new &lt;em&gt;class&lt;&#x2F;em&gt; of flavors.
This is what a genre is.
Games in the same genre share many aromas,
yet all have their own subtle distinct flavor.&lt;&#x2F;p&gt;
&lt;p&gt;Games of the same developer have different flavors,
yet have a consistent undertone.
This is because the developer, like the player, has their personal taste, favorite aromas.&lt;&#x2F;p&gt;
&lt;p&gt;Aromas and flavors are a language indeed.
Game design and play is a communion,
a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cryptophasia&quot;&gt;cryptophasia&lt;&#x2F;a&gt; of players and developers.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not proposing anything practical here
(indeed, I warned you of that much at the beginning of the post).&lt;&#x2F;p&gt;
&lt;p&gt;I want to share a way of looking at games as beautiful things and
allow anyone to appreciate them more for what they are.
The language model of games may not help a company bump their quarterly revenue,
but is a beautiful way of talking about games, it helps see into the core of the game,
its essence, and appreciate all its flavor and scent.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe it’s pure navel gazing, maybe this could be honed into a game design tool?
Who knows? Anyway, I hope I helped make things more beautiful.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;tl;dr&lt;&#x2F;h4&gt;
		&lt;p&gt;Game is a &lt;em&gt;medium&lt;&#x2F;em&gt;, a mean of &lt;em&gt;communication&lt;&#x2F;em&gt;.
Play is the resolution of a personal dialog between the developer and the player.
(Or sometimes, between multiple players)&lt;&#x2F;p&gt;
&lt;p&gt;Game essence is what makes a game unique
and places it in relation to other existing games.
I call it &lt;em&gt;flavor&lt;&#x2F;em&gt;. &lt;em&gt;Flavor&lt;&#x2F;em&gt; is a sum of many &lt;em&gt;aromas&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Aromas&lt;&#x2F;em&gt; (or elements, game design atoms) are shared between games.
Each game has however its own exact combination of aromas,
which gives it its unique flavor.
A genre is a common set of aromas.&lt;&#x2F;p&gt;
&lt;p&gt;The game developer picks up aromas from all the games they want
(consciously or not)
and put them together to create their own flavor in a new game.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Behind the Klod</title>
		<published>2022-09-02T00:00:00+00:00</published>
		<updated>2022-09-02T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/making-of-klod-tech/" type="text/html"/>
		<id>https://devildahu.ch/devlog/making-of-klod-tech/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bone-klod&quot;&gt;Klod&lt;&#x2F;a&gt; is our submission to the second Bevy game jam.
It was made in 10 days by Devil Dahu, our 2 people team.
Nicola (me) at programming and music, and Xo at 3d art.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Jargon&lt;&#x2F;h4&gt;
		&lt;p&gt;&lt;em&gt;to klod, klodding, klodded&lt;&#x2F;em&gt;: verb, to add to the klod ball.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h2 id=&quot;preparing&quot;&gt;Preparing&lt;&#x2F;h2&gt;
&lt;p&gt;Pre-jam, I prepared a template based on our entry in the last jam,
&lt;a href=&quot;https:&#x2F;&#x2F;gibonus.itch.io&#x2F;warlocks-gambit&quot;&gt;Warlock’s Gambit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;devildahu.ch&#x2F;devlog&#x2F;making-of-klod-tech&#x2F;initial_menu.jpg&quot; alt=&quot;The template menu&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since the game was still running on bevy 0.7, it was a challenge to bring
the code up to date. But it helped a lot, since UI is definitively the most
annoying part of bevy, and all the UI I ended up needing was in the template.&lt;&#x2F;p&gt;
&lt;p&gt;A saving grace was the addition of the &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;bevy-ui-navigation&#x2F;latest&#x2F;bevy_ui_navigation&#x2F;systems&#x2F;struct.InputMapping.html#structfield.focus_follows_mouse&quot;&gt;&lt;code&gt;focus_follows_mouse&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; field in the
input mapping resource of &lt;code&gt;bevy-ui-navigation&lt;&#x2F;code&gt;. I will pat myself on the back
for caring for existing users, because sometimes that user is just me 🙂.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;&#x2F;h2&gt;
&lt;p&gt;The theme choice fell at 22:00, I did want to have a reasonable night sleep,
but we first started throwing around game ideas. Xo quickly suggested something
similar to &lt;em&gt;Katamari&lt;&#x2F;em&gt;, and &lt;strong&gt;I was &lt;em&gt;in&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;. I love &lt;em&gt;Katamari Damacy&lt;&#x2F;em&gt;, and programming
a clone seemed like a very fun challenge.&lt;&#x2F;p&gt;
&lt;p&gt;I jokingly went:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s make our own twist: Katamari Damacy, but dark souls (smirking face emote)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Puzzle game with Katamari mechanics? Where depending on what you pick up,
you get different abilities&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Then realization dawned upon me:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Oh man, Katamari, but the ball is just an agglomeration of corpses&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I started implementing the klod mechanic and waited on Xo for more feedback.
At this point I was not sure about the dark fantasy setting, but Xo seemed more
onboard than myself.&lt;&#x2F;p&gt;
&lt;p&gt;We discussed what other mechanics we could add to the game, failure and win
states. I proposed a time trial object collection challenge.&lt;&#x2F;p&gt;
&lt;p&gt;We had some more crazy ideas including multiplayer, which might feed into a
larger game, but at the end we settled with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Time trial score based win condition.&lt;&#x2F;li&gt;
&lt;li&gt;“Key” mechanic with “pickup item X to open door Y.”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;the formula for mana is just &lt;code&gt;bone weight × time left&lt;&#x2F;code&gt;, it was the
initial formula, and it was so good it didn’t need improvement.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The game would be mostly going downhill, trying to steer the ball enough to
pick up items for secret paths and score. In the end, it would look a lot like
&lt;em&gt;Rock of Ages&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-music&quot;&gt;The Music&lt;&#x2F;h2&gt;
&lt;p&gt;At the start of the jam, I didn’t feel like programming at all! So, after
settling on the setting, “dark fantasy,” I immediately went on &lt;a href=&quot;https:&#x2F;&#x2F;jummbus.bitbucket.io&#x2F;&quot;&gt;jummbox&lt;&#x2F;a&gt;
and did what can only be described as “jamming,” and in 3 hours, the game
soundtrack was complete. The track was later cut to fit the game length.&lt;&#x2F;p&gt;
&lt;p&gt;The music was to be split into several tracks, triggering by reaching certain
game areas.&lt;&#x2F;p&gt;
&lt;p&gt;At first, I implemented a very fancy music queue, waiting until the last
track ends before running new ones, to avoid jarring music transitions.
Tracks, however, were too long for that, so you wound up never hearing the final
staircase scale.&lt;&#x2F;p&gt;
&lt;p&gt;The very last-minute change to play the music immediately after reaching an area
is still quite buggy. This, for example, results in audio cutting if you die in
the first area of the game.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Klod soundtrack&lt;&#x2F;h4&gt;
		&lt;p&gt;&lt;audio controls src=&quot;Klod_soundtrack.mp3&quot; preload=none&gt;&lt;&#x2F;audio&gt;&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Game jam tip&lt;&#x2F;h4&gt;
		&lt;p&gt;I strongly recommend using &lt;a href=&quot;https:&#x2F;&#x2F;jummbus.bitbucket.io&#x2F;&quot;&gt;jummbox&lt;&#x2F;a&gt; for game jam music. I have no formal music
education and do not play any instrument, yet I can get some compelling crap
out of it.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-editor&quot;&gt;The Editor&lt;&#x2F;h2&gt;
&lt;p&gt;This is the single most damaging mistake I made.&lt;&#x2F;p&gt;
&lt;p&gt;We “needed” an editor to design the level. I wanted something in-engine so
that it would be trivial and quick to test out the level and edit it.&lt;&#x2F;p&gt;
&lt;p&gt;However, no such level editor exists for bevy. So obviously… I made one.
I used &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy_editor_pls&quot;&gt;&lt;code&gt;bevy_editor_pls&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; as a base, added &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ForesightMiningSoftwareCorporation&#x2F;bevy_transform_gizmo&#x2F;&quot;&gt;&lt;code&gt;bevy_transform_gizmo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for
manipulating objects, added keybindings similar to blender to move objects
around, created a scene system with prefabs, and wrote the UI for adding
Klod-specific object, saving and loading a level, just for the jam.&lt;&#x2F;p&gt;
&lt;p&gt;This took more or less 7 days out of the 10 we were given for the jam.
It didn’t help us much, but &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ForesightMiningSoftwareCorporation&#x2F;bevy_transform_gizmo&#x2F;pull&#x2F;36&quot;&gt;it&lt;&#x2F;a&gt; did &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy-inspector-egui&#x2F;pull&#x2F;83&quot;&gt;help&lt;&#x2F;a&gt;
other &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakobhellermann&#x2F;bevy_editor_pls&#x2F;pull&#x2F;37&quot;&gt;people&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;klod_editor.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;Early editor prototype demo.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up designing the level in &lt;a href=&quot;https:&#x2F;&#x2F;www.blender.org&#x2F;&quot;&gt;Blender&lt;&#x2F;a&gt; using exclusively 1×1×1
cubes and spheres resized using scale, and writing a tinny importer
based off &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nicopap&#x2F;bevy-scene-hook&quot;&gt;&lt;code&gt;bevy-scene-hook&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to convert it into the internal scene format.
What was imported included the environment and the items such as the bones
and shovels.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;Klodable items are also 1×1×1 cubes, if you open the game files with Blender,
you’ll notice that everything, including shovels and bones, are stretched to
fit a 1×1×1 cube.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The level is imported as a bunch of invisible fixed colliders, and the actual
visible geometry is just a single entity located at the origin of the level.&lt;&#x2F;p&gt;
&lt;p&gt;The editor was however useful at the end: to place lights in the level,
do last-minute fixups for balance and filling huge holes in the walls.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;Until the very last moment, the final staircase doors didn’t have a
doorstep, making it nearly impossible to use the shovels, I just added
a cube with the editor.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;In the end, I bundled the editor with the native build artifacts, so I have
an excuse for having wasted so much of my time doing something only tangential.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-sound-effects&quot;&gt;The sound effects&lt;&#x2F;h2&gt;
&lt;p&gt;We had music, but we needed some sound effects. Physics become empirically
1195.93% better if combined with sounds.&lt;&#x2F;p&gt;
&lt;p&gt;This was easy, I downloaded the &lt;a href=&quot;https:&#x2F;&#x2F;kenney.nl&#x2F;&quot;&gt;Kenny&lt;&#x2F;a&gt; “Impact Sounds” audio pack, wrote
a very lengthy and extremely fancy audio system to handle all the possible
sound effects and configure them with the editor.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, only a single impact sound effect is used in the whole game…&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;The ball has a roll sound, the sound used is found in the “Sci-Fi sounds”
Kenny audio pack, under the &lt;code&gt;thrusterFire_002.ogg&lt;&#x2F;code&gt; name. The roll
sound is almost never heard, because it requires the ball to roll smoothly for
a while, which becomes impossible after the first bone you pick up.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;The game has 127 “impact” audio files totalling 1.4M, yet only uses 5
tracks for 75K. I’m sorry to waste your bandwidth 😢&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-gameplay&quot;&gt;The Gameplay&lt;&#x2F;h2&gt;
&lt;p&gt;The gameplay ended up relatively minimal, it only required:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A “end goal” sensor zone to know that the player completed.&lt;&#x2F;li&gt;
&lt;li&gt;Pickable items, with specified “weight” to count toward the final score.&lt;&#x2F;li&gt;
&lt;li&gt;Items with “powers” that allow destroying special walls.&lt;&#x2F;li&gt;
&lt;li&gt;Special walls that can be destroyed.&lt;&#x2F;li&gt;
&lt;li&gt;A character controller with movement.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;controls&quot;&gt;Controls&lt;&#x2F;h3&gt;
&lt;p&gt;So how should the game control?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Katamari&lt;&#x2F;em&gt; controls themselves are unique: You use the two sticks of the
controller to steer the ball in a direction, as if the left stick and right
stick were mapped to the left and right hands of the Prince.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Katamari&lt;&#x2F;em&gt; controls are notoriously disorienting, so reproducing them wasn’t a
priority. I opted for an orbit cam with WASD&#x2F;left stick directional movement,
because I was expecting most players to be familiar with such controls. It also
would make it possible to play the game on keyboard. I actually planned
&lt;em&gt;Katamari&lt;&#x2F;em&gt; controls as an option, if only as a nod to an amazing game,
but I didn’t have enough time to implement them.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Trivia&lt;&#x2F;h4&gt;
		&lt;p&gt;Gamepad support was added in 5 minutes.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;h3 id=&quot;the-camera&quot;&gt;The Camera&lt;&#x2F;h3&gt;
&lt;p&gt;Klod has a classical 3d plateformer orbit camera, which is
known to be disorienting, especially indoors. This was a contentious point in
the team at the beginning of the jam, because we opted for an indoor setting
despite knowing we would depend on an orbit cam.&lt;&#x2F;p&gt;
&lt;p&gt;Knowing that, I made sure there is ample space for the camera to move around
when designing the level. But there is still a few cramped places, and indeed
the camera in those is really bad, I’m sorry.&lt;&#x2F;p&gt;
&lt;p&gt;The orbit cam code is straight up cut from a previous unfinished game, which
itself is cut out of a very old crate running only on bevy 0.4.&lt;&#x2F;p&gt;
&lt;p&gt;I am very proud how camera-relative input works in Klod, it simply
rotates the input by the camera’s &lt;code&gt;x&lt;&#x2F;code&gt; rotation.&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;crate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;OrbitCamera &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    distance&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    x_rot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    y_rot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    follows&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; Entity,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;OrbitCamera &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;crate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;horizontal_rotation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;x_rot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;% &lt;&#x2F;span&gt;&lt;span&gt;TAU
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;ball_input&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; force &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= ;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; input force …
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; force &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Vec2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;from_angle&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(-&lt;&#x2F;span&gt;&lt;span&gt;camera&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;horizontal_rotation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;rotate&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;force&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The trick is just to use the &lt;code&gt;x_rot&lt;&#x2F;code&gt; of the camera rotation, and rotate the force
by it, now input forward is forward for the camera.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;physics&quot;&gt;Physics&lt;&#x2F;h3&gt;
&lt;p&gt;The physics were surprisingly both difficult and easy to get right.&lt;&#x2F;p&gt;
&lt;video controls&gt;
    &lt;source src=&quot;klod_first_physics.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;(2nd day Katamari-like physics)&lt;&#x2F;p&gt;
&lt;p&gt;I opted to use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dimforge&#x2F;bevy_rapier&#x2F;&quot;&gt;&lt;code&gt;bevy_rapier&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for the physics, as I am familiar with it and
there isn’t much of an alternative anyway.&lt;&#x2F;p&gt;
&lt;p&gt;The klodding mechanic was relatively trivial to implement: &lt;code&gt;bevy_rapier&lt;&#x2F;code&gt; allows
specifying composite collider shapes as a parent &lt;code&gt;RigidBody&lt;&#x2F;code&gt; and a collection
of children &lt;code&gt;Collider&lt;&#x2F;code&gt;. So theoretically, I only had to convert the transform
of an entity I can klod into the klod-local coordinate space, remove the
entity’s &lt;code&gt;RigidBody&lt;&#x2F;code&gt; and set its parent to the klod ball itself.&lt;&#x2F;p&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;transform_relative_to&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;point&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;GlobalTransform, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;reference&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;GlobalTransform&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Transform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; relative_affine &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; reference&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;affine&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;inverse&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;() *&lt;&#x2F;span&gt;&lt;span&gt; point&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;affine&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;scale&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; rotation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; translation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) =&lt;&#x2F;span&gt;&lt;span&gt; relative_affine&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;to_scale_rotation_translation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    Transform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt; translation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; rotation&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; scale &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F; `agglo_trans` is the transform of the entity to add to the klod.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; trans &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;transform_relative_to&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;agglo_trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; klod_trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, &lt;code&gt;bevy_rapier&lt;&#x2F;code&gt; has a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dimforge&#x2F;bevy_rapier&#x2F;issues&#x2F;244&quot;&gt;few&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dimforge&#x2F;bevy_rapier&#x2F;issues&#x2F;247&quot;&gt;rough&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dimforge&#x2F;bevy_rapier&#x2F;issues&#x2F;247&quot;&gt;edges&lt;&#x2F;a&gt; which made the straightforward solution simply not work.&lt;&#x2F;p&gt;
&lt;p&gt;Once those bumps were surpassed with monstrous workarounds, including splitting
the components of the added entities into multiple entities, that was it.
It just worked.&lt;&#x2F;p&gt;
&lt;p&gt;Well, &lt;em&gt;not quite&lt;&#x2F;em&gt;. I got the &lt;em&gt;Katamari&lt;&#x2F;em&gt; mechanic working, but it was nearly
impossible to navigate the level, because you invariably ended up with a shape
preventing you from moving or too big to go through doors. The solution had
many elements:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Increase the &lt;code&gt;ExternalImpulse&lt;&#x2F;code&gt; power applied by inputs proportionally to
the total klod weight.&lt;&#x2F;li&gt;
&lt;li&gt;Slightly pull toward the center each klodded object.&lt;&#x2F;li&gt;
&lt;li&gt;Only klod objects if they are within a certain radius of the ball.&lt;&#x2F;li&gt;
&lt;li&gt;Make the bone collider a &lt;code&gt;RoundedCuboid&lt;&#x2F;code&gt; over just a &lt;code&gt;Cuboid&lt;&#x2F;code&gt;, removing
all hard edges that caused the most friction and sporadic jumps.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div
	class=&quot;limit_element_width &quot;
	style=&quot;max-width:calc(min(9999px,100%));&quot;
&gt;
		&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b2c2f;color:#cccece;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;within_radius&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;distance&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; max_distance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ec5f67;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;weight &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;KLOD_INITIAL_WEIGHT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    distance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; max_distance
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;agglo_to_klod&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#c594c5;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; trans &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;transform_relative_to&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;agglo_trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; klod_trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;translation &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; trans&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;translation &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f99157;&quot;&gt;0.8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#5f6364;&quot;&gt;&#x2F;&#x2F;..
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#5fb3b3;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;
&lt;&#x2F;div&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;level-design&quot;&gt;Level Design&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;devildahu.ch&#x2F;devlog&#x2F;making-of-klod-tech&#x2F;klod_greybox.jpg&quot; alt=&quot;The blender greybox version of the Klod level&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The level design was very awkward. The best tool I had at hand was Blender,
but it’s not well suited for that kind of tasks.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, I made the level before Xo made the tileset, and this resulted
in incompatible designs. So I made due, and just added the textures Xo made
to the base collider cubes (the “&lt;a href=&quot;https:&#x2F;&#x2F;jackw-gamedesign.tumblr.com&#x2F;post&#x2F;139960850160&#x2F;what-is-greyboxing&quot;&gt;greybox&lt;&#x2F;a&gt;” level), adjusting the UVs so they
don’t feel too stretched.&lt;&#x2F;p&gt;
&lt;div class=&quot;trivia&quot;&gt;
    &lt;h4&gt;Game design tip&lt;&#x2F;h4&gt;
		&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;jackw-gamedesign.tumblr.com&#x2F;post&#x2F;139960850160&#x2F;what-is-greyboxing&quot;&gt;Greyboxing&lt;&#x2F;a&gt; is the practice of developing a 3D game exclusively with filler
grey boxes. This permits to focus exclusively on gameplay. If your game is fun
with grey boxes, it will definitively be fun with cool graphics as well.&lt;&#x2F;p&gt;
&lt;p&gt;And in a pinch, you can always do like me, keep the box geometry and add a
simple texture.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;
&lt;p&gt;The visuals of &lt;em&gt;Klod&lt;&#x2F;em&gt; is a massive downgrade compared to &lt;em&gt;Warlock’s Gambit&lt;&#x2F;em&gt;.
I tried to salvage it last-minute, adding more visual diversity with lights,
but then the problem was performance, so I had to add a way to disable lighting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-touches&quot;&gt;Final touches&lt;&#x2F;h2&gt;
&lt;p&gt;18 hours before the end of the jam, I felt like the game was not fun at all!
I was very sad. However, after adjusting the physics and adding a goal, it
magically became fun and addictive.&lt;&#x2F;p&gt;
&lt;p&gt;I think the best part of the game is when you die. Everything goes in every
direction, including the hands, and a “you lose” sound effect plays. This was
difficult to do due to the rapier issues I’ve mentioned, but it was 159.1%
worth it.&lt;&#x2F;p&gt;
&lt;p&gt;I was tempted to make the game nearly impossible so that people would naturally
see the death animation. In insight, I should have played the death animation
on any loss condition.&lt;&#x2F;p&gt;
&lt;p&gt;The spawn animation with the hands joining the ball and the ball growing is
also excellent flavor, even if it lasts less than half a second, I love it
for how silly it is.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;results-and-learning&quot;&gt;Results and learning&lt;&#x2F;h2&gt;
&lt;p&gt;I eventually came around to enjoy the game. Despite the sub-par graphics, it is
still a fun game to play. (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;devildahu&#x2F;bone-klod&quot;&gt;reminder that you can play it in browser for free&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;However, this time, the competition is fierce! I think at least two games out
of the ones I played are better than Klod, and I’ve only played 15 out of the
89 submitted games.&lt;&#x2F;p&gt;
&lt;p&gt;I think our weakness is still unfamiliarity with game development processes and
a lack of environmental artists. The weakness bevy showed are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Lack of an opinionated focus system&lt;&#x2F;li&gt;
&lt;li&gt;No mature level editors&lt;&#x2F;li&gt;
&lt;li&gt;Poor scene API design&lt;&#x2F;li&gt;
&lt;li&gt;Awful UI library&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Making Warlock&#x27;s Gambit</title>
		<published>2022-03-06T00:00:00+00:00</published>
		<updated>2022-03-06T00:00:00+00:00</updated>
		<link href="https://devildahu.ch/devlog/making-of-warlock-gambit-part-1/" type="text/html"/>
		<id>https://devildahu.ch/devlog/making-of-warlock-gambit-part-1/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gibonus.itch.io&#x2F;warlocks-gambit&quot;&gt;Warlock’s Gambit&lt;&#x2F;a&gt; is our submission
to the first Bevy game jam. It was made over
7 days by Team Plover. This dev log is a rundown of the development
process. Will dive into the nitty-gritty code implementation
details in &lt;a href=&quot;&#x2F;devlog&#x2F;making-of-warlock-gambit-part-2&quot;&gt;a future dev log&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-team&quot;&gt;The Team&lt;&#x2F;h2&gt;
&lt;p&gt;Team Plover had 7 members but most of the work was
done by 4 of them. The participation of the 3 other members was still welcome
and helped finish the game in time.&lt;&#x2F;p&gt;
&lt;p&gt;I’m one of the two developers who put serious work into Warlock’s Gambit. I’ve
programmed all the logic, while vasukas made sure my code ran on all
plateforms and implemented the win&#x2F;lose states. Which is not chump change! It
was an invaluable contribution.&lt;&#x2F;p&gt;
&lt;p&gt;Team Plover is extremely distributed, with at least 4 continents accounted for.
This was already a challenge in itself. The channels most people use for
consensus are not available to a distributed team.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;&#x2F;h2&gt;
&lt;p&gt;We decided pretty quickly to work using git on Github. The game would be in a
private repo until the release, when we would open-source it. The competition
rules allowed to start from a “generic” project. I decided to setup a project
with probably-useful dependencies and write a minimal starting menu with audio
sliders (turns out we have the only game in the comp with audio sliders.)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;&#x2F;h2&gt;
&lt;p&gt;Once the jam theme was announced, we discussed what we could do based on
“Unfair Advantage” in Discord on text channels. I personally wanted something
involving pigeons or wizards or both at the same time, imagining a game of
soccer with wizards. However, the idea that caught everyone’s imagination was
Lorithan’s card game: you play against someone who
stacked the deck against you. The only way to win would be by cheating.&lt;&#x2F;p&gt;
&lt;p&gt;Once we had the idea. I put it down on a markdown file on git with a very basic
draft of game design. Github has a surprisingly usable markdown editor that let
you edit text files and update them in the browser. With this, I encouraged
everyone, including our artists with no concept of programming to edit the
design file with their comments and design suggestions. However that file
didn’t see a lot of edits and the game design lingered.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-design&quot;&gt;The Design&lt;&#x2F;h2&gt;
&lt;p&gt;It was convened that we should have a voice chat where we could discuss
synchronously the game design to acquire a consensus before going forward with
code or art. We spent a day and an half picking up everyone’s schedule and
trying to find a time frame during which we could get all together. This failed
as we were &lt;em&gt;really&lt;&#x2F;em&gt; distributed and simply didn’t have overlapping free time to
get together.&lt;&#x2F;p&gt;
&lt;p&gt;After having spent two days waiting on something that didn’t happen, we
implicitly decided on going forward with the design. I improved the design by
adding more details. Once we were ready, we went at it like a canon ball.
This is where development really took off.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The Code&lt;&#x2F;h2&gt;
&lt;p&gt;This means we only had about &lt;strong&gt;4 days left to write the code&lt;&#x2F;strong&gt; and get something
out the door. I still can’t believe I managed to make such a high polish game in such short
notice. This is contrary to everything I’ve done before. I think the team was
the real catalyst for that productivity. I was already very familiar with rust
and was coming from 5 months of full time focus on bevy game making. I knew the
ins and out of the engine, what were the areas to avoid and how to use
optimally bevy’s feature to make a great game. But I never reached such an
intense coding output before. I’ll go into the coding details in a &lt;a href=&quot;&#x2F;devlog&#x2F;making-of-warlock-gambit-part-2&quot;&gt;future dev
log&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-art&quot;&gt;The Art&lt;&#x2F;h2&gt;
&lt;p&gt;Xo has been working with me for the same length of time I’ve been discovering
bevy. He’s an excellent artist, it’s in fact an honor to be able to work with
such a talented person. Xo mocked a scene (the one you can see in the game) and
produced the assets as separate 2d png files. I specifically asked him for this,
so that I could put them together in a 3d scene in blender, in addition to
various “empty” objects that would serve an anchor for gameplay elements. I’ll
go in more details how I linked the gameplay elements to the objects in a
future post. You can find that scene in the game files. You can open it with
blender to see for yourself how it looks like 🙂&lt;&#x2F;p&gt;
&lt;p&gt;I spent a few hours adjusting the graphical assets, not only in the 3d scene,
but also the card assets. To reduce file size, I converted the card numbers and words
to a 2d color palette. The PNG file format can efficiently
compress low color count images with simple shapes. This involved a lot of looking up
on stack overflow how to use the imageMagick &lt;code&gt;convert&lt;&#x2F;code&gt; tool. But we got
everything in the correct format by the end.&lt;&#x2F;p&gt;
&lt;p&gt;Samuel_Sound was a late-comer to the party, and worked completely independently
of the rest of the team, just asking for a mood and some inspirations. But their
contribution was paramount to give a personality to the game. The music they
produced is excellent. They worked off of &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=C0YBWu6nym4&quot;&gt;The Banished soundtrack&lt;&#x2F;a&gt;.
Samuel_Sound also contributed the card shuffling sounds.&lt;&#x2F;p&gt;
&lt;p&gt;The “words of power” that gives effect to cards are written &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Enochian&quot;&gt;in Enochian&lt;&#x2F;a&gt;. The voice you can hear when they are played is mine. I say the word as they would
be pronounced in Enochian. I modified the voice with Audacity effects.
I also made squawking and quacking noises for the bird,
sadly I couldn’t add those sfx in time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-final-rush&quot;&gt;The Final Rush&lt;&#x2F;h2&gt;
&lt;p&gt;The final day was insane! Up until Friday, we really didn’t have any playable
“game”. Just card drawing, dragging, dropping and basic War score counting. But
it came together very quickly! I calculated I could get a publishable game with
sound, music, card effects and win&#x2F;lose by midday (while the submission was at
10PM). And I wasn’t far off. By 3PM I implemented that day:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The card effects (point bonuses, adding seeds etc.)&lt;&#x2F;li&gt;
&lt;li&gt;An overlay system that shows tutorial texts and card effect descriptions&lt;&#x2F;li&gt;
&lt;li&gt;The music and sfxs (card shuffling, voices)&lt;&#x2F;li&gt;
&lt;li&gt;An AI that can chose to play a better card than the one the player played&lt;&#x2F;li&gt;
&lt;li&gt;The bird eye looking at the card the player grabs and detecting when the
cheat is used&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I took the rest of the afternoon to design a sequence of cards that makes it
impossible to win without cheating while being beatable with the sleeve trick.
This involved pen and paper and a calculator. It was very fun to design.
This prompted me to add synergies to the card effects. Surprisingly, designing
the deck with synergies in mind (for example, the +12 and x2 would double the
bonus) was much easier.&lt;&#x2F;p&gt;
&lt;p&gt;By 6:30PM I added the deck to the game. It was
time to publish the game on itch.io. This is where vasukas’s and BLucky’s
contributions were the most critical. I developed the game on Linux with
absolutely no regard for multiplatform. While I was hammering at the code,
vasukas was figuring out how to create an HTML file with the game embedded.
BLucky compiled the binary for
MacOS. I was hopping that the official bevy Github CI pipeline would be enough,
but it was too dang slow, the MacOS build failed and the wasm version didn’t even work!
Each team member pushed their version of the game to the itch.io page and by the end
we had everything in order. I even had the time to add the deck shrinking
mechanic.&lt;&#x2F;p&gt;
&lt;p&gt;That’s it. I’m really proud of the result. I do think we have the most polished
entry in the jam by a large margin, despite all the bugs. I’m myself extremely
surprised I could write so quickly such a game. And I’m surprised the game
ended up actually quite fun despite having about 3 hours of thought put into
it.&lt;&#x2F;p&gt;
&lt;p&gt;Now I &lt;em&gt;know&lt;&#x2F;em&gt; you are a bevy users and you are highly disappointed I didn’t go
into details about game architecture, ecs, events and all the implementation
details. But don’t be despondent! I &lt;em&gt;love&lt;&#x2F;em&gt; writing about technical things and as I said I’m very
proud of the code, so obviously I’ll go into a deep dive in &lt;a href=&quot;&#x2F;devlog&#x2F;making-of-warlock-gambit-part-2&quot;&gt;a future dev log entry&lt;&#x2F;a&gt;.
Be patient 😉&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
