Postmortem: Lost in Asterion – js13k 2017

Lost in Asterion is a game I made for the js13k 2017 contest, you can check it out here!

I decided to write one final piece of text about my first participation on the contest. I already described my journey in detail through the 19 days of development here, here and here; but I wanted to record some things earned and some lessons learned which may come in handy for other people or myself in the future

lostInAsterion2

My Story

Whenever I participate into a game jam or contest, I try to ask myself what is my motivation:

  • Learn a new language or tool
  • Create something cool
  • Win the contest prize

This was the first time I participated on the contest so I started a bit clueless, knowing not what to focus on.

Later, I set my goal on trying to create a FULL game, something that you would not believe was contained within 13 kilobytes. I was inspired by Aquaria… could I create a similar experience within the boundaries of the contest? besides the size limit, there was also the time constraint: One month of work, with very limited availability due to some other more important personal projects (it was around the release date of a human being I created). But I jumped in.

In the end, I think I succeeded on that (which is great!) but I cannot deny the results from the judges, which put the game pretty down the list, were pretty disappointing for me at first.

Screen Shot 2017-09-30 at 10.52.14 PM

Later, after giving it some thought, I understood it made sense… there were many entries this year, some of them really good, and when I created my own I didn’t even consider the judging process that was going to take place: I didn’t really aim to make a good impression on the limited time the judges have to check the entries.

Giovanny Beltrán shared some tips, and my opinion in general terms is you need something that grabs the attention of the judges in the first 5 seconds: animations, music, an inviting environment or an intriguing setting.

What went right

A huge world

I managed to create a BIG world, thanks to a couple of things: The cavern level generator which used Voronoi diagramas and Celular Automata, and the compact map format for the 2 areas with fixed maps.

I’m glad one of the jurors got to experience EXACTLY what I was going after! I wanted the players to actually try to make a map of the world, in paper, somewhere. This is why I didn’t include an automap. I followed a similar design on Stygian Abyss, with less exciting results.

A full run through the game may take over 2 hours (may be even more) if you are playing for the first time.

Breaking the pixel art mold

I created another game without using pixel art (a personal goal I’m trying to go after), instead all graphics are vector based. Everything is represented using geometric shapes: the background, the player, the enemies, even the bubble particles.

wp-image-1750981584

Atmosphere and Feel

I managed to create a believable atmosphere using the symbolic vectorial art with a color palette which worked pretty well, as well as the limited sound effects and the textual messages that made up the plot.

Greatest Challenge: The 13k barrier

It hit me REALLY hard and I had to spent a lot of time doing both technical tricks as well as design choices of what to keep and what to take out. I didn’t really expect to have to battle this hard with it since I wasn’t using any image files just to make sure I could have as much space as possible to build the world and the story, but it happened.

The main causes for this were the inclusion of the Voronoi diagrams library (used for map generation and background graphics) and jsfxr (Used for the 2 sound effects in the game).

The first one was completely necessary (no way to remove it) and very hard to reduce size other than trying to optimize the module structure and playing around with the uglifier. I put a lot of work on it with minimal effects over the package size.

As for jsfxr, there was little that could be done other than deciding whether it was worth keeping it or not. Because of the goal I set myself, I decided it had to remain, and I was gonna try to make the most out of it. (In the end I’m not sure it was worth it, since I could only keep two sounds)

Since I couldn’t do much to reduce the size of these two dependencies, I had to start optimizing my code (which was fineΩ) and cutting content (which was painful!)

What went wrong

Removed critical content

I cut some critical training / instructions as well as some interesting plot. People had trouble understanding what the “Drill” was for (and of course instinctively tried to use it to cut the rocks), and the plot was a bit too light.

Looking back at it, I think a better choice would have been removing some type of enemies, or even one of the fixed map areas.

Use the arrows, Z to drill
That’s about all the instructions given to the player

Ran out of time

This is because I didn’t have a clear idea on what to do since the beginning.

However, I’m not sure I’d say that was something bad or it could have been avoided… I think sometimes it’s ok to start with a general idea (2D cavern exploration game, vector art) and then let it evolve.

In any case, I spent a lot of time working on something that didn’t end up in the final product: The “collisions” with slopes. That was educational but would have been better invested on playtesting.

