Random image of Textel, my bat fursona

COBERTOS

LTU Forge Global Games Jam

Participated in my first games jam a couple weeks ago, the LTU Forge Global Games Jam. Super fun, a little stressful at times, but it was so exciting to be able to do it in such a welcoming environment. Coming out of it, I feel inspired and more experienced for having done it. I really want to do another; a feeling similarly expressed by my friends.

Carl Escape is a narritive/dialog based game, so naturally that was the first system we worked on.

Multiple dialog bubbles with focus on the currently talking character was the implementation we went with after a few iterations. Blukat worked on the data structure that backed this one.

Basic dialog

While the final game had only two characters, it allowed for dynamic names, backgrounds, and choices in the dialog tree

Dialog with full artwork

As the art and storyline came in from JD, JabberJaws, and BearAxe, Blukat and I plugged in the assets into the API, everyone coming together when things needed final tweaks. Half way through, the dialog front end was mostly complete so I switched over to working on the minigames.

The core minigame was a simple skill check to test the player during certain decisions of the game.

Quick text effect at the beginning and you get dropped in the game. Hit the green to win. It's faster and the win area smaller for more difficult versions of this game.

Skill check minigame gif showing that you have to stop in the bar in the green area

What was fun about these minigames being independent from the rest of the game is that they can be imported into the core game and placed anywhere. Being PIXI.Containers, they lived right in the scene graph with everything else.

Skill check minigame embeded into the main game

The other minigame started out as a bottle flipping game (I got a little side tracked) but turned into the final game for escaping Carl.

Thanks to some awesome last minute artwork from JD. You put the key in the hole to get back into your hours and escape the antagonist.

Minigame where you have to put the key in the door hole

I'm happy that in the end, the game worked when it was presented to everyone though it did have a bug or two. It works on both mobile portrait and desktop though should be barely playable at any resolution. Really wish I would've thought to use a transform: scale() on the game instead of writing a massive resize method though. I did this for a game at work recently and it was so much less work to set up that the one in Carl Escape.

During/after the jam I wrote down a few points to keep in mind for future projects/game jams:

  • Games jams are an exercise, not a test. This was something I told myself multiple times to lessen the anxiety.
  • Dead simple mechanics are easy to get down and then build on.
  • Narritive stories have tons of boilerplate.
  • Don't get caught up in making "the best game"
  • Trying to act as a leader for the team doesn't really work, it's everyone collective motivation and effort that will push the game over the finish line and really communicate what it's about. It's less anxiety that way too.
  • Parameters like group size, development experience, planning amount, game type, and engine choice/group engine use make quite a difference in how the game will come out.
  • Familiarity tools is essential in allowing people in their roles to be the most efficient with their time.

The other teams put together some really interesting ideas. It's impossible to compare between other's work due to the differences in team structure and team decisions, but I think ours held up well and got some good laughs at the final presentation. So glad to have participated in this!

Read More »

Vue.js render() and $slots; Corrupt DOM

vuevuejsjavascripthtml5htmltemplate$slots

Just ran into an issue today when making a component with a custom render() function and messing around with vnodes passed in via $slots. A seemingly simple template produced really odd results where some DOM elements would disappear, some would be duplicated, some would be out of order, and others would have their inner content ripped out to their outside after a few rerenders. Small template tweaks would also produce vastly different output, sometimes seemingly correct output.

You can see an example in this codepen:

Fix

After hours of debugging I found assigning a v-bind:key to every element fixes it, kind of like how v-for needs a v-bind:key to work properly.

You can do that using this snippet:

{
    created: function(){
        //Give each vnode in your slot a key using forEach index
        this.$slots.default.forEach(function(vNode, index){
            vNode.key = index;
        });
    }
}

Vue's reactivity and element reuse can be seamless and magical for most uses but sometimes it really just bites you in the ass, kind of like this case.

Read More »

Is WebAssembly faster than vanilla Javascript?

webassemblywasmperformancejavascript

I keep seeing GitHub issues of people just like me trying to figure out what WebAssembly (Wasm) and previously asm.js mean for performance-related javascript (in my case, games). WebAssembly should introduce less abstraction between you and the hardware and so your code should in general run faster, right? In reality this question is harder to answer because WebAssembly runs in a Javascript VM-like environment and was not made directly motivated for performance. I'll be putting aside the misinformation and anecdotes to hopefully find out if and how applying Wasm might make your projects more performant.

A bit of background on Wasm

