<?xml version='1.0' encoding='utf-8' ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Try Jumping</title>
<subtitle>Open Source game development.</subtitle>
<id>urn:uuid:55744ab6-4035-3bbf-b3ae-bb6eb0d78397</id>
<updated>2023-05-02T20:55:22Z</updated>
<link href="https://tryjumping.com/blog" />
<link href="https://tryjumping.com/blog/feed.xml" rel="self" />
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<entry xml:base="https://tryjumping.com/blog/2021/11/07/dose-response-coming-to-steam/">
<title type="text">Dose Response is coming to Steam</title>
<link href="https://tryjumping.com/blog/2021/11/07/dose-response-coming-to-steam/" rel="alternate" type="text/html" />
<id>https://tryjumping.com/blog/2021/11/07/dose-response-coming-to-steam/</id>
<published>2021-11-07T20:34:01+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;I&amp;#8217;m delighted to announce that &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is coming to Steam!&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://store.steampowered.com/app/1750910/Dose_Response/&quot;&gt;&lt;img src=&quot;02%20high.png&quot; alt=&quot;Dose Response screenshot&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Compared to the currently-available 1.0 version, the new release will feature Actual Graphics™, music &amp;amp; sound effects, improved UI and a full mouse support.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t know when the game will be released. I&amp;#8217;d love to do it this year, but between work, personal life and having a one-month-old baby, it is completely up in the air.&lt;/p&gt;
&lt;p&gt;The initial release will be on Windows and Linux. I&amp;#8217;d love to do a MacOS release as well, but between Apple&amp;#8217;s developer license fees and code signing requirements, that&amp;#8217;s something I&amp;#8217;ll investigate later. The sales of the game will also play a role in the decision.&lt;/p&gt;
&lt;p&gt;You can go to the &lt;a href=&quot;https://store.steampowered.com/app/1750910/Dose_Response/&quot;&gt;Dose Response Steam page&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://store.steampowered.com/app/1750910/Dose_Response/&quot; class=&quot;bare&quot;&gt;https://store.steampowered.com/app/1750910/Dose_Response/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;By adding the game to your wishlist, you&amp;#8217;ll be notified when it&amp;#8217;s out ;-).&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2021/01/31/2021-in-roguelikedev/">
<title type="text">2021 in RoguelikeDev</title>
<link href="https://tryjumping.com/blog/2021/01/31/2021-in-roguelikedev/" rel="alternate" type="text/html" />
<id>https://tryjumping.com/blog/2021/01/31/2021-in-roguelikedev/</id>
<published>2021-01-31T19:05:58+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;The &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;r/roguelikedev subreddit community&lt;/a&gt; hosts a &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/comments/ko17gw/2021_in_roguelikedev_a_january_event/&quot;&gt;yearly January event&lt;/a&gt; where authors talk about the last year in development and look ahead. This is my post (&lt;a href=&quot;https://www.reddit.com/r/roguelikedev/comments/l8nap5/2021_in_roguelikedev_dose_response/&quot;&gt;originally on Reddit&lt;/a&gt;)&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;dose_response&quot;&gt;Dose Response&lt;/h2&gt;
&lt;p&gt;Dose Response is an open world roguelike where you&amp;#8217;re an addict. You&amp;#8217;re wandering around, desperately looking for the next fix, having to avoid the dangers surrounding you.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s an abstract game&amp;#8201;&amp;#8212;&amp;#8201;no needles or guns, the monsters are concepts rather than orcs or trolls. The focus is more on the loop of compulsion and the alternating of feeling great and the fall that follows.&lt;/p&gt;
&lt;p&gt;It is also supposed to be a relatively short and simple game. One where you don&amp;#8217;t have a tonne of things to learn. There&amp;#8217;s few items, a handful of monsters, no levelling and no spells. Something that a &quot;normal player&quot; would be able to play (and win if they&amp;#8217;re careful) while still being challenging and true to the roguelike feel.&lt;/p&gt;
&lt;h2 id=&quot;2020_retrospective&quot;&gt;2020 Retrospective&lt;/h2&gt;
&lt;p&gt;I had planned to double down on Dose Response development and release it on Steam. But the last 15 months or so have been incredibly difficult for me. Crises came in different forms, from many angles, one after another. It took a huge amount of effort and energy to remain safe and (mostly) sound.&lt;/p&gt;
&lt;p&gt;Things are better now, but I was able to do a small fraction of what I planned.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve wanted to add graphical tiles to the game for a long time, but I really worried about being able to keep the feel of the game, maintain the abstract nature of it.&lt;/p&gt;
&lt;p&gt;Then I came across this free &lt;a href=&quot;https://v3x3d.itch.io/bountiful-bits&quot;&gt;Bountiful Bits tileset by VEXED&lt;/a&gt; and I loved it instantly. Put it in the game, loved the look and asked the author if they were willing to create the tiles that were missing (characters, monsters, food, doses).&lt;/p&gt;
&lt;p&gt;And we came up with a great agreement. The work was in a range I was happy to pay for something that will unlikely reach any real profit, they&amp;#8217;re licensed under CC0 which means I can keep the game fully open source and &lt;a href=&quot;https://vexed.zone/tools/&quot;&gt;VEXED&lt;/a&gt; can have them in their open portfolio.&lt;/p&gt;
&lt;p&gt;VEXED has been fantastic to work with&amp;#8201;&amp;#8212;&amp;#8201;they took on my deeply vague requests and created something with the exact look and feel I wanted.&lt;/p&gt;
&lt;h3 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h3&gt;
&lt;p&gt;Companion NPC with tiles:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-gfx.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-gfx.png&quot; alt=&quot;Companion NPC screenshot with tiles&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Same screenshot with ASCII graphics:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-ascii.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-ascii.png&quot; alt=&quot;Companion NPC screenshot in ASCII&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A fully uncovered game map:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-full-ascii.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-full-ascii.png&quot; alt=&quot;Screenshot of the full game map with tiles&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Same with ASCII graphics:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-full-gfx.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-full-gfx.png&quot; alt=&quot;Screenshot of the full game map in ASCII&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The only other significant thing I&amp;#8217;ve done was replace my ad-hoc text-based UI code with a Rust-native library called &lt;a href=&quot;https://github.com/emilk/egui/&quot;&gt;egui&lt;/a&gt;. It&amp;#8217;s a pretty young project, but it&amp;#8217;s got actual widgets, can do layouts, is renderer agnostic and therefore let me do a lot of things I&amp;#8217;ve been putting off.&lt;/p&gt;
&lt;p&gt;Main menu:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-menu.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-menu.png&quot; alt=&quot;Main Menu&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Settings:&lt;/p&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;screenshot-2021-01-30-settings.png&quot;&gt;&lt;img src=&quot;screenshot-2021-01-30-settings.png&quot; alt=&quot;Settings&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Oh, and I finally also got a laptop from Apple a year ago and thus managed to fix issues on that platform. Since then, Apple has switched their lineup to a completely new CPU architecture so who knows if it&amp;#8217;ll still work there. I&amp;#8217;m not buying a mac every year.&lt;/p&gt;
&lt;h2 id=&quot;2021_outlook&quot;&gt;2021 Outlook&lt;/h2&gt;
&lt;p&gt;There&amp;#8217;s a handful of things that I&amp;#8217;d like to do before I feel I&amp;#8217;m satisfied with the game:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Finish up the menu and GUI work
&lt;ul&gt;
&lt;li&gt;
Add the graphical tiles to the Help pages, inventory, etc.
&lt;ul&gt;
&lt;li&gt;
Right now, the GUI only shows the ASCII version of everything
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Implement the Challenge settings to make the game easier/harder to play
&lt;/li&gt;
&lt;li&gt;
Add a colour-blind and/or greyscale mode
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Add (optional) sounds and some ambient music
&lt;/li&gt;
&lt;li&gt;
Improve the world generation
&lt;ul&gt;
&lt;li&gt;
I like what the current naïve worldgen produces
&lt;/li&gt;
&lt;li&gt;
But I&amp;#8217;d like to make the exploration more varied and interesting
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Better mouse support
&lt;ul&gt;
&lt;li&gt;
You can fully control the game with a mouse but it&amp;#8217;s awkward
&lt;/li&gt;
&lt;li&gt;
I&amp;#8217;d like to make it feel better without compromising on the &quot;roguelikeness&quot;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Start posting regular gameplay videos and updates
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are massive, but they&amp;#8217;ll take time and energy which is in short supply still.&lt;/p&gt;
&lt;p&gt;And the biggie: release on Steam.&lt;/p&gt;
&lt;p&gt;Even without updating the gameplay, I want to finish up the graphics, sound &amp;amp; controls work before I&amp;#8217;m comfortable putting it on Steam, though.&lt;/p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tryjumping.com/dose-response-roguelike/&quot;&gt;Website&lt;/a&gt; | &lt;a href=&quot;https://www.youtube.com/watch?v=Pjkn7_YyBM8&quot;&gt;Trailer&lt;/a&gt; | &lt;a href=&quot;https://tryjumping.itch.io/dose-response&quot;&gt;itch.io&lt;/a&gt; | &lt;a href=&quot;https://github.com/tryjumping/dose-response&quot;&gt;Source&lt;/a&gt; | &lt;a href=&quot;https://tryjumping.com/dose-response-roguelike/play/&quot;&gt;Play Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The version on the website/itch doesn&amp;#8217;t have the new changes. I need to read up on Steam&amp;#8217;s (and other stores&#39;) policies to see how much is allowed on other sites with possibly different payment strategies (Dose Response on Itch is pay what you want). I might end up keeping the ASCII-only version as is and make the new version with graphics etc. have a set price.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/12/20/dose-response-1-0-is-out/">
<title type="text">Dose Response 1.0 Is Out!</title>
<link href="https://tryjumping.com/blog/2018/12/20/dose-response-1-0-is-out/" rel="alternate" type="text/html" />
<id>urn:uuid:8d92b40e-1a87-3510-9441-379a2d96bfc7</id>
<published>2018-12-20T12:07:40+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;We are extremely happy to announce the first full release of &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt;. It is a short open-world roguelike where you play an addict.&lt;/p&gt;
&lt;p&gt;It is a traditional roguelike (ASCII graphics, 8-directional movement, permadeath), but streamlined and with each play through lasting about 5 minutes.&lt;/p&gt;
&lt;p&gt;You can get &lt;a href=&quot;https://tryjumping.itch.io/dose-response&quot;&gt;Dose Response on itch.io&lt;/a&gt; (it’s pay what you want).&lt;/p&gt;
&lt;iframe frameborder=&quot;0&quot; src=&quot;https://itch.io/embed/226247?bg_color=161616&amp;amp;fg_color=adadad&amp;amp;link_color=ff4929&amp;amp;border_color=52534d&quot; width=&quot;552&quot; height=&quot;167&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;You can also check out the trailer:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Pjkn7_YyBM8&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;And have a look at the screenshots on our &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response page&lt;/a&gt;.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/12/15/this-week-in-dose-response-8/">
<title type="text">This Week in Dose Response 8</title>
<link href="https://tryjumping.com/blog/2018/12/15/this-week-in-dose-response-8/" rel="alternate" type="text/html" />
<id>urn:uuid:8d92b40e-1a87-3510-9441-379a2d96bfc7</id>
<published>2018-12-15T09:25:40+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlights game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Changes this week:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Added icon to the Windows executable
&lt;/li&gt;
&lt;li&gt;
Added a &lt;a href=&quot;./will-progress-bar.png&quot;&gt;progress bar for increasing your Will stat&lt;/a&gt; (in the top-right corner next to the Will number)
&lt;/li&gt;
&lt;li&gt;
Companion NPCs are always visible (even outside FoV or in unexplored areas)
&lt;/li&gt;
&lt;li&gt;
More work (visuals, blog, content) on the new website: tryjumping.com
&lt;/li&gt;
&lt;li&gt;
Starting the game now shows the main menu (as opposed to the actual game) first
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The latest change is a bit bittersweet. I really liked the way Braid just dumped you into the game as soon as you started it without faffing about with the UI.&lt;/p&gt;
&lt;p&gt;But ultimately, most games show you the menu first, so it’s familiar to the players and there are things you may want to do first (reading the help, switching to full screen, loading a game).&lt;/p&gt;
&lt;p&gt;After several months, I’ve also &lt;a href=&quot;/dose-response-roguelike/dose-response-victory-2018-12-14T13-26-34.png&quot;&gt;finally won the game fair and square again&lt;/a&gt; \o/. Always a good feeling :-).&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/12/01/this-week-in-dose-response-7/">
<title type="text">This Week in Dose Response 7</title>
<link href="https://tryjumping.com/blog/2018/12/01/this-week-in-dose-response-7/" rel="alternate" type="text/html" />
<id>urn:uuid:649f4c70-89b5-3b55-8618-536b4528008b</id>
<published>2018-12-01T10:41:42+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlights game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;This is our first beta release \o/.&lt;/p&gt;
&lt;p&gt;Changes this week:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finally fixed the screen scrolling glitch&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This has been a long-standing bug that was driving me nuts: when the camera re-centres on the player, there was this weird flickering glitch that I just could not figure out.&lt;/p&gt;
&lt;p&gt;Well now I did \o/. Turns out, instead of having a single camera position, I was setting a custom offset to each rendered tile and the offset was not being set on some of them.&lt;/p&gt;
&lt;p&gt;Since that was the last bug that really needed fixing for this to be releasable, this is the beta :-).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixed the winit backend look on Linux under Wayland&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In addition to the default SDL rendering backend, we ship another one based on Winit and Glium – a pure Rust backend. This should make it easier for people who want to build the code themselves.&lt;/p&gt;
&lt;p&gt;Well, on Linux with Wayland (the newer um… desktop compositor or something? It replaces X11 basically), it tried to guess the desired window size (rather than using what the game tells it to)&lt;/p&gt;
&lt;p&gt;Plus the fullscreen was still showing window decorations (the title bar, minimise &amp;amp; maximise buttons, etc.) and now it should be correct.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Web presence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So I’ve created an &lt;a href=&quot;https://tryjumping.itch.io/dose-response&quot;&gt;itch.io page&lt;/a&gt; as well as a &lt;a href=&quot;https://tryjumping.com/&quot;&gt;website for this and any potential future gamedev projects&lt;/a&gt;. They both… um… need some work :-).&lt;/p&gt;
&lt;p&gt;I’ll probably also want to create a company for tax purposes – I don’t expect to actually make any money selling Dose Response, but I wouldn’t want to deprive my country of their fair share of the five dollars or whatever if my mum buys it.&lt;/p&gt;
&lt;p&gt;Plus it’ll be a useful exercise if I ever go freelance and/or fulltime gamedev (not very likely). And who knows, some day the team may have more than one person so having an actual studio might be nice. Also, this is probably a massive exercise in overthinking, I’m aware.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/11/24/this-week-in-dose-response-6/">
<title type="text">This Week in Dose Response 6</title>
<link href="https://tryjumping.com/blog/2018/11/24/this-week-in-dose-response-6/" rel="alternate" type="text/html" />
<id>urn:uuid:90bb3a53-7736-395b-b745-b9c726e83946</id>
<published>2018-11-24T13:37:39+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Changes this week:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Give companion NPCs same speed as the player&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When a NPC accompanies (a sober) player, one of the bonuses they can impart is doubling the movement speed. That meant the player could outrun the NPC and since the world can be (semi) infinite, the NPC could get outside of the actively simulated area and the bonus would disappear. I threw a few good runs over this.&lt;/p&gt;
&lt;p&gt;So companion NPCs will now always match player’s speed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Double the food bonus&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No matter how deep into a withdrawal you are, eating food will now get you sober. That makes the rule easier to understand, but it also means eating food will make you last twice as long now.&lt;/p&gt;
&lt;p&gt;I worried this would screw up the balance but I still can’t win this damn thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remove window scaling in winit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While SDL2 is the default windowing backend, we do support &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;winit&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://crates.io/crates/winit&quot;&gt;glutin&lt;/a&gt; – the pure Rust alternatives. By default, winit tries to guess a DPI correction based on the display which results in 1.6 scaling on my machine. And that means the game’s tiles look fuzzy.&lt;/p&gt;
&lt;p&gt;We only have a single font size right now, anything else gets scaled up by the GPU.&lt;/p&gt;
&lt;p&gt;I’ll want to make all this more responsive with dynamic font sizes some day, but for now, I’ve just forced a 1x scaling across the board. You can always resize the window if you want.&lt;/p&gt;
&lt;p&gt;Speaking of scaling and fuzzy fonts, I’ve got a 4K monitor now so &lt;a href=&quot;2018-11-20T11-30-46-4K.png&quot;&gt;here’s Dose Response in 3840 x 2160 pixels&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And finally, I’ve updated a few code dependencies and did a bit of cleanup. Busy work with no observable benefit, but it made me a little happier :-).&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/11/17/this-week-in-dose-response-5/">
<title type="text">This Week in Dose Response 5</title>
<link href="https://tryjumping.com/blog/2018/11/17/this-week-in-dose-response-5/" rel="alternate" type="text/html" />
<id>urn:uuid:d0aced75-300b-3c50-9c60-091e7609462e</id>
<published>2018-11-17T10:40:56+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Changes this week:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disappeared Victory NPC signpost&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During the endgame, a Victory NPC appears and the player must get to them without getting high. If they do use a dose, the NPC would disappear. Which can be confusing.&lt;/p&gt;
&lt;p&gt;So now they &lt;a href=&quot;2018-11-17T11-36-33-signpost.png&quot;&gt;leave a signpost behind&lt;/a&gt; and when the player bumps into it, they’ll get a &lt;a href=&quot;2018-11-17T11-36-41-signpost-msg.png&quot;&gt;message explaining what happened&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixed crash on starting a new game in the Web version&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, using WebAssembly means occasionally dropping down to raw pointers which can mean crashes. Starting a new game without reloading the page now works again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Added version, build information and license directly in the game&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In case the player only has the game’s executable (without the corresponding readme or other files) and wants to report a bug I’d still like to know exactly which version they’re running.&lt;/p&gt;
&lt;p&gt;That information is now in a &lt;a href=&quot;2018-11-17T11-43-51-about.png&quot;&gt;new help page&lt;/a&gt;, so they can just send me a screenshot of that. Plus stuff like the licensing information, homepage etc.&lt;/p&gt;
&lt;p&gt;And the same info is now present in the game log produced on startup.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/11/10/this-week-in-dose-response-4/">
<title type="text">This Week in Dose Response 4</title>
<link href="https://tryjumping.com/blog/2018/11/10/this-week-in-dose-response-4/" rel="alternate" type="text/html" />
<id>urn:uuid:dd462871-00cd-3528-b65c-7618ff234038</id>
<published>2018-11-10T11:41:32+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Slow week, but a week of progress nonetheless! Mostly polishing up the Victory NPC situation.&lt;/p&gt;
&lt;p&gt;At the beginning of the endgame section, a special NPC is generated. The player’s goal is to reach that NPC to win (see last week’s update).&lt;/p&gt;
&lt;p&gt;To make sure the NPC is actually reachable by the player, I run a pathfinding algorithm and pick a different location if it fails. Because the world of Dose Response is potentially infinite, we need to limit the pathfinding computation. I used to have a situation where it would just take forever trying to inspect every corner of the world.&lt;/p&gt;
&lt;p&gt;The previously hardcoded limit did not reach far enough to the expected NPC distance (80-120 tiles away) and just increasing it meant more computation work from the monsters, slowing the game down. So this is now configurable and the current values seem to work fine in all cases.&lt;/p&gt;
&lt;p&gt;When the Victory NPC appears, the camera briefly scrolls towards them. This was broken, because we were always only rendering tiles within a small distance from the player. So when the &amp;#8220;camera&amp;#8221; left that area, all you could see was black.&lt;/p&gt;
&lt;p&gt;This is now fixed and the rendering code correctly identifies which tiles to show.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/11/04/this-week-in-dose-response-3/">
<title type="text">This Week in Dose Response 3</title>
<link href="https://tryjumping.com/blog/2018/11/04/this-week-in-dose-response-3/" rel="alternate" type="text/html" />
<id>urn:uuid:bf957ef2-1965-3a1d-b5d9-fa91ec7f01e5</id>
<published>2018-11-04T17:09:11+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is a small open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;It’s been four months since my last update and also since I got to do any real work on the game.&lt;/p&gt;
&lt;p&gt;This week, I’ve finally added the real endgame, removing the placeholder one. Previously, once you’ve reached the endgame condition (being able to pick up any dose without being compelled to use it immediately), you won the game if you managed to stay sober for 100 turns. Which is kind of boring, not easy to communicate and so on.&lt;/p&gt;
&lt;p&gt;So now, a new NPC is spawned 80-120 tiles away and the camera pans to it and back. If you use any dose (food is fine), the NPC disappears again. But if you stay sober and reach them, you win the game. I like to think of it as reuniting with a lost friend or family member after you’ve managed to get clean and stay clean. But the game is abstract enough not to impose any particular interpretation on the player.&lt;/p&gt;
&lt;p&gt;Here are some screenshots of the final moments:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;2018-11-03T14-06-00.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;2018-11-03T14-06-00.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;2018-11-03T14-07-31.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;2018-11-03T14-07-31.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;2018-11-03T14-07-47.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;2018-11-03T14-07-47.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wanted to add one more showing the victory screen, but as soon as I bumped into the NPC, the game crashed :-). Naturally, that’s fixed now.&lt;/p&gt;
&lt;p&gt;As you can see, the Victory NPC is of the same look &amp;amp; colour as the main player (white). I wanted to distinguish them from the other NPCs in the game and making them look like the player seems to do the trick nicely. The NPC is stationary and there’s always at most one in the game. So it shouldn’t cause any confusion. But if it does, I’ll pick another colour.&lt;/p&gt;
&lt;p&gt;I’m really excited about this because I’m finally making progress again and also, this was the final missing gameplay piece. There’s a bunch of bugs and glitches that need fixing, but otherwise, the game is now feature complete (famous roguelikedev last words).&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/05/05/this-week-in-dose-response-2/">
<title type="text">This Week in Dose Response 2</title>
<link href="https://tryjumping.com/blog/2018/05/05/this-week-in-dose-response-2/" rel="alternate" type="text/html" />
<id>urn:uuid:13dd0502-2188-352a-9d48-5b145bd03d84</id>
<published>2018-05-05T19:19:48+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is an open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Mostly engine work this week. The previous SDL experiments uncovered deficiencies in the &amp;#8220;engine architecture&amp;#8221;. Mostly, the backends were doing way too much work and the game/engine boundary did not work that great. So I’ve tried to clean it up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The renderers now only support 2 operations: draw a rectangle or a a portion of the texture map
&lt;/li&gt;
&lt;li&gt;
Fixed the pure-Rust OpenGL renderer as well as the web backend
&lt;/li&gt;
&lt;li&gt;
Moved a bunch of code that was previously hidden in the various backends up so it’s available everywhere
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the backends are now much smaller and everything else (text layout, glyph positioning, screen fade, etc.) is done outside of them, the game finally looks and feels the same on all the backends (rust, sdl, web).&lt;/p&gt;
&lt;h2 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h2&gt;
&lt;div class=&quot;title&quot;&gt;Glitches in the texture rendering made it look like some alien language:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
New game (glitch): &lt;a href=&quot;char-glitch-game.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-game.png&quot; alt=&quot;New game glitch&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
New game (fixed): &lt;a href=&quot;char-glitch-game-fixed.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-game-fixed.png&quot; alt=&quot;New game fixed&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Help screen (glitch): &lt;a href=&quot;char-glitch-help.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-help.png&quot; alt=&quot;Help screen glitch&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Help screen (fixed): &lt;a href=&quot;char-glitch-help-fixed.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-help-fixed.png&quot; alt=&quot;Help screen fixed&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Main Menu (glitch): &lt;a href=&quot;char-glitch-menu.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-menu.png&quot; alt=&quot;Main menu glitch&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Main Menu (fixed): &lt;a href=&quot;char-glitch-menu-fixed.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;char-glitch-menu-fixed.png&quot; alt=&quot;Main menu fixed&quot;&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;title&quot;&gt;First successful texture rendering in WebGL:&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;webgl-texture-test.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;webgl-texture-test.png&quot; alt=&quot;webgl&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(that should have been the &lt;code&gt;@&lt;/code&gt; sign but I couldn’t convert that to the opengl texture coordinates easily)&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2018/04/09/this-week-in-dose-response-1/">
<title type="text">This Week in Dose Response 1</title>
<link href="https://tryjumping.com/blog/2018/04/09/this-week-in-dose-response-1/" rel="alternate" type="text/html" />
<id>urn:uuid:3d3617d7-022d-3a5f-913e-4404da8fd3fa</id>
<published>2018-04-09T08:18:39+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This Week in Dose Response highlight game changes done in the last week or so. It is inspired by the weekly thread at the &lt;a href=&quot;https://www.reddit.com/r/roguelikedev/&quot;&gt;roguelikedev subreddit&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; is an open-world roguelike where you play an addict)&lt;/p&gt;
&lt;p&gt;Quite an eventful week with a lot of code changes and experimentation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Added an optional SDL2 backend – this should improve things like fullscreen later on
&lt;/li&gt;
&lt;li&gt;
The screen scrolls smoothly when the player gets close to a window edge
&lt;/li&gt;
&lt;li&gt;
The player can now move while animations (screen re-centering or dose explosion) are playing
&lt;/li&gt;
&lt;li&gt;
More gameplay tweaks for Dose strength and tolerance increase
&lt;/li&gt;
&lt;li&gt;
The game is still winnable :)
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The SDL backend and smooth scrolling still have a few bugs, but things look good.&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2017/12/25/dose-response-ported-to-webassembly/">
<title type="text">Dose Response ported to WebAssembly!</title>
<link href="https://tryjumping.com/blog/2017/12/25/dose-response-ported-to-webassembly/" rel="alternate" type="text/html" />
<id>urn:uuid:941dbaf4-a2d1-35dd-8fc0-915509377627</id>
<published>2017-12-25T22:00:00+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;div class=&quot;admonitionblock warning&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Warning&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;em&gt;This post was written at the dawn of Rust&amp;#8217;s WebAssembly support. At a time when no libraries supported it directly. There are now multiple engines (general and geared towards roguelikes) that target games to desktop as well as the web. It is for historical interest only. At the very least you should use WebGL to render graphics.&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Rust now supports compiling to &lt;a href=&quot;https://en.wikipedia.org/wiki/WebAssembly&quot;&gt;WebAssembly (wasm)&lt;/a&gt;. That means you can write Rust code, compile it and run it directly in the browser.&lt;/p&gt;
&lt;p&gt;I planned to wait with looking into it once everything settles down. But then &lt;a href=&quot;https://github.com/richardanaya&quot;&gt;richardanaya&lt;/a&gt; wrote this very simple &lt;a href=&quot;https://github.com/richardanaya/rust-roguelike&quot;&gt;&amp;#8220;roguelike&amp;#8221; example in rust+wasm&lt;/a&gt;. I looked at it, and it was short and clear. Enough to understand what was going on.&lt;/p&gt;
&lt;p&gt;And so I figured maybe I should take a look at what would it take to run &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; on wasm.&lt;/p&gt;
&lt;p&gt;This post documents a process of doing that.&lt;/p&gt;
&lt;p&gt;I had no idea what to expect. Dose Response is not a huge game, but it was not written with the browser in mind and while the game is rather small, it is not a trivial project.&lt;/p&gt;
&lt;p&gt;I wasn’t even sure it was possible to actually do this at this time without a considerable rewrite (which I wasn’t going to do).&lt;/p&gt;
&lt;p&gt;As a warning, there’s a certain amount of cargo-culting involved in this effort. My webdev (js, css, html) knowledge is a bit rusty, I knew next to nothing about wasm, not to mention these fancy modern graphics options such as the Canvas 2D API and WebGL. And it’s not like I’m an FFI/low-level expert either.&lt;/p&gt;
&lt;p&gt;There &lt;em&gt;were&lt;/em&gt; a few things going for this effort, though:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
The game has a support for conditional compilation and switchable backends already
&lt;/li&gt;
&lt;li&gt;
Turns out, we don’t have a lot of direct dependencies (but a bunch of transitive ones)
&lt;/li&gt;
&lt;li&gt;
All the dependencies we do have are in Rust
&lt;/li&gt;
&lt;li&gt;
The graphics is just a grid of characters on the screen – no need to figure out how to do images etc.
&lt;/li&gt;
&lt;li&gt;
The game is single-threaded
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the_plan&quot;&gt;The Plan&lt;/h2&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
Set Rust up for wasm compilation
&lt;/li&gt;
&lt;li&gt;
Compile Dose Response
&lt;/li&gt;
&lt;li&gt;
if it turns out I can’t get it to compile, don’t even mess with the rest
&lt;/li&gt;
&lt;li&gt;
Figure out how to handle the game loop
&lt;/li&gt;
&lt;li&gt;
Figure out input handling
&lt;/li&gt;
&lt;li&gt;
Figure out graphics
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ideally, we would get to a minimal JavaScript core that will call out to Rust for everything without having to make huge changes to our Rust codebase.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;We need rustup and for now, Rust nightly. I’d switched to Nightly months ago because I tried &lt;code&gt;impl Trait&lt;/code&gt; and didn’t want to go back. So that’s all good.&lt;/p&gt;
&lt;p&gt;We need to get the latest nightly and add the wasm target:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ rustup update nightly
$ rustup target add wasm32-unknown-unknown --toolchain=nightly&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;compilation&quot;&gt;Compilation&lt;/h2&gt;
&lt;p&gt;Let’s try to compile it! (this will fail for sure)&lt;/p&gt;
&lt;p&gt;We’ll disable all the optional bits – that includes all graphics backends – so the result would be unplayable even if it did compile. There’s no chance we’ll be able to compile the windowing or opengl dependencies, though, so let’s not even try:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ cargo +nightly build --release --target wasm32-unknown-unknown --no-default-features&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A bunch of stuff failed to compile. I ran &lt;code&gt;cargo update&lt;/code&gt; and tried again to make sure I’m using the latest bits. That could have caused additional breakage (but it didn’t this time) and it did actually get rid of some of the errors.&lt;/p&gt;
&lt;p&gt;But not all of them.&lt;/p&gt;
&lt;h3 id=&quot;crate_investigation&quot;&gt;Crate investigation&lt;/h3&gt;
&lt;p&gt;Now with all the parallel compilation, etc. going around, it was hard to figure out which crates didn’t work and why. So I’ve created a new test project and added my dependencies one by one:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ cd ~/tmp
$ cargo new --vcs git --bin wasm
$ cd wasm/
$ cargo +nightly build --release --target wasm32-unknown-unknown --no-default-features
   Compiling wasm v0.1.0 (file:///home/thomas/tmp/wasm)
    Finished release [optimized] target(s) in 1.59 secs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Okay, it compiles when there are no dependencies! (this is a basic but important thing to establish)&lt;/p&gt;
&lt;p&gt;So now I just added the Dose Response dependencies one by one and tried to compile them to wasm:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;a href=&quot;https://crates.io/crates/bitflags&quot;&gt;bitflags&lt;/a&gt;: no problem
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://crates.io/crates/clap&quot;&gt;clap&lt;/a&gt;: didn’t compile because &lt;a href=&quot;https://crates.io/crates/atty&quot;&gt;atty&lt;/a&gt; didn’t compile. That’s okay, we won’t be parsing the command line arguments in the browser
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://crates.io/crates/rand&quot;&gt;rand&lt;/a&gt;: didn’t compile – this is a problem. We depend heavily on rand
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://crates.io/crates/time&quot;&gt;time&lt;/a&gt;: didn’t compile. I’m only using this for the &lt;code&gt;Duration&lt;/code&gt; struct, so I think I should be able to switch to &lt;code&gt;std::time&lt;/code&gt;. Been meaning to anyway.
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://crates.io/crates/serde&quot;&gt;serde, serde_derive, serde_json&lt;/a&gt;: compiled no problem
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, Clap is not a big deal, Time shoudln’t be either, but Rand is a huge problem.&lt;/p&gt;
&lt;p&gt;I went to look at their repo, thinking about filing an issue when I discovered that the master has fixed this already, it’s not just released on crates.io yet.&lt;/p&gt;
&lt;p&gt;So I tried:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;rand = { git = &quot;https://github.com/rust-lang-nursery/rand&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and &lt;strong&gt;it compiles&lt;/strong&gt; \o/&lt;/p&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
there appears to be a new version of &lt;code&gt;rand&lt;/code&gt; published now, so this should be all good. I haven’t tested it yet.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;So we need to go back to Dose Response, make clap optional and replace the &lt;code&gt;time&lt;/code&gt; crate with &lt;code&gt;std::time&lt;/code&gt;. And use the master version of &lt;code&gt;rand&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;compiling_clap_conditionally&quot;&gt;Compiling clap conditionally&lt;/h3&gt;
&lt;p&gt;We’ll add a new cargo feature called ``cli&#39;&#39;, turn it on by default and delegate our commandline handling there.&lt;/p&gt;
&lt;p&gt;So in &lt;code&gt;Cargo.toml&lt;/code&gt; in the &lt;code&gt;[features]&lt;/code&gt; section:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;default = [&quot;opengl&quot;, &quot;cli&quot;]

cli = [&quot;clap&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And we change the dependency from &lt;code&gt;clap = &quot;2.20.1&quot;&lt;/code&gt; to &lt;code&gt;clap = { version = &quot;2.20.1&quot;, optional = true }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Compiling with &lt;code&gt;cargo check&lt;/code&gt; works. Here’s what happens when you disable the default features though:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;$ cargo check --no-default-features
   Compiling dose-response v0.4.3 (file:///home/thomas/code/dose-response)
error[E0463]: can&#39;t find crate for `clap`
 --&amp;gt; src/main.rs:6:1
  |
6 | extern crate clap;
  | ^^^^^^^^^^^^^^^^^^ can&#39;t find crate

error: aborting due to previous error

error: Could not compile `dose-response`.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The code needs to handle the &lt;code&gt;cli&lt;/code&gt; feature conditionally, too.&lt;/p&gt;
&lt;p&gt;All of our clap usage is contained in &lt;code&gt;src/main.rs&lt;/code&gt;. First, let’s import the crate only when the &lt;code&gt;cli&lt;/code&gt; feature is enabled:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(feature = &quot;cli&quot;)]
extern crate clap;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Okay, now it fails when we try to actually use it:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;$ cargo check --no-default-features
   Compiling dose-response v0.4.3 (file:///home/thomas/code/dose-response)
error[E0432]: unresolved import `clap`
   --&amp;gt; src/main.rs:189:9
    |
189 |     use clap::{App, Arg, ArgGroup};
    |         ^^^^ Maybe a missing `extern crate clap;`?&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There’s a lot of ways to do this, but I’m just going to move all that logic to a separate function and then compile that out.&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(feature = &quot;cli&quot;)]
fn process_cli_and_run_game(
    display_size: point::Point,
    world_size: point::Point,
    map_size: i32,
    panel_width: i32,
    default_background: color::Color,
    title: &amp;amp;str,
    update: engine::UpdateFn&amp;lt;State&amp;gt;,
) {
    use clap::{App, Arg, ArgGroup};

    let matches = App::new(title)
        .author(&quot;Tomas Sedovic &amp;lt;tomas@sedovic.cz&amp;gt;&quot;)
        .about(&quot;Roguelike game about addiction&quot;)
        .arg(
        ...
        )
        .get_matches();

    let state = if let Some(replay) = matches.value_of(&quot;replay&quot;) {
       ...
    };
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And another one for when the cli feature is not enabled:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(not(feature = &quot;cli&quot;))]
fn process_cli_and_run_game(
    _display_size: point::Point,
    _world_size: point::Point,
    _map_size: i32,
    _panel_width: i32,
    _default_background: color::Color,
    _title: &amp;amp;str,
    _update: engine::UpdateFn&amp;lt;State&amp;gt;,
) {
    unimplemented!()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This one is empty for now, but we will use it when running wasm. And the &lt;code&gt;main&lt;/code&gt; function is now just:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;process_cli_and_run_game(display_size, world_size, map_size, panel_width,
                         color::background, title, game::update);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So with this, both &lt;code&gt;cargo check&lt;/code&gt; and &lt;code&gt;cargo check --no-default-features&lt;/code&gt; succeed, though the latter shows a lot of unused code warnings.&lt;/p&gt;
&lt;p&gt;Of course if we try to run it with &lt;code&gt;cargo run --no-default-features&lt;/code&gt; it, we’ll hit the &lt;code&gt;unimplemented!&lt;/code&gt; macro. Normal &lt;code&gt;cargo run&lt;/code&gt; continues to work though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/6a16a6a556faf9fe7c71543e33cde9acc4447a5f&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/6a16a6a556faf9fe7c71543e33cde9acc4447a5f&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;replacing_the_time_crate_with_stdtime&quot;&gt;Replacing the time crate with std::time&lt;/h3&gt;
&lt;p&gt;I’m hoping this will be mostly straightforward, because at least in theory, everything we use from the &lt;code&gt;time&lt;/code&gt; crate should just be in &lt;code&gt;std::time&lt;/code&gt; now.&lt;/p&gt;
&lt;p&gt;Let’s remove &lt;code&gt;time&lt;/code&gt; from &lt;code&gt;Cargo.toml&lt;/code&gt;, compile and try to just replace &lt;code&gt;use time&lt;/code&gt; with &lt;code&gt;use std::time&lt;/code&gt; everywhere.&lt;/p&gt;
&lt;p&gt;That, sadly, didn’t quite work out.&lt;/p&gt;
&lt;p&gt;We’re using two imports from the crate: &lt;code&gt;Duration&lt;/code&gt; and &lt;code&gt;PreciseTime&lt;/code&gt;. &lt;code&gt;std::time&lt;/code&gt; seems to use &lt;code&gt;Instant&lt;/code&gt; in place of &lt;code&gt;PreciseTime&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;time::now&lt;/code&gt; function we use also doesn’t exist, but &lt;code&gt;Instant::now&lt;/code&gt; seems to be the equivalent.&lt;/p&gt;
&lt;p&gt;Next, &lt;code&gt;Duration::milliseconds&lt;/code&gt; is called &lt;code&gt;Duration::from_millis&lt;/code&gt; now.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Duration::zero&lt;/code&gt; is &lt;code&gt;Duration::new(0, 0)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most of the remaining errors were about missing &lt;code&gt;num_milliseconds&lt;/code&gt; and &lt;code&gt;num_microseconds&lt;/code&gt; methods. These, sadly, are not in the standard library, so I just took their implementations from the &lt;code&gt;time&lt;/code&gt; crate:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;/// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: u32 = 1000;
/// The number of nanoseconds in a millisecond.
const NANOS_PER_MILLI: u32 = 1000_000;
/// The number of microseconds per second.
const MICROS_PER_SEC: u64 = 1000_000;
/// The number of milliseconds per second.
const MILLIS_PER_SEC: u64 = 1000;
/// The number of seconds in a minute.


pub fn num_milliseconds(duration: Duration) -&amp;gt; u64 {
    let secs_part = duration.as_secs() * MILLIS_PER_SEC;
    let nanos_part = duration.subsec_nanos() / NANOS_PER_MILLI;
    secs_part + nanos_part as u64
}


pub fn num_microseconds(duration: Duration) -&amp;gt; Option&amp;lt;u64&amp;gt; {
    if let Some(secs_part) = duration.as_secs().checked_mul(MICROS_PER_SEC) {
        let nanos_part = duration.subsec_nanos() / NANOS_PER_MICRO;
        return secs_part.checked_add(nanos_part as u64)
    }
    None
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’ve created a new module called &lt;code&gt;util&lt;/code&gt; and put them in there. Every project should have a &lt;code&gt;util&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;The final missing piece is the &lt;code&gt;strftime&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Turns out, there is one place where we use the date/time functionality as opposed to just tracking time duration. For every game, we create a file that captures the game’s seed and keyboard input so we can replay it later. That file has the current date and time in its name.&lt;/p&gt;
&lt;p&gt;This is mostly used for debugging - if we get an unexpected panic or a weird behaviour, we can just replay the game and inspect it.&lt;/p&gt;
&lt;p&gt;It’s not necessary for wasm (figuring out how to do file-based IO is a whole other kettle of fish) and so we can conditionally compile that out, too.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/386ef64717c8961dcd79165c505e1d96d8bdceca&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/386ef64717c8961dcd79165c505e1d96d8bdceca&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;making_replays_optional&quot;&gt;Making replays optional&lt;/h3&gt;
&lt;p&gt;We need to get the current date &amp;amp; time and then format it.&lt;/p&gt;
&lt;p&gt;There doesn’t seem to be a way to do this in the standard library, so I &lt;em&gt;could&lt;/em&gt; just keep using &lt;code&gt;time&lt;/code&gt; for that, but according to its repo, the crate is now deprecated and they recommend switching to &lt;a href=&quot;https://crates.io/crates/chrono&quot;&gt;chrono&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’ll make the replay functionality optional and start using chrono for literally one line of code. &lt;strong&gt;YAY&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s a new optional dependency: &lt;code&gt;chrono = { version = &quot;0.4.0&quot;, optional = true }&lt;/code&gt; and a new feature to Cargo.toml:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;default = [&quot;opengl&quot;, &quot;cli&quot;, &quot;replay&quot;]

replay = [&quot;chrono&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next, we add the crate in (&lt;code&gt;main.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(feature = &quot;replay&quot;)]
extern crate chrono;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next to fix the compilation error we replace this:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let timestamp = format!(
    &quot;{}.{:03}&quot;,
    time::strftime(&quot;%FT%H-%M-%S&quot;, &amp;amp;cur_time).unwrap(),
    (cur_time.tm_nsec / 1000000)
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;with this:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;use chrono::prelude::*;
let local_time = Local::now();

// Timestamp in format: 2016-11-20T20-04-39.123. We can&#39;t use the
// colons in the timestamp -- Windows don&#39;t allow them in a path.
let timestamp = local_time.format(&quot;%FT%H-%M-%S%.3f&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To make replay optional, I needed to mark the &lt;code&gt;generate_replay_path&lt;/code&gt; function with &lt;code&gt;#[cfg(feature = &quot;replay&quot;)]&lt;/code&gt; and update its return value from &lt;code&gt;PathBuf&lt;/code&gt; to &lt;code&gt;Option&amp;lt;PathBuf&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And create stub that returns &lt;code&gt;None&lt;/code&gt; for the case when the &lt;code&gt;replay&lt;/code&gt; feature is not enabled:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(not(feature = &quot;replay&quot;))]
pub fn generate_replay_path() -&amp;gt; Option&amp;lt;PathBuf&amp;gt; {
    None
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And finally fix the compilation errors by handling the changed return value in the code that actually creates the file.&lt;/p&gt;
&lt;p&gt;That was not actually difficult, though it turns out the whole reeplay file handling is a bit convoluted – I’ll have to go back and clean that up at some point.&lt;/p&gt;
&lt;p&gt;Anyway, we can compile with and witohut default features and &lt;code&gt;make replay&lt;/code&gt; still works!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/f0d387bc4c86b81f9677881e8a2bd8c8ee2fcf09&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/f0d387bc4c86b81f9677881e8a2bd8c8ee2fcf09&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;using_rand_from_git&quot;&gt;Using rand from git&lt;/h3&gt;
&lt;p&gt;We talked about this before, the currently-published version of the &lt;code&gt;rand&lt;/code&gt; crate does not compile under wasm (NOTE: it probably does now), so we need to use the one from master:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;rand = { git = &quot;https://github.com/rust-lang-nursery/rand&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;cargo check&lt;/code&gt; works, so does &lt;code&gt;cargo check --no-default-features&lt;/code&gt; and running the game and replaying it (to verify the random numbers are stable) does as well.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/d1c25ad2dc3d1a6a6475f9be28935ba39f1757b9&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/d1c25ad2dc3d1a6a6475f9be28935ba39f1757b9&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;compiling_dose_response_with_wasm_again&quot;&gt;Compiling dose response with wasm again&lt;/h3&gt;
&lt;p&gt;So all of this was just updating our dependencies. None of this is necessarily a wasted effort (I planned to switch back to &lt;code&gt;std::time&lt;/code&gt; at some point anyway), but the reason for doing it now is so we can do:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ cargo +nightly build --release --target wasm32-unknown-unknown --no-default-features&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;IT COMPILES!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now what?&lt;/p&gt;
&lt;p&gt;The resulting file is in &lt;code&gt;target/wasm32-unknown-unknown/release/dose-response.wasm&lt;/code&gt; and is about 62kb.&lt;/p&gt;
&lt;p&gt;We need to put it inside a webpage somehow and then hook the input and display methods to it.&lt;/p&gt;
&lt;h2 id=&quot;browser&quot;&gt;Browser&lt;/h2&gt;
&lt;p&gt;So before we do that, let’s run the game without the default features to see what happens (it should panic at the not-implemented main section).&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ cargo run --no-default-features&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which it does.&lt;/p&gt;
&lt;p&gt;So let’s try to do the same in a webpage – I’m interested to see what a wasm panic looks like. If the browser doesn’t report anything wrong, we’ll have to tread really carefully.&lt;/p&gt;
&lt;h3 id=&quot;creating_the_webpage&quot;&gt;Creating the webpage&lt;/h3&gt;
&lt;p&gt;So as the first step, let’s just literally copy the entire webpage from the &lt;code&gt;rust-roguelike&lt;/code&gt; repo and run it as is:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/richardanaya/rust-roguelike/blob/fcf6235d46894c8890baa0f9fbf95f490da7d73a/index.html&quot; class=&quot;bare&quot;&gt;https://github.com/richardanaya/rust-roguelike/blob/fcf6235d46894c8890baa0f9fbf95f490da7d73a/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I expect this to fail because our repo does not have the &lt;code&gt;roguelike.wasm&lt;/code&gt; file this webpage looks for.&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ wget &#39;https://raw.githubusercontent.com/richardanaya/rust-roguelike/master/index.html&#39;
$ python -m SimpleHTTPServer&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(tip: &lt;code&gt;python -m SimpleHTTPServer&lt;/code&gt; or &lt;code&gt;python3 -m http.server&lt;/code&gt; will serve your current directory over the port 8000)&lt;/p&gt;
&lt;p&gt;Going to &lt;a href=&quot;http://localhost:8000/&quot; class=&quot;bare&quot;&gt;http://localhost:8000/&lt;/a&gt; loads the webpage (good) and the Python http server shows that it’s trying to load &lt;code&gt;/roguelike.wasm&lt;/code&gt; (also good):&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
127.0.0.1 - - [13/Dec/2017 09:43:52] &quot;GET / HTTP/1.1&quot; 200 -
127.0.0.1 - - [13/Dec/2017 09:43:52] code 404, message File not found
127.0.0.1 - - [13/Dec/2017 09:43:52] &quot;GET /roguelike.wasm HTTP/1.1&quot; 404 -&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The developer console says:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Failed to load resource: the server responded with a status of 404 (File not found)
localhost/:30 Uncaught (in promise) CompileError: WasmCompile: Wasm decoding failed: expected magic word 00 61 73 6d, found 3c 68 65 61 @+0
    at fetch.then.then.bytes (http://localhost:8000/:30:28)
    at &amp;lt;anonymous&amp;gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Fantastic!&lt;/p&gt;
&lt;h3 id=&quot;loading_the_dose_response_binary&quot;&gt;Loading the dose response binary&lt;/h3&gt;
&lt;p&gt;So now I’ll edit the &lt;code&gt;index.html&lt;/code&gt; file to replace &lt;code&gt;fetch(&#39;roguelike.wasm&#39;)&lt;/code&gt; with &lt;code&gt;fetch(&#39;target/wasm32-unknown-unknown/release/dose-response.wasm&#39;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And reload the page.&lt;/p&gt;
&lt;p&gt;It loads, the web server shows no error and the dev console says:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Uncaught (in promise) RuntimeError: unreachable
    at wasm-function[48]:1259
    at wasm-function[1]:38
    at wasm-function[3]:1
    at wasm-function[13]:3
    at wasm-function[4]:464
    at wasm-function[178]:7
    at &amp;lt;anonymous&amp;gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We &lt;strong&gt;do&lt;/strong&gt; get panics!&lt;/p&gt;
&lt;p&gt;Now I want to be 100% sure it’s actually displaying the panic from running our code and not something else related to say loading the wasm code.&lt;/p&gt;
&lt;p&gt;So let’s replace &lt;code&gt;unimplemented!&lt;/code&gt; in &lt;code&gt;process_cli_and_run_game&lt;/code&gt; with: &lt;code&gt;panic!(&quot;Hello World!&quot;);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We need to rebuild the file and reload the page.&lt;/p&gt;
&lt;p&gt;Sadly, that produced an identical output. And trying to compile the debug mode (as opposed to the release one we’ve used so far):&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;$ cargo +nightly build --target wasm32-unknown-unknown --no-default-features --verbose&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;failed with:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;error: Could not compile `dose-response`.

Caused by:
  process didn&#39;t exit successfully: `rustc --crate-name dose_response src/main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=b2748c2fb6d01c53 --out-dir /home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps --target wasm32-unknown-unknown -L dependency=/home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps -L dependency=/home/thomas/code/dose-response/target/debug/deps --extern serde=/home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps/libserde-30f0f596b5a4d830.rlib --extern bitflags=/home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps/libbitflags-d9f60170e8604972.rlib --extern serde_json=/home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps/libserde_json-fbd6e26bf609ef03.rlib --extern serde_derive=/home/thomas/code/dose-response/target/debug/deps/libserde_derive-3f9c1af9677e8a6e.so --extern rand=/home/thomas/code/dose-response/target/wasm32-unknown-unknown/debug/deps/librand-5892cb4bb9295a9c.rlib` (signal: 11, SIGSEGV: invalid memory reference)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Sigh.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There’s another way to test this. If we just remove the panic altogether, the program should run and exit immediately – without any errors.&lt;/p&gt;
&lt;p&gt;Hmmm:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;(index):40 Uncaught (in promise) TypeError: results.instance.exports.start is not a function
    at fetch.then.then.then.results ((index):40)
    at &amp;lt;anonymous&amp;gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Okay, that’s different than the previous one and it appears to be a javascript error rather then a rust/wasm error.&lt;/p&gt;
&lt;p&gt;Time to look at what’s actually going on in &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;.then(results =&amp;gt; {
    results.instance.exports.start(width,height);
    document.body.addEventListener(&quot;keydown&quot;,function(e){
      console.log(&quot;Key Pressed:&quot;+e.keyCode);
      results.instance.exports.key_down(e.keyCode);
    })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It appears to be calling a Rust function called &lt;code&gt;start&lt;/code&gt; which we don’t have. I’ve also only now noticed that the &lt;code&gt;rust-roguelike&lt;/code&gt; repo is set up as a library, not a binary.&lt;/p&gt;
&lt;p&gt;But one step at a time. Let’s create the &lt;code&gt;start&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn start(width: i32, height: i32) -&amp;gt; () {
    // TODO: run the game here
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;no_mangle&lt;/code&gt; bit will make sure that the compiler will export the function with the name you specified. Similarly, &lt;code&gt;extern &quot;C&quot;&lt;/code&gt; will make sure this uses the stable C ABI rather than Rust’s default one which could change. Same thing has to happen if you want to call your Rust function from C, Python or whatever.&lt;/p&gt;
&lt;p&gt;Recompile and reload.&lt;/p&gt;
&lt;p&gt;Aha! No errors!&lt;/p&gt;
&lt;p&gt;Pressing a key results in:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Key Pressed:37
(index):43 Uncaught TypeError: results.instance.exports.key_down is not a function
    at HTMLBodyElement.&amp;lt;anonymous&amp;gt; ((index):43)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which is because the line immediately after calling &lt;code&gt;start&lt;/code&gt; sets up a keyboard listener that tries to call another Rust function called &lt;code&gt;key_down&lt;/code&gt;. Which we don’t have either.&lt;/p&gt;
&lt;p&gt;That’s okay for now.&lt;/p&gt;
&lt;p&gt;Before we go ahead, I tried putting &lt;code&gt;println!(&quot;Hello World!&quot;)&lt;/code&gt; in &lt;code&gt;start&lt;/code&gt; just in case it happened to hook up to the browser’s console.&lt;/p&gt;
&lt;p&gt;It did not. Oh well.&lt;/p&gt;
&lt;p&gt;I also tried to set &lt;code&gt;#[no_mangle]&lt;/code&gt; on &lt;code&gt;main&lt;/code&gt; (to avoid having another entry point), but that didn’t compile. Worth looking into later.&lt;/p&gt;
&lt;p&gt;For now though, it appears that:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
When we include the webassembly file, it gets executed
&lt;/li&gt;
&lt;li&gt;
We can Rust from the browser by using &lt;code&gt;results.instance.exports&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That means we could either just start the game with &lt;code&gt;main&lt;/code&gt; as usual, or we can do nothing in &lt;code&gt;main&lt;/code&gt; and run the game from javascript by calling the &lt;code&gt;start&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;This may have implications on the kind of game loop we’re going to do.&lt;/p&gt;
&lt;p&gt;For now, I’ll just go with the former approach as it’s identical to what we do everywhere else.&lt;/p&gt;
&lt;p&gt;That is: we remove the &lt;code&gt;start&lt;/code&gt; function for now, remove the body of the final &lt;code&gt;then&lt;/code&gt; in the webpage and take it from there.&lt;/p&gt;
&lt;p&gt;So here’s the HTML I’ll be working with for now:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&amp;lt;body&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;script&amp;gt;
var width = 80;
var height = 60;
var squareSize = 10;
var c = document.createElement(&#39;canvas&#39;);
c.width = width*squareSize;
c.height = height*squareSize;
document.body.append(c);

var ctx = c.getContext(&#39;2d&#39;);
ctx.textAlign = &quot;center&quot;;
ctx.font = &#39;12px arial&#39;;

fetch(&#39;target/wasm32-unknown-unknown/release/dose-response.wasm&#39;)
.then(response =&amp;gt; response.arrayBuffer())
.then(bytes =&amp;gt; WebAssembly.instantiate(bytes, {
  env: {
 }
}))
.then(results =&amp;gt; {
    console.log(&quot;The game has finished.&quot;);
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(I’ve left the canvas bit from rust-roguelike in because I’ll need that later anyway)&lt;/p&gt;
&lt;p&gt;If you set &lt;code&gt;main.rs&lt;/code&gt; to exit cleanly, the console will print &lt;code&gt;The game has finished&lt;/code&gt;. If you panic, you’ll see an error instead.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/2b3bd82bac354cca37eef672bd435c9f97b1e595&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/2b3bd82bac354cca37eef672bd435c9f97b1e595&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;game_loop&quot;&gt;Game loop&lt;/h3&gt;
&lt;p&gt;We’ll have to create a new graphics backend (&lt;code&gt;wasm&lt;/code&gt;) and set up the game loop there.&lt;/p&gt;
&lt;p&gt;The way I’d like to do this is (like with all the other backends) is to run the game loop fully inside Rust (in the graphics backend), call out to JS to render what we want and to read the keyboard input.&lt;/p&gt;
&lt;p&gt;I’m not sure whether you can pass structs around (my guess would be no) so the data processing might get a little nasty, but the bigger worry is this:&lt;/p&gt;
&lt;p&gt;Normally, the game runs in a loop that keeps yielding to the operating system when idle. Basically, each frame we process the game logic, draw stuff on the screen and then wait until the next frame is ready. This lets the OS handle input events that we receive next frame.&lt;/p&gt;
&lt;p&gt;I don’t know how to &lt;code&gt;yield&lt;/code&gt; from WebAssembly and my guess would be that if Rust just runs an infinite loop, the browser will lock up.&lt;/p&gt;
&lt;p&gt;Now, my default browser (chromium) has been designed with multiprocessing in mind from the beginning. Each tab runs in a single process so they’re isolated from each other.&lt;/p&gt;
&lt;p&gt;So I have no doubts that this will bring down everything.&lt;/p&gt;
&lt;p&gt;But let’s try it! What happens if we run an infinite loop?&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;process_cli_and_run_game&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;loop {
    println!(&quot;y&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Running this normally &lt;code&gt;cargo run --no-default-features --release&lt;/code&gt; shows that it does &lt;em&gt;not&lt;/em&gt; get optimised away, so let’s load it up in the browser!&lt;/p&gt;
&lt;p&gt;Surprisingly, the browser still seems to respond normally, but looking at the console, it prints no message (implying the program is still running) and &lt;code&gt;htop&lt;/code&gt; shows one of my CPUs pegged to 100% and tied to a &lt;code&gt;chromium-browser&lt;/code&gt; tab. And when I close the tab, it promptly goes away.&lt;/p&gt;
&lt;p&gt;So that’s all good.&lt;/p&gt;
&lt;p&gt;I wonder what happens if I do the same thing in JavaScript.&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;for(;;) {
    console.log(&quot;y&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That does actually lock up the whole browser and peg &lt;strong&gt;all my CPUs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for not letting us down, chromium!&lt;/p&gt;
&lt;p&gt;How &lt;em&gt;do&lt;/em&gt; javascript games implement game loops, then? My guess would be something like &lt;code&gt;document.setInterval(update, dt)&lt;/code&gt; or something which iirc does actually yield the control back to the browser.&lt;/p&gt;
&lt;p&gt;Searching for ``game loop in javascript&#39;&#39; (this is top notch gamedev process right here) yields this MDN document:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Games/Anatomy&quot; class=&quot;bare&quot;&gt;https://developer.mozilla.org/en-US/docs/Games/Anatomy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Which actually suggests using &lt;code&gt;window.requestAnimationFrame&lt;/code&gt;. Fair enough.&lt;/p&gt;
&lt;p&gt;So let’s see what happens there:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;function update() {
    window.requestAnimationFrame(update);
    console.log(&quot;y&quot;);
}
update();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It works! The browser is responsive, the CPU usage did come up (all CPUs, not just one), but not crazily so, and the console is printing our lovely messages.&lt;/p&gt;
&lt;p&gt;But this inverts the control (the game loop is now in javascript rather than rust), and it means now I’d have to call the update function from javascript to rust. Which means writing more JS.&lt;/p&gt;
&lt;p&gt;It’s also complicated because we can’t just be calling the Rust &lt;code&gt;game::update&lt;/code&gt; from JS – it requires the game &lt;code&gt;State&lt;/code&gt; struct which (you guessed it) holds all the game state.&lt;/p&gt;
&lt;p&gt;So I guess we have to keep running the Rust game in a loop somehow and pass data from the JS to it or something?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UGH.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I tried running &lt;code&gt;thread::sleep&lt;/code&gt; in wasm, but that panics.&lt;/p&gt;
&lt;p&gt;Basically, this is a difference between using plain &lt;em&gt;webassembly&lt;/em&gt; which has zero to no runtime and &lt;em&gt;empscripten&lt;/em&gt; which does actually bring in a runtime.&lt;/p&gt;
&lt;p&gt;And everything on the web seems to be just using emscripten even with wasm.&lt;/p&gt;
&lt;p&gt;The rust-roguelike repo keeps all the gamestate in a static variable. I’m not keen about that, but it should work. So we would keep the game loop in JS, but all it would do is call a function that would load the game &lt;code&gt;State&lt;/code&gt; from a &lt;code&gt;static&lt;/code&gt;, run &lt;code&gt;game::update&lt;/code&gt; and then display the results somehow.&lt;/p&gt;
&lt;p&gt;So okay, we’ll drive the game loop from javascript. Rust will expose two functions: &lt;code&gt;initialise&lt;/code&gt; where we set the static data up and &lt;code&gt;update&lt;/code&gt; where we process the game loop.&lt;/p&gt;
&lt;p&gt;So tentatively, this is our new javascript code:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;results.instance.exports.initialise();
console.log(&quot;The game is initialised.&quot;);
function update() {
    window.requestAnimationFrame(update);
    console.log(results.instance.exports.update());
}
update();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And in main.rs we create two functions:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn initialise() {
    // NOTE: at our current font, the height of 43 is the maximum
    // value for 1336x768 monitors.
    let map_size = 43;
    let panel_width = 20;
    let display_size = (map_size + panel_width, map_size).into();
    // NOTE: 2 ^ 30
    let world_size = (1_073_741_824, 1_073_741_824).into();
    let title = &quot;Dose Response&quot;;

    let state = State::new_game(
        world_size,
        map_size,
        panel_width,
        display_size,
        false,  // exit-after
        None,  // replay file
        false,  // invincible
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(this is copied straight from &lt;code&gt;main&lt;/code&gt; and is how we would set the game up. No statics yet, we’ll deal with that later)&lt;/p&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn update() {
    // TODO update a frame here
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When we run this, we get a panic /o\.&lt;/p&gt;
&lt;p&gt;Now this took me a while to figure out (by commenting the code out lines by line), but eventually, I tracked it to two calls of &lt;code&gt;rand::thread_rng&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;thread_rng&lt;/code&gt; just straight-up panics and I think this comes down to the lack of any real OS/runtime in wasm.&lt;/p&gt;
&lt;p&gt;Now in basically everything in Dose Response uses a seeded random generator. We want to be able to do a perfect replay.&lt;/p&gt;
&lt;p&gt;However, to generate the initial seed, we grab a value from &lt;code&gt;rand::thread_rng&lt;/code&gt;. Another option would be to get the seed from the system time.&lt;/p&gt;
&lt;p&gt;If we don’t generate a seed that’s different every time, the game map will be the same on every play through!&lt;/p&gt;
&lt;p&gt;But for now, to test things out, let’s just hardcode the seed:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;//let seed = rand::random::&amp;lt;u32&amp;gt;();
let seed = 1234;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(&lt;code&gt;rand::random&lt;/code&gt; uses &lt;code&gt;thread_rng&lt;/code&gt; internally)&lt;/p&gt;
&lt;p&gt;Next, when we generate a new game tile and it’s a tree (represented by the hash character: &lt;code&gt;#&lt;/code&gt;), we will assign it a random colour to provide a little visual variety.&lt;/p&gt;
&lt;p&gt;Since this had no effect on the gameplay, we just grabbed a random one (in &lt;code&gt;level.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let options = [color::tree_1, color::tree_2, color::tree_3];
*rand::thread_rng().choose(&amp;amp;options).unwrap()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Again, this will need to be handled properly, but to move forward, let’s just replace it with:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;color::tree_1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After those two fixes, we can initialise the game without panics /.&lt;/p&gt;
&lt;p&gt;Let’s try to run the game update function.&lt;/p&gt;
&lt;p&gt;For now, we’ll just put this code in &lt;code&gt;initialise&lt;/code&gt;, right after we define the state just to make sure we’re good to go:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let dt = std::time::Duration::new(0, 0);
let fps = 60;
let keys: Vec&amp;lt;keys::Key&amp;gt; = vec![];
let mouse: engine::Mouse = Default::default();
let mut settings = engine::Settings{ fullscreen: false };
let mut drawcalls: Vec&amp;lt;engine::Draw&amp;gt; = vec![];

let result = game::update(
    &amp;amp;mut state,
    dt,
    display_size,
    fps,
    &amp;amp;keys,
    mouse,
    &amp;amp;mut settings,
    &amp;amp;mut drawcalls,
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(stubbing most of the arguments out for now)&lt;/p&gt;
&lt;p&gt;Sadly, running the update panics too.&lt;/p&gt;
&lt;p&gt;This time it’s with:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;::std::time::Instant::now()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And I remember writing that a lot when we moved from &lt;code&gt;time&lt;/code&gt; to &lt;code&gt;std::time&lt;/code&gt;. And we do use use timers pervasively in the code. There’s probably a way of getting away with them, but for now, I’m just not that into it.&lt;/p&gt;
&lt;p&gt;So that might be it for now.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;(and I have indeed left it here for two days, but it kept bugging me – I really wanted to get this going – so I did a &lt;code&gt;git grep Instant::now&lt;/code&gt; to see how much of a damage this would end up being and it turns out, the game code only uses this in a single place!)&lt;/p&gt;
&lt;p&gt;So let’s just disable that for now.&lt;/p&gt;
&lt;p&gt;I’ve added a new Cargo feature called &lt;code&gt;web&lt;/code&gt; (with no optional crates) and then in &lt;code&gt;timer.rs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;pub struct Stopwatch {
    #[cfg(not(feature = &quot;web&quot;))]
    start: Instant,
}

impl Stopwatch {
    pub fn start() -&amp;gt; Self {
        Stopwatch {
            #[cfg(not(feature = &quot;web&quot;))]
            start: Instant::now()
        }
    }

    pub fn finish(self) -&amp;gt; Duration {
        #[cfg(not(feature = &quot;web&quot;))]
        return Instant::now().duration_since(self.start);

        // TODO: make this work for the web as well!
        #[cfg(feature = &quot;web&quot;)]
        return Duration::new(0, 0);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And after that, the game update function panics no more!&lt;/p&gt;
&lt;p&gt;So we need to figure out how to pass the state to the game. And I really don’t want to have it in the static section.&lt;/p&gt;
&lt;p&gt;It turns out that we can just allocate &lt;code&gt;State&lt;/code&gt; on the heap (which wasm does have available, else all our &lt;code&gt;Vec&lt;/code&gt; allocations would have failed) and just pass the pointer to each &lt;code&gt;update&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;Here’s the new initialise function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn initialise() -&amp;gt; *mut State {
    let mut state = {
        // NOTE: at our current font, the height of 43 is the maximum
        // value for 1336x768 monitors.
        let map_size = 43;
        let panel_width = 20;
        let display_size: point::Point = (map_size + panel_width, map_size).into();
        // NOTE: 2 ^ 30
        let world_size: point::Point = (1_073_741_824, 1_073_741_824).into();
        let _title = &quot;Dose Response&quot;;

        Box::new(State::new_game(
            world_size,
            map_size,
            panel_width,
            display_size,
            false,  // exit-after
            None,  // replay file
            false,  // invincible
        ))
    };

    Box::into_raw(state)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Mostly identical, but we create a pointer (box) of the game state and then return it with &lt;code&gt;into_raw&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That will cause Rust to forget about the memory (i.e. it will not attempt to drop it) and return a raw pointer we pass to javascript.&lt;/p&gt;
&lt;p&gt;And, here’s the update function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn update(state_ptr: *mut State) {
    #[allow(unsafe_code)]
    let mut state: Box&amp;lt;State&amp;gt; = unsafe { Box::from_raw(state_ptr) };

    let dt = std::time::Duration::new(0, 0);
    let display_size = point::Point::new(0, 0);
    let fps = 60;
    let keys: Vec&amp;lt;keys::Key&amp;gt; = vec![];
    let mouse: engine::Mouse = Default::default();
    let mut settings = engine::Settings{ fullscreen: false };
    let mut drawcalls: Vec&amp;lt;engine::Draw&amp;gt; = vec![];

    let result = game::update(
        &amp;amp;mut state,
        dt,
        display_size,
        fps,
        &amp;amp;keys,
        mouse,
        &amp;amp;mut settings,
        &amp;amp;mut drawcalls,
    );

    std::mem::forget(state);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So we receive the raw pointer to &lt;code&gt;State&lt;/code&gt;, reconstruct a &lt;code&gt;Box&lt;/code&gt; from it using &lt;code&gt;Box::from_raw&lt;/code&gt;), call the &lt;code&gt;game::update&lt;/code&gt; method on it and then instruct Rust to forget about it again with &lt;code&gt;mem::forget&lt;/code&gt; so it doesn’t get dropped.&lt;/p&gt;
&lt;p&gt;To make it all work, we now need to pass the pointer around in javascript.&lt;/p&gt;
&lt;p&gt;First, create a global variable called &lt;code&gt;gamestate_ptr&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var gamestate_ptr;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;next, make sure it’s set when calling &lt;code&gt;initialise&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;gamestate_ptr = results.instance.exports.initialise();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and finally, pass it to update:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;function update() {
    window.requestAnimationFrame(update);
    results.instance.exports.update(gamestate_ptr);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Recompile &amp;amp; force refresh the browser window. Everything should still be working!&lt;/p&gt;
&lt;h2 id=&quot;graphics&quot;&gt;Graphics&lt;/h2&gt;
&lt;p&gt;Next, let’s do graphics. Yes, according to the initial plan, keyboard input was to be next, but I won’t believe what we’ve done actually works until I’ve seen it. Also, it’ll be easier to debug input if we can display the results.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;game::update&lt;/code&gt; function in Dose Response populates a &lt;code&gt;Vec&lt;/code&gt; of &amp;#8220;drawcalls&amp;#8221; – structs that instruct the graphics backend what needs to be drawn. It’s just data the backend interprets.&lt;/p&gt;
&lt;p&gt;In our opengl backend, we turn that into a list of vertices and upload those to the GPU.&lt;/p&gt;
&lt;p&gt;I’d like to try doing something similar here because a) that’s how we do it in the other backends; b) it’s how I imagine using WebGL would work: JS to set up the webgl context and Rust/wasm to generate the vertices; and c) I’m interested to know how to pass more complex dynamic data back and forth.&lt;/p&gt;
&lt;p&gt;This is in contrast with the rust-roguelike repo that just has a javascript &lt;code&gt;draw_char&lt;/code&gt; function the Rust/wasm code calls for every glyph it wants to render.&lt;/p&gt;
&lt;h3 id=&quot;reading_vec_from_javascript&quot;&gt;Reading Vec from JavaScript&lt;/h3&gt;
&lt;p&gt;We can worry about handling structured data later. For now, let’s just create a &lt;code&gt;Vec&amp;lt;u8&amp;gt;&lt;/code&gt; in Rust and see if we can read it from JS without copying the whole thing over.&lt;/p&gt;
&lt;p&gt;There’s no way of passing arrays from wasm to js directly (that I know of), so we’ll resort to passing the pointer to the data and its length.&lt;/p&gt;
&lt;p&gt;For now, we’ll just create it on every &lt;code&gt;update&lt;/code&gt; call:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;//  TODO: put the data from real drawcalls here
let js_drawcalls = vec![42; 10];

#[allow(unsafe_code)]
unsafe {
    draw(js_drawcalls.as_ptr(), js_drawcalls.len());
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;draw&lt;/code&gt; is a function we’re going to write in JS to read the data (and ultimately display it on the page).&lt;/p&gt;
&lt;p&gt;To compile this, we need to define &lt;code&gt;draw&lt;/code&gt; as an external/ffi function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;extern {
    fn draw(nums: *const u8, len: usize);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next, we need to define the function in javascript.&lt;/p&gt;
&lt;p&gt;Javascript functions that should be available in wasm go into the &lt;code&gt;env&lt;/code&gt; object in the &lt;code&gt;WebAssembly.instantiate&lt;/code&gt; call. It was empty for now so let’s put &lt;code&gt;draw&lt;/code&gt; in:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  .then(bytes =&amp;gt; WebAssembly.instantiate(bytes, {
    env: {
      draw: function(ptr, len) {
        console.log(&quot;Called draw with ptr:&quot;, ptr, &quot;len:&quot;, len);
      }
    }
  }))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Recompile and reload, we should see something like this:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Called draw with ptr: 1605016 len: 10&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Okay so now we have JavaScript calling Rust and Rust calling JavaScript. How do we get JS to read Rust’s memory?&lt;/p&gt;
&lt;p&gt;Turns out, the entire memory buffer is provided in &lt;code&gt;results.instance.exports.memory.buffer&lt;/code&gt; after the wasm module is instantiated.&lt;/p&gt;
&lt;p&gt;But to make that available to our draw function, we need store it in a global variable.&lt;/p&gt;
&lt;p&gt;So, let’s create a variable that will store the wasm instance:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var wasm_instance;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(this is top level, outside of any function or then calls)&lt;/p&gt;
&lt;p&gt;Then, set it as the first thing in the &lt;code&gt;.then(results =&amp;gt; )&lt;/code&gt; before calling &lt;code&gt;initialise&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;.then(results =&amp;gt; {
  wasm_instance = results.instance;
  gamestate_ptr = results.instance.exports.initialise();
  console.log(&quot;The game is initialised.&quot;);

  ...
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And now we can access the memory buffer in our draw function.&lt;/p&gt;
&lt;p&gt;We can use it to construct a &lt;code&gt;Uint8Array&lt;/code&gt; pointing at the section we want:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;draw: function(ptr, len) {
  console.log(&quot;Called draw with ptr:&quot;, ptr, &quot;len:&quot;, len);

  memory = new Uint8Array(wasm_instance.exports.memory.buffer, ptr, len);
  console.log(&quot;memory:&quot;, memory);

  for(let n of memory.values()) {
    console.log(n);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So passing the memory buffer, pointer and length to &lt;code&gt;Uint8Array&lt;/code&gt; will create a view of that memory. We can then use the &lt;code&gt;values&lt;/code&gt; or &lt;code&gt;entries&lt;/code&gt; methods to iterate over it (or just access it as a normal array).&lt;/p&gt;
&lt;p&gt;Running this will print something like this:&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Called draw with ptr: 1605016 len: 10
memory: Uint8Array(10) [42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
(10) 42&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;By the way, you might be tempted to store a reference to &lt;code&gt;memory.buffer&lt;/code&gt; and use that directly. &lt;strong&gt;Don’t do that&lt;/strong&gt;. As &lt;a href=&quot;https://www.reddit.com/r/rust/comments/7knkrk/wasm_issues_when_using_more_than_one_memory_page/&quot;&gt;I’ve foolishly found out&lt;/a&gt;, if the browser has to allocate a new memory page (1 page is 64k) it will clear the existing memory, allocate the new one somewhere else and update &lt;code&gt;memory.buffer&lt;/code&gt; so your view will be pointing to old, unused and empty section of the memory.&lt;/p&gt;
&lt;p&gt;Make sure you use the fresh &lt;code&gt;memory.buffer&lt;/code&gt; every time you create a view into it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The next step is to populate this vector with actual stuff to draw!&lt;/p&gt;
&lt;p&gt;Since we’ve dealt with lists of &lt;code&gt;u8&lt;/code&gt;, let’s keep doing that for now. Again, to my knowledge, there is no direct mapping between structs and JS objects in the wasm boundary.&lt;/p&gt;
&lt;p&gt;We will ignore the other drawcalls right now and only focus on printing out the characters on the screen. Each character has it’s position (&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates), a glyph and a colour (in RGB).&lt;/p&gt;
&lt;p&gt;As luck would have it, each of our values fit in a &lt;code&gt;u8&lt;/code&gt; in practise!&lt;/p&gt;
&lt;p&gt;The coordinates are roughly 50 x 80, all our glyphs are ASCII (and therefore 0-255) and our colour segments are already stored in &lt;code&gt;u8&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So! We’ll read the drawcalls returned by our &lt;code&gt;update&lt;/code&gt; function and for each push 6 values onto the &lt;code&gt;js_drawcalls&lt;/code&gt; vector:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;// Each &quot;drawcall&quot; will be 6 u8 values: x, y, char, r, g, b
let mut js_drawcalls = Vec::with_capacity(drawcalls.len() * 6);
for dc in &amp;amp;drawcalls {
    match dc {
        &amp;amp;engine::Draw::Char(point, glyph, color) =&amp;gt; {
            assert!(point.x &amp;gt;= 0 &amp;amp;&amp;amp; point.x &amp;lt; 255);
            assert!(point.y &amp;gt;= 0 &amp;amp;&amp;amp; point.y &amp;lt; 255);
            assert!(glyph.is_ascii());
            js_drawcalls.push(point.x as u8);
            js_drawcalls.push(point.y as u8);
            js_drawcalls.push(glyph as u8);
            js_drawcalls.push(color.r);
            js_drawcalls.push(color.g);
            js_drawcalls.push(color.b);
        }
        _ =&amp;gt; {}  // TODO
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ve sprinkled in a few asserts just in case, but like I said, this should all just work.&lt;/p&gt;
&lt;p&gt;Now we need to unpack this in javascript:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;if(len % 6 != 0) {
  throw new Error(&quot;The drawcalls vector must have a multiple of 6 elements!&quot;);
}

for(let i = 0; i &amp;lt; len; i += 6) {
  let x = memory[i + 0];
  let y = memory[i + 1];
  let glyph = String.fromCharCode(memory[i + 2]);
  let r = memory[i + 3];
  let g = memory[i + 4];
  let b = memory[i + 5];
  console.log(&quot;x:&quot;, x, &quot;y:&quot;, y, &quot;glyph:&quot;, glyph, &quot;color:&quot;, [r, g, b]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We do a sanity check on the supplied length and then read the position, character and colour from the vector and print them out.&lt;/p&gt;
&lt;p&gt;A compile and refresh later, the characters printed out on the console consist of &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt; and finally a &lt;code&gt;@&lt;/code&gt; – exactly what we expect \o/.&lt;/p&gt;
&lt;p&gt;Now let’s draw them on the canvas.&lt;/p&gt;
&lt;h3 id=&quot;drawing_on_the_canvas&quot;&gt;Drawing on the canvas&lt;/h3&gt;
&lt;p&gt;We have to update the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; vars to match what we normally use:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var width = 63;
var height = 43;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then copy the canvas drawing lines from the rust-roguelike repo to our draw function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;ctx.fillStyle = `rgb(${r},${g},${b})`;
ctx.clearRect(x * squareSize, y * squareSize, squareSize, squareSize);
ctx.fillText(glyph, x*squareSize + squareSize / 2, y*squareSize + squareSize / 2);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;\o/&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;\o/&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;\o/&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;\o/&lt;/p&gt;
&lt;p&gt;\o/&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;\o/ \o/ \o/&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It actually works. For real.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;first-look.png&quot; alt=&quot;Baby’s First Render&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It doesn’t look good because the font is different and too small and the background colour is white. But it works.&lt;/p&gt;
&lt;p&gt;Wow.&lt;/p&gt;
&lt;p&gt;Awesome.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/10524333b2c80994833d9a6fdd300421fb625626&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/10524333b2c80994833d9a6fdd300421fb625626&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So the rest is mostly just keyboard handling and then a ton of polish.&lt;/p&gt;
&lt;h3 id=&quot;keyboard_input&quot;&gt;Keyboard input&lt;/h3&gt;
&lt;p&gt;We need to read keys from javascript and pass them to the update function. The way all the other backends work is they queue up all the keypresses and then submit the array to update.&lt;/p&gt;
&lt;p&gt;The &amp;#8220;engine&amp;#8221; is not multi-threaded or evented or whatever.&lt;/p&gt;
&lt;p&gt;So let’s record the keys in javascript first.&lt;/p&gt;
&lt;p&gt;We’ll create another global for storing the keys:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var pressed_keys = [];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then in the final block we put this:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;document.addEventListener(&#39;keydown&#39;, (event) =&amp;gt; {
  console.log(event);
  pressed_keys.push(event);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will run the closure every time a key is pushed. We print it out and add it to our queue.&lt;/p&gt;
&lt;p&gt;Now we can refresh the page, press some keys and see what they’re made of in the dev console.&lt;/p&gt;
&lt;p&gt;Now in Dose Response, we’re interested in the what key was pressed and whether any of the &lt;code&gt;shift&lt;/code&gt;, &lt;code&gt;ctrl&lt;/code&gt; or &lt;code&gt;alt&lt;/code&gt; were down at the time.&lt;/p&gt;
&lt;p&gt;So ideally, we’d put something like this to our &lt;code&gt;update&lt;/code&gt; JS function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;for(let key of pressed_keys) {
  wasm_instance.exports.key_pressed(key.key, key.ctrlKey, key.altKey, key.shiftKey);
}
pressed_keys = [];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(expecting we’d have a corresponding &lt;code&gt;key_pressed&lt;/code&gt; function in rust)&lt;/p&gt;
&lt;p&gt;Now that’s all well and good, but the &lt;code&gt;event.key&lt;/code&gt; value is a string, not a number. E.g. pressing the Down key, it says &lt;code&gt;ArrowDown&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is a code value in &lt;code&gt;event.keyCode&lt;/code&gt;, but MDN says that it’s deprecated and that I should use the &lt;code&gt;key&lt;/code&gt; value:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent&quot; class=&quot;bare&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’d rather not use deprecated stuff for new projects so &lt;code&gt;key&lt;/code&gt; with its string value it is. Not to mention &lt;code&gt;keyCode&lt;/code&gt; is apparently system-dependent so it could differ between browsers or even their versions. And while I know that &lt;strong&gt;never happens in web development&lt;/strong&gt;, one can never be too sure.&lt;/p&gt;
&lt;p&gt;I looked into passing a string to Rust, but basically, it involves asking Rust to allocate a bit of memory for the string, copying the string there and passing a pointer to it.&lt;/p&gt;
&lt;p&gt;So instead I decided to build a look up table and pass an integer which is trivial:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;const keymap = {
  ArrowUp: 0,
  ArrowDown: 1,
  ArrowLeft: 2,
  ArrowRight: 3
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then in the &lt;code&gt;update&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;for(let key of pressed_keys) {
  var key_code = -1;
  if(key.key in keymap) {
    key_code = keymap[key.key];
  }
  wasm_instance.exports.key_pressed(
    gamestate_ptr,
    key_code,
    key.ctrlKey, key.altKey, key.shiftKey);
}
pressed_keys = [];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I also pass the gamestate pointer in, so we can add add the keys to our &lt;code&gt;State&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;The rust part is pretty straightforward:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn key_pressed(
    state_ptr: *mut State,
    external_code: i32,
    ctrl: bool, alt: bool, shift: bool
)
{
    #[allow(unsafe_code)]
    let mut state: Box&amp;lt;State&amp;gt; = unsafe { Box::from_raw(state_ptr) };

    let code = match external_code {
        0 =&amp;gt; Some(keys::KeyCode::Up),
        1 =&amp;gt; Some(keys::KeyCode::Down),
        2 =&amp;gt; Some(keys::KeyCode::Left),
        3 =&amp;gt; Some(keys::KeyCode::Right),
        _ =&amp;gt; None,
    };
    if let Some(code) = code {
        state.keys.push(keys::Key { code, alt, ctrl, shift});
    }

    std::mem::forget(state);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We do the same from_raw/forget dance for our state pointer and then we just convert the &lt;code&gt;`key code&#39;&#39; to our `+KeyCode+&lt;/code&gt; struct and push the key to &lt;code&gt;state.keys&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And amazingly, when I compile it and refresh the page, I can move around!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/2741873ff6e34c88b4a5929ca477fc8dea877c7b&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/2741873ff6e34c88b4a5929ca477fc8dea877c7b&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The game is done!&lt;/p&gt;
&lt;p&gt;Well, not quite.&lt;/p&gt;
&lt;h3 id=&quot;not_quite_fixing_time&quot;&gt;Not quite fixing time&lt;/h3&gt;
&lt;p&gt;The first thing I noticed is that when I walk to a dose (represented by a blue &lt;code&gt;i&lt;/code&gt;), the game hangs.&lt;/p&gt;
&lt;p&gt;Now I happen to know that when you use a dose, we play an explosion effect animation and don’t let you move until the animation is finished (basically to prevent that a monster would seemingly move into an explosion). I’ll probably want to rework that, but for now it is what it is.&lt;/p&gt;
&lt;p&gt;And in our update code, we’re not passing the real elapsed time, but rather a &lt;code&gt;Duration::new(0, 0)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Which means the animation never finishes, which means the player can’t move.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;yea I know. dum&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So anyway, a quick fix is just replace that with &lt;code&gt;Duration::new(1, 0)&lt;/code&gt; i.e. pretend that a full second passed between each update.&lt;/p&gt;
&lt;p&gt;Ultimately, we’ll have to pass the correct value there, though.&lt;/p&gt;
&lt;p&gt;After that, the game is somewhat playable: we don’t have the keys to e.g. eat food and we don’t see the explosion animation or any text or UI, but we can use doses, pick stuff up and fight monsters.&lt;/p&gt;
&lt;p&gt;There is one other issue I’ve noticed though:&lt;/p&gt;
&lt;p&gt;When the player goes to the edge of the screen, the game normally re-centers the view around the player. That’s not happening here – the display just stays where it is.&lt;/p&gt;
&lt;p&gt;I’m guessing that’s another animation/timing issue but it might also to do with the effectively disabled stopwatch we did earlier.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/fd8c6ffebbbbd2c80f58da0e2bc22ef47d2ea31b&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/fd8c6ffebbbbd2c80f58da0e2bc22ef47d2ea31b&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So the next steps:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
Pass in the remaining keys
&lt;/li&gt;
&lt;li&gt;
Implement the remaining drawcalls
&lt;/li&gt;
&lt;li&gt;
Detect and pass in the right elapsed time value
&lt;/li&gt;
&lt;li&gt;
Fix the thread_rng &amp;amp; stopwatch code we had to compile out
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;remaining_keys&quot;&gt;Remaining keys&lt;/h3&gt;
&lt;p&gt;I’m not happy about having to maintain a two/way mapping between the keys – in javascript and in rust – and I could use a &lt;code&gt;build.rs&lt;/code&gt; script to generate both. In fact, I may end up doing just that at some point.&lt;/p&gt;
&lt;p&gt;But for now, I’ll just do it manually because it’s faster and there’s a ton of other stuff we’ll want to clean up later anyway. This whole effort is about getting to a working proof of concept as quickly as possible.&lt;/p&gt;
&lt;p&gt;I’m not going to paste the code here, because it’s just two big lookup tables:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/18fd5aab1836520284a4c2c124a158f48f238666&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/18fd5aab1836520284a4c2c124a158f48f238666&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The code is brittle (any rearranging of the &lt;code&gt;KeyCode&lt;/code&gt; enum would mess it up), but it does actually seem to work.&lt;/p&gt;
&lt;p&gt;We’re also handling the numpad differently. For most keys, we want to use &lt;code&gt;event.key&lt;/code&gt; because it prints out the your keyboard layout says you pressed rather than the physical key on the keyboard.&lt;/p&gt;
&lt;p&gt;This is useful e.g. for the Dvorak users. If they press &lt;code&gt;e&lt;/code&gt; to eat food, they want to do it where their layout says &lt;code&gt;e&lt;/code&gt; is not where it’s on QWERTY.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;event.key&lt;/code&gt; reports the same value for both the numpad and alphanum keys. Dose Response distinguishes between the two however – numpad is for movement and alphanum for using items in the inventory.&lt;/p&gt;
&lt;p&gt;So for those we need to look at &lt;code&gt;event.code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, this would be a &lt;em&gt;perfect&lt;/em&gt; place for a lightweight JavaScript library. Something that would look at a key event in whatever browser it runs – whether it uses the new &lt;code&gt;key&lt;/code&gt; string values or the old &lt;code&gt;keyCode&lt;/code&gt; ones – and convert them to a numerical code that is consistent across all browsers.&lt;/p&gt;
&lt;p&gt;I’m sure something like that exists and I’ll probably go look it up and switch to it later on.&lt;/p&gt;
&lt;p&gt;Anyway though, THIS WORKS. I can play the game using the numpad.&lt;/p&gt;
&lt;p&gt;And while verifying that things such as eating the food work properly is hard (because of the missing graphical information), it does actually seem to function fine.&lt;/p&gt;
&lt;h3 id=&quot;missing_drawcalls&quot;&gt;Missing drawcalls&lt;/h3&gt;
&lt;p&gt;Let’s add the missing drawcalls and show everything we’re supposed to.&lt;/p&gt;
&lt;p&gt;This will also be fiddly because our Rust drawcalls are actually enums of various sizes.&lt;/p&gt;
&lt;p&gt;It might actually be prudent to use some sort of binary encoding that has library support for JS and rust.&lt;/p&gt;
&lt;p&gt;But for now, it’s the quick&amp;amp;dirty solution time!&lt;/p&gt;
&lt;p&gt;We can turn our text rendering to existing char drawcalls so let’s add that first.&lt;/p&gt;
&lt;h4 id=&quot;rendering_text&quot;&gt;Rendering text&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;Draw::Text&lt;/code&gt; enum is not very sophisticated – it just takes a starting position, text to print out and a colour.&lt;/p&gt;
&lt;p&gt;No alignment, font, style or anything fancy like that. The text looks actually horrid (being tied to a grid does that) and it’s something I’ll want to change at some point.&lt;/p&gt;
&lt;p&gt;Anyway we can just go through all the characters and turn them into &amp;#8220;js drawcalls&amp;#8221;.&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&amp;amp;engine::Draw::Text(start_pos, ref text, color) =&amp;gt; {
    for (i, glyph) in text.char_indices() {
        let pos = start_pos + (i as i32, 0);
        assert!(pos.x &amp;gt;= 0 &amp;amp;&amp;amp; pos.x &amp;lt; 255);
        assert!(pos.y &amp;gt;= 0 &amp;amp;&amp;amp; pos.y &amp;lt; 255);
        assert!(glyph.is_ascii());
        js_drawcalls.push(pos.x as u8);
        js_drawcalls.push(pos.y as u8);
        js_drawcalls.push(glyph as u8);
        js_drawcalls.push(color.r);
        js_drawcalls.push(color.g);
        js_drawcalls.push(color.b);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Basically just copy/pasted the code for &lt;code&gt;Draw::Char&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that works! We’re getting some weird text artifacts, but they seem to be something on the canvas side.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/8d0e939dbdc70334c5e72cf5b753ae5d51dc51ca&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/8d0e939dbdc70334c5e72cf5b753ae5d51dc51ca&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;text-with-artifacts.png&quot; alt=&quot;Text with artifacts&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We should probably be clearing it or something.&lt;/p&gt;
&lt;p&gt;Yep, that was it. Putting this in the &lt;code&gt;draw&lt;/code&gt; js function worked:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;ctx.clearRect(0, 0, width * squareSize, height * squareSize);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;text-without-artifacts.png&quot; alt=&quot;Text without artifacts&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I mean, &amp;#8220;worked&amp;#8221;. It still looks bad.&lt;/p&gt;
&lt;h4 id=&quot;rendering_rectangles&quot;&gt;Rendering rectangles&lt;/h4&gt;
&lt;p&gt;Now let’s draw a rectangle. It gets a top-left position, size and colour.&lt;/p&gt;
&lt;p&gt;We can pass that information to the JS and call &lt;code&gt;clearRect&lt;/code&gt; on the canvas context, but actually, I’m now interested how far can we take just using the existing code. So let’s just generate a bunch more empty characters to fill:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&amp;amp;engine::Draw::Rectangle(top_left, dimensions, color) =&amp;gt; {
    if dimensions.x &amp;gt; 0 &amp;amp;&amp;amp; dimensions.y &amp;gt; 0 {
        let rect = rect::Rectangle::from_point_and_size(top_left, dimensions);
        for pos in rect.points() {
            assert!(pos.x &amp;gt;= 0 &amp;amp;&amp;amp; pos.x &amp;lt; 255);
            assert!(pos.y &amp;gt;= 0 &amp;amp;&amp;amp; pos.y &amp;lt; 255);
            js_drawcalls.push(pos.x as u8);
            js_drawcalls.push(pos.y as u8);
            js_drawcalls.push(0);
            js_drawcalls.push(color.r);
            js_drawcalls.push(color.g);
            js_drawcalls.push(color.b);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(note that this will probably be less efficient than passing just the rect info and colour)&lt;/p&gt;
&lt;p&gt;Luckily, we already have a &lt;code&gt;Rectangle&lt;/code&gt; struct that lets us iterate over its points, etc. Why is &lt;code&gt;engine::Draw::Rectangle&lt;/code&gt; using two &lt;code&gt;Point&lt;/code&gt;s instead of a &lt;code&gt;Rectangle&lt;/code&gt;? Because the struct came later and I haven’t updated the code yet.&lt;/p&gt;
&lt;p&gt;We will want to have a special &amp;#8220;glyph&amp;#8221; to denote that we want to fill a rectangle with colour rather than clearing it and drawing a text there.&lt;/p&gt;
&lt;p&gt;We’ll use &lt;code&gt;0&lt;/code&gt; which is nonexistent in Dose Response’s texts.&lt;/p&gt;
&lt;p&gt;We will update our canvas drawing function a little. First, we’ll set &lt;code&gt;glyph&lt;/code&gt; to &lt;code&gt;null&lt;/code&gt; if we get zero, just to make that explicit:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var glyph = null;
if(memory[i + 2] != 0) {
  glyph = String.fromCharCode(memory[i + 2]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then the drawing is now:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;if(glyph === null) {
  ctx.fillStyle = `rgb(${r},${g},${b})`;
  ctx.fillRect(x * squareSize, y * squareSize, squareSize, squareSize);
} else {
  ctx.fillStyle = `rgb(${r},${g},${b})`;
  ctx.fillText(glyph, x * squareSize + squareSize / 2, y * squareSize + squareSize / 2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And voilà! We can see the bar in the top-right corner that shows our state of the mind \o/.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;rectangle-rendering.png&quot; alt=&quot;Rectangle rendering&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The background position and size seems a little off, but we’ll figure that out later.&lt;/p&gt;
&lt;h4 id=&quot;setting_background&quot;&gt;Setting background&lt;/h4&gt;
&lt;p&gt;So next we implement the &lt;code&gt;Background&lt;/code&gt; drawcall. This one is used for the explosion animation as well as highlighting the area where a dose is too strong to resist and the player character has to get to it.&lt;/p&gt;
&lt;p&gt;By now, our drawcall implementation pattern should be clear: re-use the existing JS code as much as we can.&lt;/p&gt;
&lt;p&gt;Basically, this should be the same thing as the &lt;code&gt;Rectangle&lt;/code&gt; call except only do it for a single cell.&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&amp;amp;engine::Draw::Background(pos, color) =&amp;gt; {
    assert!(pos.x &amp;gt;= 0 &amp;amp;&amp;amp; pos.x &amp;lt; 255);
    assert!(pos.y &amp;gt;= 0 &amp;amp;&amp;amp; pos.y &amp;lt; 255);
    js_drawcalls.push(pos.x as u8);
    js_drawcalls.push(pos.y as u8);
    js_drawcalls.push(0);
    js_drawcalls.push(color.r);
    js_drawcalls.push(color.g);
    js_drawcalls.push(color.b);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And that works \o/.&lt;/p&gt;
&lt;p&gt;We still don’t see the explosion animation on using a dose, but we do see the irresistible area.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;background-rendering.png&quot; alt=&quot;Irresistible area visible&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/12225b377068e7774dad3069b04043681e8ac18f&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/12225b377068e7774dad3069b04043681e8ac18f&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;a_slightly_better_time_fix&quot;&gt;A slightly better time fix&lt;/h4&gt;
&lt;p&gt;The animation is easy to fix: it’s because of our still broken &lt;code&gt;dt&lt;/code&gt; value we’re passing to &lt;code&gt;game::update&lt;/code&gt;. The animations are shorter than 1 second so they don’t show up.&lt;/p&gt;
&lt;p&gt;Changing it to &lt;code&gt;Duration::from_millis(100)&lt;/code&gt; makes them show up.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/13a8851341b023e96e384e1264a494ce6c5454b4&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/13a8851341b023e96e384e1264a494ce6c5454b4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(step on the blue &lt;code&gt;i&lt;/code&gt; to see it)&lt;/p&gt;
&lt;h4 id=&quot;sorting_the_drawcalls&quot;&gt;Sorting the drawcalls&lt;/h4&gt;
&lt;p&gt;Now we’re almost there! We have one drawcall to implement (screen fading), but before we get to it, there’s one really obvious thing going on here: our drawcalls are unsorted and they overlap with each other.&lt;/p&gt;
&lt;p&gt;It’s been visible before (if you looked at a food (the &lt;code&gt;%&lt;/code&gt; sign), you could still see the dot &lt;code&gt;.&lt;/code&gt; for an empty tile showing through on the same space) but with the explosions and irresistible areas, it’s really obvious:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;unsorted-drawcalls.png&quot; alt=&quot;Unsorted drawcalls&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is because the drawcalls can theoretically come in any order, but our game assumes that there can only be one glyph on a cell. Similarly, setting a background shouldn’t actually overwrite a glyph that’s been set previously.&lt;/p&gt;
&lt;p&gt;So we just need to sort them. This is actually super easy because we had to do literally the same thing in the opengl/glium backend.&lt;/p&gt;
&lt;p&gt;First I’ve moved it out of the glium backend to make it available everywhere:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/f8acebc2c47cf3e37126d30436d41e4a68619228&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/f8acebc2c47cf3e37126d30436d41e4a68619228&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And then just called it in wasm:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;engine::sort_drawcalls(&amp;amp;mut drawcalls, 0..);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And with that, the ordering-based graphical issues are gone.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/4a1107cbae50819c77739f106f0a64bbb269bbcd&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/4a1107cbae50819c77739f106f0a64bbb269bbcd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We still have the weird rectangular issues, but you should know the mantra now: later.&lt;/p&gt;
&lt;h4 id=&quot;adding_screen_fade&quot;&gt;Adding screen fade&lt;/h4&gt;
&lt;p&gt;Now the final drawcall: &lt;code&gt;Fade&lt;/code&gt;. This is a very important effect that does…&lt;/p&gt;
&lt;p&gt;Screen fading!&lt;/p&gt;
&lt;p&gt;When you get deeper and deeper into the withdrawal, the game gets darker and darker. When you lose, the game briefly fades to white, red or black (depending on the cause of your failure) before showing the game over screen.&lt;/p&gt;
&lt;p&gt;The fact that it’s literally harder to see (and notice some monsters) when being in a withdrawal is one of the earliest design choices I made and I’m still absolutely sticking with it.&lt;/p&gt;
&lt;p&gt;We need to figure out how to do that on the canvas and then figure out how to pass that data through (because that does not fit into the other drawcalls that well).&lt;/p&gt;
&lt;p&gt;I wonder if I can draw a rectangle over the entire screen with a nonzero alpha and implement fading that way?&lt;/p&gt;
&lt;p&gt;Putting this in the JS draw function after we’ve gone through our drawcalls:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;// Test fading
ctx.fillStyle = &quot;rgba(255, 0, 0, 0.5)&quot;;
ctx.fillRect(0, 0, width * squareSize, height * squareSize);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;fading-test.png&quot; alt=&quot;Fading test&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It works! The whole game is still visible, but it’s covered in a translucent red tinge. Spoooooooky!&lt;/p&gt;
&lt;p&gt;So yea that’s how we do it. Now how to pass the fade values through.&lt;/p&gt;
&lt;p&gt;Since our &amp;#8220;graphics data pipeline&amp;#8221; has worked so well so far, I’d still like to keep using it as is.&lt;/p&gt;
&lt;p&gt;If there were more things like fade that don’t map to characters easily, I’d say it’s time to stop, but this is literally the final drawcall.&lt;/p&gt;
&lt;p&gt;So we need to pass in the RGB values as usual (the fade colour), the alpha (fade amount – this is normally a f32 but can be converted to a byte) and we need to indicate that this is indeed a fade not a character render.&lt;/p&gt;
&lt;p&gt;So let’s say this: if both x and y equal to 255 (the highest position value, never used in the game), we’ll do a fade and treat the &amp;#8220;glyph&amp;#8221; as alpha.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;yea yea messy and whatever.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So in &lt;code&gt;draw&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  if(x == 255 &amp;amp;&amp;amp; y == 255) {
    let alpha = memory[i + 2] / 255;  // convert the &quot;alpha&quot; to &amp;lt;0, 1&amp;gt;
    ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`;
    ctx.fillRect(0, 0, width * squareSize, height * squareSize);
  } else if(glyph === null) {
    ctx.fillStyle = `rgb(${r},${g},${b})`;
    ctx.fillRect(x * squareSize, y * squareSize, squareSize, squareSize);
  } else {
    ctx.fillStyle = `rgb(${r},${g},${b})`;
    ctx.fillText(glyph, x * squareSize + squareSize / 2, y * squareSize + squareSize / 2);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ve just added another branch that will take the alpha (stored as a byte value so between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;255&lt;/code&gt;), convert it to a float between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; by using this super clever thing called &lt;strong&gt;math&lt;/strong&gt; and fills the entire screen with it.&lt;/p&gt;
&lt;p&gt;Now for the Rust part:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&amp;amp;engine::Draw::Fade(fade, color) =&amp;gt; {
    assert!(fade &amp;gt;= 0.0);
    assert!(fade &amp;lt;= 1.0);
    // NOTE: (255, 255) position means fade
    js_drawcalls.push(255);
    js_drawcalls.push(255);
    // NOTE: fade value/alpha is stored in the glyph
    js_drawcalls.push(((1.0 - fade) * 255.0) as u8);
    js_drawcalls.push(color.r);
    js_drawcalls.push(color.g);
    js_drawcalls.push(color.b);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And it works!&lt;/p&gt;
&lt;p&gt;So that’s all drawcalls done!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/4eff11c4f1a6a644603401f6c2fd6dc31543eafe&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/4eff11c4f1a6a644603401f6c2fd6dc31543eafe&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;passing_the_correct_time_delta&quot;&gt;Passing the correct time delta&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;window.requestAnimationFrame&lt;/code&gt; function apparently passes a timestamp to the update function. Let’s use it!&lt;/p&gt;
&lt;p&gt;Changing our js &lt;code&gt;update&lt;/code&gt; function signature to:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;function update(timestamp) {
   ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;timestamp&lt;/code&gt; is the total number of elapsed milliseconds. We want to calculate how much elapsed since the last time we called &lt;code&gt;update&lt;/code&gt; so we want to store the timestamp of the previous frame:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;var previous_frame_timestamp = 0;

function update(timestamp) {
  window.requestAnimationFrame(update);
  let dt = timestamp - previous_frame_timestamp;
  previous_frame_timestamp = timestamp;
  console.log(dt);

  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So we store the previous timestamp, calculate the delta time, print it out and update the previous frame timestamp.&lt;/p&gt;
&lt;p&gt;When I run this, I get a steady stream of 16-ish milliseconds, i.e. 60 FPS.&lt;/p&gt;
&lt;p&gt;Dose Response will be a &lt;strong&gt;Real PC Game For Real PC Men&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let’s pass that value to Rust now by adding it to the wasm update call:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;results.instance.exports.update(gamestate_ptr, dt);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And in Rust, change our update function to:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern &quot;C&quot; fn update(state_ptr: *mut State, dt_ms: u32) {
    #[allow(unsafe_code)]
    let mut state: Box&amp;lt;State&amp;gt; = unsafe { Box::from_raw(state_ptr) };


    let dt = std::time::Duration::from_millis(dt_ms as u64);

    ...

    let result = game::update(
        &amp;amp;mut state,
        dt,
        display_size,
        fps,
        &amp;amp;keys,
        mouse,
        &amp;amp;mut settings,
        &amp;amp;mut drawcalls,
    );&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;i.e. we’ve added the &lt;code&gt;dt_ms&lt;/code&gt; argument to our update function&lt;/p&gt;
&lt;p&gt;Now I’m not a member of the &lt;a href=&quot;https://en.wikipedia.org/wiki/PC_Master_Race&quot;&gt;PC MASTER RACE&lt;/a&gt; so I honestly can’t say whether it’s any good, but the animations do feel a little smoother and hey, I’ve just noticed that the screen scrolls correctly when we get to the edge.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/61c5025da235683dfaf39046381e65a193ffc87a&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/61c5025da235683dfaf39046381e65a193ffc87a&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And that’s basically it! The game is now fully playable although it looks like ass.&lt;/p&gt;
&lt;p&gt;And there are the a few time and randomness things we’ve commented out in order to proceed with the rest of the game. Now’s a good time to resolve them:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
Random seeds
&lt;/li&gt;
&lt;li&gt;
Random tree colours
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Instant::now&lt;/code&gt; in &lt;code&gt;timer::Stopwatch&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;random_seeds&quot;&gt;Random seeds&lt;/h3&gt;
&lt;p&gt;We need to generate the seed in javascript and pass it to rust.&lt;/p&gt;
&lt;p&gt;Javascript/browser has &lt;code&gt;Math.random&lt;/code&gt; which returns a float in the &lt;code&gt;&amp;lt;0, 1&amp;gt;&lt;/code&gt; range.&lt;/p&gt;
&lt;p&gt;Let’s make it available in Rust by adding this to our &lt;code&gt;env&lt;/code&gt; object alongside draw:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;env: {
  random: Math.random,
  draw: function(ptr, len) {
    // ...
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Next, add it to the extern block in main.rs:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;extern {
    fn draw(nums: *const u8, len: usize);
    fn random() -&amp;gt; f32;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then add a new &lt;code&gt;random_seed&lt;/code&gt; function with conditional implementation for wasm and non-wasm:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;#[cfg(not(feature = &quot;web&quot;))]
pub fn random_seed() -&amp;gt; u32 {
    rand::random::&amp;lt;u32&amp;gt;()
}

#[cfg(feature = &quot;web&quot;)]
pub fn random_seed() -&amp;gt; u32 {
    #[allow(unsafe_code)]
    // NOTE: this comes from `Math.random` and returns a float in the &amp;lt;0, 1&amp;gt; range:
    let random_float = unsafe { ::random() };
    (random_float * ::std::u32::MAX as f32) as u32
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And finally use it in &lt;code&gt;state.rs&lt;/code&gt;’ &lt;code&gt;new_game&lt;/code&gt; instead of the hardcoded value:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let seed = util::random_seed();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And now the game is different every time you play it!&lt;/p&gt;
&lt;p&gt;I think ultimately, it would be good to move anything that’s talking to the outside world (like randomness, getting current time, display, input etc.) to isolated modules and keeping everything else &amp;#8220;pure&amp;#8221; not in the functional sense but rather being isolated from the OS.&lt;/p&gt;
&lt;p&gt;We’re kind of close to being there – and wasm actually helped us to discover the areas where we weren’t – but yea code like this should probably not be tucked away in utils.&lt;/p&gt;
&lt;p&gt;Anyways, another thing to do later.&lt;/p&gt;
&lt;p&gt;So that’s random seeds done.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/fdbc828503b8cd0583852f4ca732e1f9455555b3&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/fdbc828503b8cd0583852f4ca732e1f9455555b3&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;fixing_starting_a_new_game&quot;&gt;Fixing starting a new game&lt;/h3&gt;
&lt;p&gt;Before we get to the other two options I’ve realised something though: we’re never testing the &amp;#8220;start a new game after the existing one&amp;#8221; functionality in wasm. That’s because it’s mapped to the F5 key which means &amp;#8220;reload this page&amp;#8221; in most browsers.&lt;/p&gt;
&lt;p&gt;So let’s remap it to the &lt;code&gt;N&lt;/code&gt; key. Although we have to be careful because that key is also used for movement.&lt;/p&gt;
&lt;p&gt;So we update the message in &lt;code&gt;render.rs&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let keyboard_text = &quot;[N] New Game    [Q] Quit&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then in game.rs update:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;if state.keys.matches_code(KeyCode::F5) ||
state.endgame_screen_visible &amp;amp;&amp;amp; state.keys.matches_code(KeyCode::N) {
   ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I want to keep the &lt;code&gt;F5&lt;/code&gt; there for starting a new game while playing the current one. Eventually, we’ll probably add a menu of some sort instead.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/0195b2763b4a486478daf4c49cabdc55c6c76ba1&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/0195b2763b4a486478daf4c49cabdc55c6c76ba1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And guess what! Losing a game and pressing &lt;code&gt;N&lt;/code&gt; doesn’t work under wasm but it does in native build. So we need to fix this!&lt;/p&gt;
&lt;p&gt;This is most likely because the wasm &lt;code&gt;update&lt;/code&gt; function ignores the result of the &lt;code&gt;game::update&lt;/code&gt; – which is what controls whether a new game should be started.&lt;/p&gt;
&lt;p&gt;And indeed, we take a result but then don’t do anything with it:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let result = game::update(
    &amp;amp;mut state,
    ...
    &amp;amp;mut drawcalls,
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So yea let’s take a look at the result and restart the game if we get a new state:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;match result {
    game::RunningState::Running =&amp;gt; {}
    game::RunningState::NewGame(new_state) =&amp;gt; {
        *state = new_state;
    }
    game::RunningState::Stopped =&amp;gt; {},
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Easy peasy.&lt;/p&gt;
&lt;p&gt;What’s more, it works :-)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/6707b535ac34bc15a310c7f74cd273b3a6f16a16&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/6707b535ac34bc15a310c7f74cd273b3a6f16a16&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;random_tree_colours&quot;&gt;Random tree colours&lt;/h3&gt;
&lt;p&gt;With that little distraction out of the way, let’s look at our random trees!!&lt;/p&gt;
&lt;p&gt;Problem is this code in &lt;code&gt;level::Tile::new&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let options = [color::tree_1, color::tree_2, color::tree_3];
//*rand::thread_rng().choose(&amp;amp;options).unwrap()
color::tree_1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So I’m not entirely sure what to do here: there’s nothing in the function signature (&lt;code&gt;pub fn new(kind: TileKind) -&amp;gt; Tile&lt;/code&gt;) to let us produce a random-like effect – say if we got the tile’s position or something there, we could at least do something like &lt;code&gt;x * y % 3&lt;/code&gt; or something.&lt;/p&gt;
&lt;p&gt;We could implement our own &amp;#8220;thread_rng&amp;#8221; and we can even do it using the &lt;code&gt;generate_seed&lt;/code&gt; fn from earlier.&lt;/p&gt;
&lt;p&gt;But also, in this game runaway randomness is kind of dangerous because our replays rely on everything being completely deterministic. That wasn’t an issue here because the colour is a purely cosmetic thing. But still. I’d like to make this more explicit now.&lt;/p&gt;
&lt;p&gt;That kind of decision doesn’t belong in the &lt;code&gt;Tile::new&lt;/code&gt; function anyway.&lt;/p&gt;
&lt;p&gt;I’ve replaced it with just:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;impl Tile {
    pub fn new(kind: TileKind) -&amp;gt; Tile {
        let color = match kind {
            TileKind::Empty =&amp;gt; color::empty_tile,
            TileKind::Tree =&amp;gt; color::tree_1,
        };
        Tile {
            kind,
            fg_color: color,
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And we’ll handle the randomness somewhere else.&lt;/p&gt;
&lt;p&gt;The tiles are being created in &lt;code&gt;generators/forrest.rs&lt;/code&gt; in the &lt;code&gt;generate_map&lt;/code&gt; function. So let’s create the different colours there:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let mut tile = Tile::new(kind);
if tile.kind == TileKind::Tree {
    let options = [color::tree_1, color::tree_2, color::tree_3];
    tile.fg_color = *one_off_rng.choose(&amp;amp;options).unwrap();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is where all of our procedural generation happens so it really is the place to do this kind of stuff.&lt;/p&gt;
&lt;p&gt;Also, if we ever want to do say different kinds of forrets (maybe it’s autumn or maybe we’re in a tundra and the colours are different), it makes sense to have that code here anyway.&lt;/p&gt;
&lt;p&gt;I’ve also decided to use a different random generator for this cosmetic stuff. It’s called a &lt;code&gt;one_off_rng&lt;/code&gt; (couldn’t think of a better name – the old programming joke is in full effect) – basically this is the RNG we want to use for things we don’t want to affect the replay.&lt;/p&gt;
&lt;p&gt;(&lt;em&gt;author’s note 2 days later&lt;/em&gt;: &lt;code&gt;throwavay_rng&lt;/code&gt;!)&lt;/p&gt;
&lt;p&gt;The tree colour doesn’t matter much anyway because it’s all static, but if we decided to say insert some randomness into our animations or something, we’d want that anyway. So here goes.&lt;/p&gt;
&lt;p&gt;And that means we’re now passing two RNGs to the &lt;code&gt;generate_map&lt;/code&gt; fn:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;fn generate_map&amp;lt;R: Rng, G: Rng&amp;gt;(rng: &amp;amp;mut R, one_off_rng: &amp;amp;mut G, map_size: Point, player_pos: Point) -&amp;gt; Vec&amp;lt;(Point, Tile)&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and we actually have create the new one. In &lt;code&gt;Chunk::new&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;let mut one_off_rng = chunk.rng.clone();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We just create it there and pass it in. Nothing special. Eventually, I may want to make that part of the &lt;code&gt;Chunk&lt;/code&gt; or even &lt;code&gt;World&lt;/code&gt; or whatever. But because no one cares about this RNG, it can be whatever wherever.&lt;/p&gt;
&lt;p&gt;And that makes our trees marginally more interesting \o/.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;random-trees.png&quot; alt=&quot;Random trees&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/8184ab306f0373b9a136750482e25e7bb740d27a&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/8184ab306f0373b9a136750482e25e7bb740d27a&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;implementing_stopwatch&quot;&gt;Implementing Stopwatch&lt;/h3&gt;
&lt;p&gt;Okay, onto the Stopwatch thing with &lt;code&gt;Instant::now&lt;/code&gt;. No idea what that’s for because all the animations and timing-based things seem to be working fine.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;Oh.&lt;/p&gt;
&lt;p&gt;It’s only used for counting how long the game update and render portions took each frame. The game prints some stats of the slowest frames etc. at the end for me for when I want to tune the performance later on.&lt;/p&gt;
&lt;p&gt;We don’t need that for wasm. I mean, we’ll probably want some wasm profiling later on but for now there’s no way of printing that data anyway, so whatever.&lt;/p&gt;
&lt;p&gt;We are done with the Rust port!!&lt;/p&gt;
&lt;h3 id=&quot;fixing_the_game_look&quot;&gt;Fixing the game look&lt;/h3&gt;
&lt;p&gt;The game still doesn’t look right – I suspect the text position is not quite right – but that’s on the canvas js side of things.&lt;/p&gt;
&lt;p&gt;Here’s a screenshot of the native build:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;native-screenshot.png&quot; alt=&quot;Native screenshot&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And here’s the WebAssembly version:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;wasm-ugly.png&quot; alt=&quot;Wasm ugly screenshot&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We need to fix that.&lt;/p&gt;
&lt;p&gt;Let’s render something we know what it’s supposed to look like at a known place and see what actually happens.&lt;/p&gt;
&lt;p&gt;Put this after the &lt;code&gt;engine::sort_drawcalls&lt;/code&gt; (so we know it shows up):&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;drawcalls.push(engine::Draw::Background((0, 0).into(), color::Color{r: 255, g: 0, b: 0}));
drawcalls.push(engine::Draw::Char((0, 0).into(), &#39;X&#39;, color::Color{r: 0, g: 0, b: 0}));

drawcalls.push(engine::Draw::Background((1, 1).into(), color::Color{r: 255, g: 255, b: 255}));
drawcalls.push(engine::Draw::Char((1, 1).into(), &#39;X&#39;, color::Color{r: 0, g: 0, b: 0}));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ll draw a black &lt;code&gt;X&lt;/code&gt; on a red background on the &lt;code&gt;[0, 0]&lt;/code&gt; coordinates and another one on a white background at &lt;code&gt;[1, 1]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And the letters are definitely not positioned correctly, but I can’t tell whether the backgrounds are of the correct size and shape.&lt;/p&gt;
&lt;p&gt;So I took a screenshot and inspected it in &lt;a href=&quot;https://www.gimp.org/&quot;&gt;GIMP&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The tiles are indeed square and of correct size and position. It’s the text that’s off.&lt;/p&gt;
&lt;h4 id=&quot;fixing_glyph_position&quot;&gt;Fixing glyph position&lt;/h4&gt;
&lt;p&gt;I just copied that bit of rendering from rust-roguelike and it looks like it might not work for us. Also, I’ve changed the font size.&lt;/p&gt;
&lt;p&gt;Anyway here’s how each character was rendered:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;ctx.fillText(glyph, x * squareSize + squareSize / 2, y * squareSize + squareSize / 2);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So I’m guessing this &lt;code&gt;+ squareSize / 2&lt;/code&gt; bit at the end is the problem.&lt;/p&gt;
&lt;p&gt;When I removed it from both coordinates the text went a lot further up and to the left almost outside the correct coordinates. So there clearly is a need for this, it’s just that the &lt;code&gt;half tile size&lt;/code&gt; fudge is not quite correct.&lt;/p&gt;
&lt;p&gt;Looking at the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillText&quot;&gt;ctx.fillText documentation&lt;/a&gt; didn’t help much, so it seems I’m going to have to fudge this too for now.&lt;/p&gt;
&lt;p&gt;Just in case this is font-dependent though, I’d like to make sure we use the right font, first. So I don’t have to redo it when I make the switch.&lt;/p&gt;
&lt;p&gt;So let’s set the font now!&lt;/p&gt;
&lt;p&gt;We already have the font under &lt;code&gt;fonts/mononoki-Regular.ttf&lt;/code&gt; so it’s just a matter of loading it up in the CSS:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;@font-face {
  font-family: &#39;mononoki&#39;;
  font-style: normal;
  font-weight: 400;
  src: local(&#39;mononoki&#39;), url(&#39;fonts/mononoki-Regular.ttf&#39;) format(&#39;truetype&#39;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then using it in the canvas:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;ctx.font = &#39;16px mononoki&#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And looks like the position is the same. So let’s do some trial and error!&lt;/p&gt;
&lt;p&gt;In the end, this is what I went with:&lt;/p&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;highlight&quot;&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;let x_fudge = 8;
let y_fudge = 13;
ctx.fillText(glyph, x * squareSize + x_fudge, y * squareSize + y_fudge);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I’ve also compared it with the non-web dose response and changed the font size to &lt;code&gt;14&lt;/code&gt;. I still don’t understand how font sizes work when the same number can mean wildly different things but whatever. 14 looks close to the non-web version.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;wasm-fixed-text.png&quot; alt=&quot;Wasm fixed text&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/acc7f3688b6f7abc728db0d2d7534fcc90d39d9b&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/acc7f3688b6f7abc728db0d2d7534fcc90d39d9b&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;fixing_rectangles&quot;&gt;Fixing rectangles&lt;/h4&gt;
&lt;p&gt;And there’s one final thing: our rectangles seem to be 1 tile wider and taller.&lt;/p&gt;
&lt;p&gt;Which is actually a misunderstanding between our &lt;code&gt;Rectangle&lt;/code&gt; struct we used to render these and what the &lt;code&gt;Draw::Rectangle&lt;/code&gt; drawcall means.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;rect::Rectangle&lt;/code&gt; with size &lt;code&gt;1, 1&lt;/code&gt; has four tiles, whereas our drawcall would make that a single tile. That’s actually a bug in &lt;code&gt;rect::Rectangle&lt;/code&gt; now that I think about it (I mean clearly 2x2 does not have a 1x1 size). So let’s fix that.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;wasm-final.png&quot; alt=&quot;Final WebAssembly Screenshot&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tryjumping/dose-response/commit/5f6c04af284af313a4b70126aac3a0c2719d02c0&quot; class=&quot;bare&quot;&gt;https://github.com/tryjumping/dose-response/commit/5f6c04af284af313a4b70126aac3a0c2719d02c0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And after that, it’s all done.&lt;/p&gt;
&lt;p&gt;I’ve played it a bunch and it all seems to be working fine. So that’s awesome.&lt;/p&gt;
&lt;h2 id=&quot;wrapping_up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;I’ve merged it to master and now I’ll go clean up this stream-of-consciousness document.&lt;/p&gt;
&lt;p&gt;Oh actually, I’ve been testing it all in Chromium, should try Firefox, too.&lt;/p&gt;
&lt;p&gt;The initial load is taking forever – about 30 seconds to cromium’s 2ish. Dunno why – but after that, everything seems to be working smoothly, too.&lt;/p&gt;
&lt;p&gt;I thought it might be the initial map generation, but restarting the game once everything loaded was fine, too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So idk.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyway, here’s a list of things I think would make sense to look at going forward:&lt;/p&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
Clean up &lt;code&gt;main.rs&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;
all our wasm code is there
&lt;/li&gt;
&lt;li&gt;
but every other backend is in &lt;code&gt;engine/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
also, how about isolating all OS code (threads, time, randomness) to the backends?
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Reduce allocation costs
&lt;ul&gt;
&lt;li&gt;
we pre-allocate the &lt;code&gt;js_drawcalls&lt;/code&gt; vec but underestimate its size
&lt;/li&gt;
&lt;li&gt;
we don’t pre-allocate &lt;code&gt;drawcalls&lt;/code&gt; at all
&lt;/li&gt;
&lt;li&gt;
we should persist and clear both vectors rather than creating them every frame
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Don’t hardcode the display and font size in js
&lt;/li&gt;
&lt;li&gt;
Use a solid library for getting key events
&lt;ul&gt;
&lt;li&gt;
or at least generate the key code mapping in &lt;code&gt;build.rs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Mouse support
&lt;/li&gt;
&lt;li&gt;
Look at optimizing our canvas use
&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas&quot; class=&quot;bare&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Investigate WebGL
&lt;/li&gt;
&lt;li&gt;
Look at &lt;code&gt;target = &quot;wasm&quot;&lt;/code&gt; for conditional compilation
&lt;ul&gt;
&lt;li&gt;
I forgot that you can actually inspect the target triple for conditional compilation
&lt;/li&gt;
&lt;li&gt;
It’s quite possible we don’t need the ``web&#39;&#39; Cargo feature at all
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Switch to the latest release &lt;code&gt;rand&lt;/code&gt; crate – I think it contains the wasm support now
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Parting thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
This was not that terrible, though knowing what to expect would have been nicer
&lt;/li&gt;
&lt;li&gt;
Achieved minimal disruption of the Rust codebase
&lt;/li&gt;
&lt;li&gt;
The JS stuff is pretty small outside of keymapping
&lt;/li&gt;
&lt;li&gt;
Dose Response (intentionally) does not use singletons or any other fancy stuff – everything is in the game &lt;code&gt;State&lt;/code&gt; and just passed around. This was super helpful here. In fact, the few places where that wasn’t the case (file IO, &lt;code&gt;thread_rng&lt;/code&gt; and &lt;code&gt;Instant::now&lt;/code&gt;) actually hurt us
&lt;/li&gt;
&lt;li&gt;
Passing nontrivial stuff back and forth is kind of messy – try to minimise that as much as you can. Or maybe use proper message passing/encoding.
&lt;/li&gt;
&lt;li&gt;
The keyboard handling on js side could definitely use a nice little library
&lt;/li&gt;
&lt;li&gt;
Barring any future issues, I’ll try to make all my future projects wasm-compatible from the beginning
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Oh and one last thing!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since it is now possible to play this in the browser, I’ve created a website that lets you do that.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/dose-response-roguelike/play/&quot;&gt;Click here to play Dose Response in the browser!&lt;/a&gt;&lt;/p&gt;</content>
</entry>
<entry xml:base="https://tryjumping.com/blog/2016/12/12/introducing-dose-response/">
<title type="text">Introducing Dose Response!</title>
<link href="https://tryjumping.com/blog/2016/12/12/introducing-dose-response/" rel="alternate" type="text/html" />
<id>urn:uuid:7831b386-73a4-3eac-8d8e-57f2f8b08c49</id>
<published>2016-12-12T09:27:41+00:00</published>
<author>
<name>Tomas Sedovic</name>
<email>tomas@sedovic.cz</email>
<uri>https://tomas.sedovic.cz/</uri>
</author>
<content type="html">&lt;p&gt;&lt;em&gt;This post was originally &lt;a href=&quot;https://aimlesslygoingforward.com/&quot;&gt;written on Tomas’ personal blog&lt;/a&gt;. We’re putting it here as it is. &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Head out to the game page to learn more and try it out&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the last few years, I’ve been sporadically working on a little computer game. I wanted to make games ever since I learned how to program. About a decade and a half in, that’s one of the things that still hasn’t changed. I’d written a handful of tiny games (mostly Snake clones), have a bunch of unfinished projects from very early on and a couple of game/educational bits and pieces.&lt;/p&gt;
&lt;p&gt;Apart from my teenage years, I had never sat down and decided to actually design and build my own computer game. Until &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response&lt;/a&gt; came along.&lt;/p&gt;
&lt;p&gt;The original idea (and I think it was inspired by a conversation on the hunger clocks in &lt;a href=&quot;http://www.roguelikeradio.com/&quot;&gt;Roguelike Radio&lt;/a&gt; as well as a few words in &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Fall_(TV_series)&quot;&gt;The Fall&lt;/a&gt;) was this: you play an addict. You need to get your fix to keep going and if you don’t, you die from something akin to &lt;a href=&quot;https://en.wikipedia.org/wiki/Delirium_tremens&quot;&gt;delirium tremens&lt;/a&gt; (or a real delirium tremens if you play an alcoholic). Unlike normal food in roguelikes though: you can die of overdose (and you don’t know how pure each dose is – could be watered-down or really strong) and over time, you develop tolerance, driving you to taking more and stronger stuff.&lt;/p&gt;
&lt;p&gt;And that was basically it – make a game around this concept, change the gameplay depending on whether you’re intoxicated, sober and withdrawn, add interesting systems and see where it ends up.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This is where the game was for a long time. Some reasonably interesting systems and ideas, but I could not figure out how to make a coherent thing out of them. There was a ton of things that needed work – the map generation was literally just randomly placing stuff on the map, the UI needed a ton of work, there were bugs, information that was presented in a confusing manner, etc. etc.&lt;/p&gt;
&lt;p&gt;I could spent ages working on these things, but none of that was related to the actual gameplay and so I worried I’d be wasting time polishing a turd.&lt;/p&gt;
&lt;p&gt;And so the development mostly stopped. I’d still jot down ideas occasionally, but I didn’t know how to actually turn what I had into a real game. I couldn’t even figure out how to add an ending to it.&lt;/p&gt;
&lt;p&gt;If this were a generic fantasy dungeon crawler, you could just add a final level, some tough boss and an item to collect as a placeholder for the real thing. But that wouldn’t exactly fit the addiction theme.&lt;/p&gt;
&lt;p&gt;About a month ago, I was considering just admitting a defeat and scrapping the whole thing. I don’t think there’s any point working on a shit game (unless you have ideas to turn it around), but I was uneasy about giving up on Dose Response because it felt like it hadn’t even had a chance to be a shit game.&lt;/p&gt;
&lt;p&gt;There’s this saying in the software world (and I’ve heard the same thing in the game development circles): release early &amp;amp; release often. But I thought that I should at least wait until I have something that is an actual game before I start showing it around.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Seeing as there was no way for me alone to move forward however, there was little else to do but to talk it through with someone.&lt;/p&gt;
&lt;p&gt;And so I’ve shown the game to my wife (who doesn’t play games, but had a fresh perspective) and to a good friend who does, but isn’t a fan of roguelikes and low-budget graphics. I told them about the current state of the project, what I felt was blocking me and started to listen.&lt;/p&gt;
&lt;p&gt;To my amazement, this actually seemed to work!&lt;/p&gt;
&lt;p&gt;Their comments and suggestions helped me to get my mind unstuck. Not everything was directly applicable or going where I wanted to take the game, but they helped push me in the right direction. Or more importantly &lt;em&gt;a direction&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So I’ve added a few more systems and finally figured out a reasonable placeholder to actually win the game. And after a ridiculous amount of tries, I’ve managed to beat it.&lt;/p&gt;
&lt;p&gt;And that’s where we are now. It’s still incredibly far from anything people might actually be interested in playing (and that’s assuming it will ever end up being fun for anyone other than me), but the whole game feels much more cohesive now and I’ve a few more ideas to make it better.&lt;/p&gt;
&lt;p&gt;And at some point, when I’m reasonably satisfied with the actual gameplay, I’ll start working on polish and all the other things necessary for it to be playable by actual human beings.&lt;/p&gt;
&lt;p&gt;This may all still end badly – the game can turn out to be crap, or I might end up abandoning it or whatever. I will promise no release date or regular updates or anything like that. But it’s actually something that sort of works together and is playable now.&lt;/p&gt;
&lt;p&gt;This is what it looks like:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;./2016-12-14_16-26-54-v0.3.0.png&quot; alt=&quot;Dose Response Roguelike screenshot&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I’ve also updated the &lt;a href=&quot;/dose-response-roguelike/&quot;&gt;Dose Response project page&lt;/a&gt;. Any new information, downloads and whatnot will end up there.&lt;/p&gt;</content>
</entry>
</feed>