No Playtesting

Due to how the time frame ended, there was no playtesting at all. I was lucky that the game was fairly stable and I only had to submit a single patch, however I missed some details which would have been very easy to correct and could have left a better impression:

  • Scaling to use the whole viewport / going full screen
  • Removing enemies from the starting area so players could read the instructions peacefully and building a better ambient

The Future

This is not the end of the story for Lost in Asterion… I plan to make it evolve into a more complete game, keeping the core design but adding better sound effects, music, a complete plot (based on the original one which was chopped up), cutscenes, boss battles and an infinite exploration mode. More info soon!

Also, some things I want to do next year:

  • An arcade game bringing full action from first second of gameplay
  • Complete music track

Lost in Asterion – js13k 2017 – v0.2 released – final compo update

This is the final update of the development of Lost in Asterion for the 2017 js13kgames contest. I managed to create an interesting exploration game, and I’m pretty happy with the results (check it out here). Giovanny Ramirez created a cover art for it and it’s amazing

Following is the journey thru the last 10 days of development. You can see the previous days here and here.

lostInAsterion2

September 2 – Added enemy support with a single kind of enemy.

Enemies (actually, general “entities”) are updated once on each iteration of the game loop, they have their speed affected by gravity, are checked vs collisions with the world objects (in which case they are completely halted).

Enemies have a simple AI where they check if player is close enough. If that’s so they’ll calculate the direction to the player (in simple manhattan terms, not degrees) and then propel towards the player using they acceleration in x and y.

They are also drawn on each iteration of the game loop, scaling simple geometrical operations based on their size, around a central point.

September 3

Attack enemies using bubble beams: Every time the player presses ‘z’, a bubble beam is created in the direction he is facing. The bubble beam is a group of bubble created in sequence within milliseconds between each one, all originating from the same spot and in the same direction (with slightly different speed).

On each update cycle, entities are checked for collisions with these bubbles, in which case their health is diminished and they are drawn in white for some millis to show they have been hit.

Added sound effects using the jsfxr library. At this point I wasn’t still worried about size. I just added it and used it for movement. The way it works is providing the library with a set of parameters mirroring the configuration of the asfxr player, and they are played using the web audio API.

Also added support for plot messages tied to positions within the world fragments

September 4: Designed and added more plot. Designed the overall world map too.

September 6: After wondering how I’d tackle some variety on the maps, I decided to try to generate then procedurally with a simple “rogue” like 9 interconnected rooms algorithm.

The way it works is a random size is defined for each of these rooms, and some of them may be discarded. Connections are then defined, and then it’s drawn.

While it’s a simple generator, in the middle of implementation I noticed: a.) it was taking too much time to implement, b.) it was eating quite a bit of source code and c.) it wasn’t really worth implementing it since I wanted to have fixed maps in the end (I intended to seed the map generators)

So, I discarded the initial idea and went instead for something completely different. I rendered the maps in a spreadsheet and encoded them as bytes. The map is represented as a bitmask of open/closed spaces, I chunked it in 8 spaces long fragments, and encoded them as an hexadecimal byte representation.

Screen Shot 2017-09-16 at 4.29.19 PM

This allowed me to represent a 24 spaces segment in 6 bytes. The full map for the first temple section, which is 18×24 sectors big, is represented by this string: FFEFFF398FC1018781011C800185C1458DEFFFFDEFFF8187FFE184000084000080FF0184FF0184FF01ECFF03EEFFFF87FF0780FF87FF

When the map generator is creating a fixed map sector, it decodes the String into a boolean mask, and generated solid blocks based on the desired scale.

I used this technique to create the map for the Temple.

September 7

I had a corporate leadership training during the morning. I designed some creatures while waiting for it to develop. All of them using basic shapes.

I was running out of time and the world was not yet ready, so I focused on trying to complete it.

I added some sections requiring the player to have a given orb to pass thru, else player’s speed was drastically affected. This acted as a simple “plot device”, making players have to transverse the map in 3 different “segments”, giving the player a sense of non-linearity while still having some strict control of the game flow.