Is%20WebAssembly%20faster%20than%20vanilla%20Javascript%2075a63f0c627a498498088ae744e3c344/2000px-Web_Assembly_Logo.svg-1.png

WebAssembly Logo

Wasm was originally created for so much more than just performance. Wasm is about providing a proper compile target for native code to get into the browser. In the earlier stages of the development cycle, Wasm was actually asm.js, a unofficial JavaScript standard that only supports strict subset of JavaScript to allow native code to compile and run in a JavaScript VM. Wasm is also about providing an environment where multiple sources of code can run safely at a low level where things like memory management and control flow structures (jumping and loops) matter. Already Wasm is doing a ton of things that previously were infeasible or a real pain to do in the browser. (Sourcing a lot of this from this blog post by Adrian Colyer. It's good to keep this in mind while we ask performance only questions.

Wasm loads much quicker than Javascript code in pretty much all cases I've seen that is not really a topic that's up for debate so I'll skip over load performance and focus on runtime performance.

After quite a bit of searching and review, I found a few people who have done research into Wasm's runtime performance specifically by using benchmarks:

  • In a joint Google, Mozilla, Microsoft, and Apple paper (May 2017) (also mentioned in that blog post by Adrian Colyer updating the wider Internet community, Wasm was found to perform close to but still less than C code for runtime of certain benchmarks. Taking test cases from the PolyBenchC library, the paper found that Wasm ran within 2x of native speeds in most cases and for some within 10%. I don't think you're going to get much better than that given the use case of Wasm and it being more abstracted and safe than actual compiled C code. The paper also found that Wasm is 33.7% faster for these same test cases than asm.js (which was already faster than javascript).
  • Alon "Kripken" Zakai, a Mozilla engineer and creator of both Emscripten (LLVM to Javascript compiler) and Ammo.js (port of Bullet Physics to Javascript and Wasm), has also written about Wasm vs asm.js (March 2017), calling out multiple features that Wasm can use over asm.js and the future of what Wasm can add. And while he provides lower estimates (specifically, 5% speedup between Wasm and asm.js) this is due to testing asm.js that was ported to Wasm, and not direct Wasm compilation.
  • The game engine Unity3D has seen improvements in using Wasm in a 2018 benchmark over their 2015 asm.js benchmark. Their 2018 post goes quite into detail over a lot of little changes they've observed.
  • An engineer from Samsung performed a similar benchmark (May 2018) with matrix multiplication, providing multiple implementations with different optimizations. And while he found Wasm to be faster for larger array sizes, he concludes that for normal web development, it's probably smart to stay with normal Javascript for now.
  • One final article to check out.

This gives me a good feeling. Wasm will give you some performance increase but only for applications with datasets that require it. Building websites probably won't be moving to Wasm anytime soon.

For those of us that do want to use Wasm from Javascript for games, realize that Wasm isn't meant for a dynamically-typed, garbage-collected language like Javascript. Typescript gets you closer to a Wasm compatible language but it looks like Javascript has it's own flavor now for Wasm, AssemblyScript, a stricter/modified Typescript. This article discusses other options for running Wasm from Javascript.

Read More »

Chemistory Level and Net Code

chemistory level

Chemistory over the past couple weeks got a few new features, the biggest being an actual level and client/server networking code (or at least the start of it).

netcode-1

There's a separate build for client (Browser) and server (NodeJS), both of which run THREE.js and Oimo.js, though the server doesn't actually render anything. It took a switch to Gulp from Grunt, a pull request to WWOBJLoader2, and heavy use of ifdef-loader but it all actually talks to each other. Next steps are to add boilerplate for RPCs and member syncing and test out a little bit of multiplayer.

I really hope this goes quickly! I want to get back to game play and UI so I can start play-sharing it with my friends.

Read More »

HelloWorld Games Jam Outcome

My current company, HelloWorld, hosted a small games jam after hours. Over the course of 5 days, James (another dev at HW) and I put together two small concepts utilizing a networking engine one of my other coworkers wrote

The original concept for my game was platformer where the player must escape a pool of rising lava and race her friends to some sort of goal. The first step was intergrating the networking engine with THREE.js and physics to get 3D aesthetics and correct movement. The actual gameplay is quite shaky due to integration problems and time limitations.

Once the boilerplate was as complete as it could be, I spent a bit of time throwing together a test level and playtested it with James.

For some added spice, I tried my hand at adding an animated model for the player. THREE.js and Sketchfab made this easier than I expected though I had to use the converted GLTF format SketchFab provides (THREE.js's THREE.FBXLloader doesn't support animations and has other corner case issues).

Given the time constraints this is as far as I got but I say for an 8 hour game jam that's not too bad.

4 of the total 8 hours went into this integration

4 of the total 8 hours went into this integration

Player 2 can be seen stuck on the right side of the screen (mostly due to networking desync)

Player 2 can be seen stuck on the right side of the screen (mostly due to networking desync)

Say hi to Meelo the cat

Say hi to Meelo the cat

Super exciting and I'm looking forward to the next time I get to participate in a games jam. I've been keeping my eye on the The Forge to see if Lawrence Tech will host in 2019 where maybe a few people from HelloWorld can participate.

Read More »

Friends make weird noises

codepenjavascriptexperimentvisualsound

Made this in like 3 hours. Ripped the audio from a video my friend sent me and it felt like a good fit.

Read More »

Automated Memory Leak Testing in the Browser

Large single page web applications have a disadvantage over multi-page applications in that no page reload occurs. This means memory leaks are able to cause more performance problems in single page web applications as the lack of page reloads will not clear the javascript heap. While catching these leaks can be done by manually memory profiling, I will show you an automated test that will give a glimpse at whether memory leaks may be occuring.

The actual test is pretty simple though it requires Chrome to run. This is because Chrome comes with some nifty flags that let in browser tests do things other browsers can't.

  1. Chrome is the only browser that has the ability to read precise memory usage via javascript. This is enabled by the --enable-precise-memory-info flag.
  2. Chrome also is the only browser that allows you to trigger the garbage collector from javascript. This is enabled by the custom javascript flag --js-flags="--expose-gc"

Where I currently work, we use the Karma test runner for testing so setting up different browsers is as easy as installing an npm module and adding the browser to the build with the given flags.

After adding Chrome to your test runner, you will want to add the actual memory test. The memory test consists of a few parts.

  • A header that guards against browsers that don't support the features we need.
const isDef = (o)=>o !== undefined && o !== null;
if (!isDef(window.performance) || !isDef(window.performance.memory)) {
    console.log("Unsupported environment, window.performance.memory is unavailable");
    this.skip(); //Skips test (in Chai)
    return;
}
if (typeof window.gc !== "function") {
    console.log("Unsupported environment, window.gc is unavailable");
    this.skip();
    return;
}
  • A function for getting a memory profile
const getMemoryProfile = ()=>{ 
    window.gc(); //Trigger GC to get precise used memory reading
    return window.performance.memory.usedJSHeapSize; //Return used memory
};
  • An object that tracks memory profiles over time (optional though useful)
const profile = {
    samples: [],
    diffs: [],
    averageUsage: 0,
    averageChange: 0,
    //Collects a sample of memory and updates all the values in the
    //profile object
    sample() {
        const runningAverage = (arr, newVal, oldAvg)=>{
            return ((oldAvg * (arr.length-1) + newVal) / arr.length);
        };

        let newSample = getMemoryProfile();
        this.samples.push(newSample);
        this.averageUsage = runningAverage(this.samples, newSample, this.averageUsage);
        if(sampleLen >= 2) {
            let newDiff = this.samples[sampleLen - 1] - this.samples[sampleLen - 2];
            this.diffs.push(newDiff);
            this.averageChange = runningAverage(this.diffs, newDiff, this.averageChange);
        }
    }
};
  • The portion of your application you want to profile between calls to profile.sample(). In my case, this was the loading of a particularly heavy WebGL scene whereby a 50MB+ model was loaded in addition to many other operations where it would then be "disposed" of and all references to created objects broken (or we hope!).
profile.sample();
//Your test code here!
profile.sample();
  • The test assertions that are specific to the memory requirements of your application. Some sample assertions are given below (in this case using the chai expect framework)
const inMB = (n)=>n/1000000;

//Check average change in memory samples to not be over 10MB
expect(inMB(profile.averageChange).to.be.at.most(10);

//Check the final memory usage against the first usage, there should be little change if everything was properly deallocated
expect(inMB(getMemoryProfile())).to.be.at.most(profile.samples[0] + 0.25);

This test has saved me a couple of times though isn't bullet proof. Chrome and Firefox are very different beasts when it comes to memory management and, with specific "experimental" technologies like WebGL (come on, we already have WebGL2!), Firefox really likes to leak. This is the point where you start using the memory profiling tools native to your browser (Firefox profiler and Chrome Profiler). I prefer Chrome's toolset just because it gives you so much more control but Firefox's will probably get there with time.

Read More »