Added more world content by configuring the map generator for Volcanic Rift (simply using fiery colors for the background) and creating another fixed map for the City Ruins (thus capitalizing on the code added to handle it on the temple ruins).

Having the world definition in a good shape, I continued by adding enemies generation on demand. As the player moves around a sector enemies will be constantly generated off screen up to a given limit.

Finally, I added Game Over flow, the game loop will check if player is dead and render a different screen instead.

September 8

One remaining piece to make the game playable was having a better victory condition, so I worked on adding an end boss. Also started working on support for different kind of enemies.

September 9: Rendered different creatures types based on the designs I had made. Used simple canvas 2d content drawing directives such as fillArc, as well as paths being stroked and filled.

September 10: Assigned enemy level / difficulty based on sector (harder ones as the player progresses).

Also made some missing powerups work: Made the bubble beam work only if the player had the Orb of Verra Kera, and hull recovery only happening if he had the Orb of Gabrielle.

Also added the “title screen” of sorts, and continued polishing the “plot”.

September 11 – Begun the quest to reduce space. Started by questioning myself whether I wanted to keep (and may be even extend) the plot and content OR if I’d rather work towards keeping sound support. I decided for the latter. Started having 2.76 KB of compressed code to take away.

This was extremely painful, some of the things I did were:

  • Ditched the original minified version of the Voronoi library. Instead included the original source code into the minification flow, and removed some parts which were not being used.
  • Move code into data, placing redundant code sections into methods executing batches of operation based on arrays of parameters.
  • Change formatting of definition of function prototypes using Class.prototype = { fn: {} } instead of Class.prototype.fn = function(){}. *
  • Replace all const with var*
  • Reduce HTML infrastructure to a bare minimum, no css nor styles, very plain index.html with no HEAD section or encoding declaration, etc.
  • Remove “use strict” from all modules
  • Shorten plot and ending messages.
  • Move “private” functions outside the functions prototype (effectively allowing uglify to mangle their names)

For the things marked with *, I found of they didn’t really help much in the end since zip compression took care of repeating Strings pretty well. The only thing that helps is actually removing content.

Additionally, I adding the knock back mechanics to make “combat” more interesting (and making the game less hard by allowing player to tackle enemies away). I also added the drill as a default “melee” weapon before acquiring the sonic beam.

September 12 – I was running out of time and hadn’t done proper testing so I released a first version for public testing.

I worked hard to reduce the package size more and more, doing the following:

  • Use the same SFX for the movement fans and for the drill
  • Modularize the Voronoi library. Extracted the different classes used by it on different modules, hoping to refactor them to move private functions from the prototypes into module scope functions. I actually had to roll this back afterwards since the additional module management increased size, but it was helpful to simplify the modules individually and prevent introducing bugs into an unknown code base.
  • Configure uglify to mangle properties starting with underscore (both functions and attributes). This was extremely helpful! I proceeded to use it mainly on the Voronoi library.
  • Cut more plot.
  • Remove unused error message Strings.
  • Ditch the minified jsfxr file and include the already minified source into my own minification process.
  • Merge modules into single files, making the code less readable for now.

Went to bed with 50 bytes left and the plans to finish thru next morning as well as doing some testing…

Then, while already on bed around 1AM, decided to check the deadline and found out it was 13:00 CEST, not Central American Time as I initially thought. That meant it was happening in less than 5 hours. The panic.

There was no way I was going to lose all the time I had invested, so I got up and finished the adventure by completely removing two kind of enemies and cutting the plot text even more.

Lost – js13k 2017 (Update #2)

There’s about one week left for js13k 2017. As usual the jam has sequestered my mind, draining my processing power, thinking about it all day long how to push it further.

Here’s the story from last update, reconstructed from twitter + the git log. It’s been a fun journey so far.

August 19 – Added background stones using Voronoi. Keeping up with the goal of not using pixel art, got the idea from a shower curtain. May need some additional details to make them look like rocks without using textures.

Screen Shot 2017-09-02 at 11.25.29 AM
Walking around alien caverns

August 22 – Infinitely spawning maps, generated on the fly. This was tricky but needed in order to not be completely irresponsible with memory. One of my goals was to create a huge spawning world within the 13k limit, that of course was going to involve procedural generation (but I intend to keep the world fixed by seeding the pRNG properly). For this I’m dividing the map in 4 quadrants, and based on where the player is I clean the opposite sector and generate the closer ones.

August 23 – Implemented a CA module for Voronoi diagrams and used it on terrain and background to smooth them out. I used the output of the Voronoi library and post processed it adding the neighbor sectors. The CA module I made allow simple rules as in “For a cell of given type X, if there are (more/less) than N cells of type Y around, change its type to Z, P% of times”.

Also added a jetpack for easier exploration. I still didn’t have a clue on the theme of the game, was thinking it was may be going to be a space explorer ala Samus Aran.

August 27 – Added complete zoom support for the camera object (still thinking if it’ll be used in game, for now just using it for debugging purposes). All positions and dimensions are scaled based on the zoom factor, and then repositioned based on the camera position (which right now keeps synced with player, but may change that in the future)

August 29 – Worked hard trying to add support for smoothly walking on the slopes. I almost got it but there were some edge cases where the player would become stuck, or go through the slope and into the rock.

The way it worked was by tracing a line between the player’s hitbox center and an imaginary point below representing the gravity drag. Then I checked for the intersection of the polygon sides vs it to see what side was colliding with the player. Previously, I calculated the slope of all sides of the polygons. Then when the player was walking against the polygon, I changed his y position too, based on the slope.

One of the issues was faced was that when walking between stones the player may sometimes hit the wrong polygon side (one inside the rocks) .

August 30 – Figured out the issues with slopes were going to eat up all my time and I wouldn’t ship without them working perfectly. So decided to change theme to underwater caverns.

Tweaked the physics to allow the player to “float” (weaker gravity) as well as removing jumping since you can thrust upwards anytime now.  Initially made a “radial” movement schema where you could rotate and then thrust forward, but then decided to simplify it so you just move in the direction you press the key to. Also changed collisions so you’ll be stopped completely when colliding with anything (removed slope calculations), but they were still a bit buggy at this point.

Screen Shot 2017-09-02 at 11.31.59 AM
Floating in the caverns

August 31 – Up until now, the player had just been a colored squared so I decided to jump into changing it to what it was going to be in the final game. I considered several options from the beginning but since I was not going to use pixel art, adding humanoid characters with animation would have been quite painful, taking a lot of time and I wasn’t confident the end result would look good since I lack the skills. So, give that I had switched the theme to underwater, I decided to use a rigid body (a vehicle).

Did some research on deep exploration vehicles (Bathyscaphes) and in the end settled for a fantasy bathysphere. Also went ahead and added some “bubble” particles, generated from the sphere’s fans depending on the direction the vehicle was moving. Then as a last touch added a simple emulated head light, using a semitransparent white triangle.

September 1 – Started by doing some needed upgrades into the boilerplate project, mainly replacing using the uglify module with uglify-es in order to be able to use ES6 features in the source code.

Then I finally got into fixing the collisions, so right now I’m checking the intersection between the four sides of the player’s “future” hitbox vs the nearest stones, and calling it a collision in case there’s any intersection. I’m also keeping the case of projecting a line from the hitbox center to the future center and checking for intersections, to prevent cases of high y acceleration by gravity. It works pretty well now.

Did some cleanup using jshint and upgraded some parts to ES6 syntax, just for easier maintenance in the future and for the code to look better too 🙂

I got my hands into a more serious high level world layout generation, I designed the fixed world map which is composed by different sections, each section has a given type (which defines the parameters for the sector generator to build the map) as well as expected connections with neighbor sectors.

After the Voronoi diagram has been generated, the generator marks some of the sectors as special types: Unbreakable stones at the borders of the sector, and fixed open spaces representing the connections with its neighbors, these represent the constraints of the sector in order for it to fit the overall map, the CA rules don’t affect them.

I defined the parameters for some of the sector types: The Gate, Caverns, Open Areas, Farmlands and the Darkness Abyss (In which you can only see your headlight)

darkness
The Darkness Abyss

Then I added The Gate and the orbs needed to open it. In order to win the game you have to explore the depths, find the fours orbs and come back to open it, without getting lost in the process.

I also resized the viewport to 800×600 (was 400×400), and modified the physics a bit by generating a bit of “lift” with the vertical movement (akin to the sphere having some kind of “fins”, I guess)

lost
The Gate

Coming up

In order of relevance seeking to make a fun game

  • Enemies
  • Powerups
  • Parallax effect for background
  • Vegetation in the foreground
  • Enhance sector connection
  • Temple generator
  • City Ruins generator
  • Volcanic Ridge generator

 

Lost in the Underworld – Day 1, js13kgames

Alright, I decided to participate for the first time on js13kgames!

The plan is to create a cavern exploration game with a huge world and multiple paths on it, where the player has to find treasures and powerups. I also hope this series of blog posts is more informative and useful than usual.

The idea is to do terrain generation on the fly using Voronoi diagrams and Cellular Automata, also I won’t use pixel art but instead vector graphics (at least for the terrain).

After checking some of the options in the tools page, I decided to use Florent Cailhol’s JS13k Boilerplate. It is probably the simpler starter project there… it has some game loop logic, seedable RNG and gulp scripts for packing and minifying. It also comes with a sample simple implementation for physics.

I started adding keyboard support so you could jump and move around.

const pressed = {};

module.exports = {
	init: function(){
		window.onkeydown = function(e) {pressed[e.keyCode] = true};
		window.onkeyup = function(e) {pressed[e.keyCode] = false};
	},
	isDown: function(keyCode){
		return pressed[keyCode];
	}
}

Also did some foundations of the “physics” system based on the original, since the terrain will be irregular, what I’m doing for the collisions is checking if the future position of the player will be located inside one of the polygons. I used the “inside” function from James Halliday Point in Polygon repo, an implementation of the PNPOLY algorithm. There’s still a lot of potential optimizations to be done.

stones.forEach(function(s){
  if (e.dx != 0){
    if (e.dx > 0){
      if (inside([tx+e.w,ty+e.h/2], s.vs)){
        hCollision = true;
      }
    } else if (e.dx > 0){
      if (inside([tx,ty+e.h/2], s.vs)){
        hCollision = true;
      }
    }
  }
  if (inside([tx+e.w/2,ty+e.h], s.vs)){
    vCollision = true;
  }
}

Had to add a special case for high acceleration caused by gravity, which would make the player go though thing barriers because the updated position would just go through it. For this one I’m checking if the line traced from the current position to the future position intersects the polygon, based on a stack overflow response by Dan Fox.

if (e.dy > 100){
  //Prevent falling through thin borders at high acc
  if (polygonIntersects({
    a: {x: e.x+e.w/2, y: e.y+e.h},
    b: {x: tx+e.w/2, y: ty+e.h}},
    s.vs
  )){
   vCollision = true;
  }
}

Added simple camera support, centered on the player, for this I have a camera object whose position I affect along with the player’s. Then I substract that position from the world position of all objects when it’s time to draw them, to translate them to viewport coordinates.

js13k-2

Then I added super simple Voronoi map gen using Raymond Hill’s JavaScript Voronoi, it adds quite a bit of weight to the package but works pretty nice. I may have to slim it down for the final dist.

js13k-3.1

For now, I’m just randomly picking Voronoi cells, next up will use CA for the caverns to look less random.

var voronoi = new Voronoi();
var bbox = {xl: -300, xr: 1450, yt: 0, yb: 3550};
var sites = [];
for (var i = 0; i < 450; i++){
  sites.push({
    x: rand.range(bbox.xl, bbox.xr),
    y: rand.range(bbox.yt, bbox.yb)
  })
}
var diagram = voronoi.compute(sites, bbox);
const stones = [];
diagram.cells.forEach(function(cell){
  if (rand.bool())
    return;
  let vs = [];
  cell.halfedges.forEach(function (halfedge){
    vs.push([halfedge.getStartpoint().x, halfedge.getStartpoint().y]);
  });
  stones.push({vs: vs});
});

Navigating around the map made evident that my physics system still needs a lot of work. I will post it here once it’s more polished so it can be useful for someone.

I found out the core of the RNG module of the boilerplate isn’t working, so made it use Math.random instead for now. It also seems the current gulp tasks don’t work well with some ES6 syntax, I’ll take care of that later.

Current package size is: 7.13 KB