Postmortem: ArcherFire Duet of Aces – js13k 2018

ArcherFire: Duet of Aces is a game I made for the js13k 2018 contest, you can check it out here! (and the source code is here)

I decided to write one final piece of text about my second participation on the contest. I already described my journey in detail here and here, and also did a dissection of the source code, but I wanted to record some lessons learned which may come in handy for other people or myself in the future.

afdoa

The story

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

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

This was the second time I participated in the contest; results from last year had been a bit disappointing (regarding the ranking given by the jurors), and I knew my development time this year was going to be very limited. Still, I aimed to rank high into the lists.

The theme for this year was OFFLINE, as mentioned in my first blog post, I started off with a vague idea of a space… thing… where you could collaborate with other players offline to advance through the game.

20180913_210742

On the first day of dev, I created some foundations work looking forward to having some kind of space sandbox thing with arcade elements (Similar to this entry, which ended up being one of the contest winners). However, given the constraints I had, I decided to follow my own advice from last year’s postmortem and create:

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

And that’s precisely what I ended up doing! Interestingly, and maybe because of what I set to do and my experience from last year, I didn’t have any issues with the 13KB limit so I didn’t have to cut around any corners. I incorporated the OFFLINE theme by allowing 2 players hot-seat offline play.

However, the results were even less encouraging this year. Despite receiving good feedback from the jurors, the game didn’t even end up in the top 100. (Last year it ended up #40 overall and ranked well in the Community and Social lists). Since this was the first year where some constraints were put on the prizes model (only top 100 entries would get prizes) that meant that effectively I lost the contest. There was a total of 270 entries, and mine ended up ranked #105.

Screen Shot 2018-10-18 at 6.35.57 PM

Unlike last year, this time I don’t really have some big factors I think led to this result. I contented myself in thinking that the jurying process is not perfect, and there may have been very good entries this year. Still, here’s what I think worked and didn’t work.

What went right

  • Seeded Procedural Generation: Managed to create an infinite, increasingly harder, top-down shooter level which was the same every time you played (So, in theory, the more you play the game the more likely you are to memorize the hazards and get farther)
  • Pseudo 3D Effect: Everyone loved how cool the ships looked when soaring around.
  • Straightforward action-packed: The game is pretty responsive and quick, with lots of action on screen. No need to explain anyone how to play because it’s obvious!
  • 2 players hot-seat mode: I couldn’t test this much because I have no friends, but I saw some people have fun and yell at each other afterward.
  • A solid, finished entry: No bugs, no feeling of being an “incomplete game”, it is what it is and it doesn’t break.
  • Music: One of the game highlights, and I didn’t do it myself 😀 it was all thanks to Ryan Malm. I just gave him a reference and some ideas, and he came up with the track. Thanks again!

What went wrong

  • Floaty Controls: Since my foundational work on a simple physics engine had support for acceleration, I stuck to the end with the idea of the ships being “hard to control” as a “challenging aspect” for the player. I knew it was frustrating, but I waged on the players trying harder to learn how to control it. In the end, it ended up being too hard and too different to the standard. A model where the ships had less inertia would have been much more playable and enjoyable. Maybe I need to start making easier games!
  • Balancing: Some people reported the game was a bit too hard. In part, this may be closely related to the controls, but also could have lessened the hit points of the enemies or made the difficulty curve less step.
  • Lack of theme: Yet another space shooter, no plot, maybe went too much into the arcade direction? So that aspect was pretty uninteresting. There were also too few types of enemies, mainly because of the time constraints I had.
  • Graphics too simple: I am not an artist, and the game had high-resolution vector art. Unlike last year where I could go around that by using shadows in the darkness, this year I went for colors and maybe it didn’t look too nice. One thing that could have worked would have been using WebGL filters to post-process the bare graphics, which has worked great for other games in the past.

The Future

This is not the end of the story for Duet of Aces… I plan to make it evolve into a more complete game, keeping the core design but adding better art, sound effects, more music, a complete plot and more importantly, adapting it to social media mobile platforms. More info soon!

Also, some things I want to do next year:

  • An easy game, rewarding players without requiring lots of skill.
  • Gorgeous visuals.

OpenArthurianX6 – SkyBox tweaks

Back to development!

Added a mask for the celestial bodies on the skybox, tried first with a sprite mask but then realized a simple rectangular mask would work just as well.

Next up was sky color, dug up a very old sky color calculator thing done originally for Pixal in 2009

Screen Shot 2018-09-22 at 1.54.11 PM

Also found these notes which seems I used to code it :

atmosphereBase: Universe is black always, right?

lightStrengthForTheHour (Sun)

       0.0 ----------> 0.3 0.7 0.9 ------> 1.0 ------------------> 1.0 ------> 0.9 0.7 0.3 --------->
 HOUR  0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20  21  22  23

baseLight: Stars emit white light.

It seems like the core of the tool is an interpolation function for these values, coupled with some research on how light works in the atmosphere (over-simplified of course). I went ahead and used the original old source code (probably one of my first works in JS) and transformed it into a decent module. It’s now integrated into the engine, in theory, this would allow to change some attributes of the atmosphere and have the color of the sky respond (small details, but it’s fun).

Screen Shot 2018-09-22 at 10.58.53 PM

Also allowed defining items for the NPCs, which allows Shamino to fire arrows.

Been considering how the UI should work (full-screen map vs. a layout similar to U6). For now, I think I’m going to continue on the route to create an exult/nuvie-like layout with floating windows. This also means much smaller reliance on the events log/messages window for things like combat, the damage will instead be shown on screen, for starters.

Another thing I’m considering is merging MobTypes and NPCDefinitions, I see a lot of overlap there, and it’s causing the code to be more complex than it should, what I’m thinking is a single list, so you’ll be able to define what a generic skeleton is, and in the future make spawners for them, but in the same set of definitions you would have for example Shamino, including his full dialog and initial equipment the current way things are laid out you reference a mob type from the npc definitions, but I’m finding out that most of the times you will not reuse an existing mob type….

Unless maybe if we need to have a lot of NPCs, reusing the same basic definition for a “townsman” or “children”… gotta think about this more before making the moves in the code

ArcherFire: Duet of Aces, js13k 2018 source code dissection

JS13k 2018 has gone by! this is the third of a series of posts detailing my journey, as well as the structure of the game I built. You can play it online here!

afdoa

Links to the full series: part1, part2, postmortem

The full source code of the game (github repo), uncompressed and unminified, is 43136 bytes for the single javascript file, plus 349 bytes for the html file. This includes a lot of comments and code that could be written in a more optimal way, which reflects that my biggest restriction this year was not the size, but the time I could invest in the project.

Screen Shot 2018-09-21 at 10.02.50 AM

Following is a summary of the 43136 bytes, which of course could be laid out in a much better, modular way, but were thrown together in a huge file for the sake of reducing overload from webpack for having multiple modules.

So, why do I think this may be relevant? Well, I believe this may be a bare minimum setup to have an arcade game up and running; understanding how these components work together to create the game experience might be helpful to create a more organized structure, without falling on the mistake of over-engineering (start small and simple!).

Also, having them all in a monolithic block creates an implicit graph of dependencies, where the more general purpose components are (generally) defined first, then other code uses them. Here’s a first stab at translating that to a component / class / object diagram.

Screen Shot 2018-09-21 at 10.50.36 AM

With each segment of the source code, I’m including a short description which may give you an idea of the types of components in play for the game, here we go!

  • Soundbox player (11879 bytes): Pasted from here, this is the code that interprets the song “script” and transforms it into a WAV stream.
  • Theme song (5148 bytes): Created by Ryan Malm, it’s exported from Soundbox online player.
  • SFXR player lib (2637 bytes): Minified form of the original source code here, this code allows playing SFXs based on a list of settings
  • Initialization function (466 bytes): Creation of the music player and the WAV stream from the song script.
  • Sound data for SFXR (484 bytes): 5 different sound effects represented by SFXR instructions (Explosion, Bullet, Missile, Super Explosion, Start Game Beep)
  • SFX playback functions (359 bytes): Preload Audio objects from SFXR sound data and allows easy playback.
  • pRNG functions (719 bytes): Functions to generate random numbers, including the seedable pRNG.
  • Keyboard input routine (533 bytes): Some hooks around keypress and keydown to allow polling for the state of a key or add a listener function.
  • Shape renderer (1765 bytes): Given a canvas rendering context, a set of “shape instructions”, a position and a scale value, translate the simplified instructions into Canvas 2D API operations.
  • Mob class (887 bytes): Model the basic things moving around in the world, every Mob has an appearance, speed, and position in the x and y axis. This class also includes functions to update the mob, destroy it and check collisions with other mobs, as well as the creation of explosions.
  • RAF function (401 bytes): Function that allows hooking other functions into an animation frame, doing the fundamental calculations for the elapsed time between frames which are used to (try to) keep things running at a constant speed regardless of where they are run.
  • Collision functions (177 bytes): Simple collision checks based on the Manhattan distance between two mobs and their size.
  • Game Loop (1952 bytes): Keeps tracks of different list of mobs, used for both updating them on each animation frame, as well as rendering them on screen. It also keeps tracks of the animation-based Timers
  • LCD-like number rendering (805 bytes): Allows drawing any number as an LCD-like display.
  • UI Rendering (1371 bytes): Depending on the current state of the game, might draw the loading message, or the title screen, or the HUD including the scores and the current wave, or the Game Over message.
  • Enemy Factory (2318 bytes): Contains the stats for the different kind of enemies, as well as function to create groups of them in a given initial setup. For example you can request the factory to create 5 mines in horizontal formation at y = 200
  • Player Ship class (2356 bytes): Extends Mob, has special checks on its update function to simulate inertia as well as handle the practical “3d” effect when moving around and keeping the player ships on-screen. Of course, it also includes functions to control the movement of the ship using the keyboard (the actual keys that are used are received as a parameter, which means there could potentially be more than 2 players on screen). Also allows firing missiles, and keeps track of a player’s score.
  • Enemy class (1208 bytes): Extends Mob, has a simple “reaction” model which allows it to potentially fire a bullet at the player each x milliseconds. The speed of the bullet on each axis is calculated using the arc-tangent between the target and the enemy. The target is selected from the list of players (the closest one)
  • Star class (304 bytes): Extends Mob refining the destroy class so that a new star is created at the top when a star is destroyed.
  • Planet class (366 bytes): Extends Mob defining a special render function which draws a circle filled with a gradient based on the 2 colors and rotation of the planet.
  • Explosion class (928 bytes): This class is similar to Mob, but explosions have no speed (just a position). It’s designed to progressively draw an explosion on screen, based on the “run time” and “size” parameters, the size and color of the circle to be drawn are determined by the “progress” of the animation (a value growing from 0 to 100, based on the accumulated render time and the total run time). When fading, it substracts from the drawn circle creating a growing “hole” inside of it.
  • Shape definitions (2487 bytes): A dictionary of lists of drawing instructions to be interpreted by the Shape Renderer, all Mobs have a reference to a shape definition, used in the game loop
  • Game Start function (683 bytes): Plays the theme song, creates the player ships and starts a timer for wave generation. Called by the title screen and the enter key handler (for restarting the game)
  • Enemy Wave Generation (1947 bytes): Several functions containing the logic to create a new “wave” of enemies. Levels are made of waves generated every 3 seconds, this component decides what enemies will be spawned on each wave, and under what behavior. Makes extensive use of the seeded pRNG, as well as the Enemy Factory. Also creates the planets.
  • Enter key handler (320 bytes): Used to control the game state from the title screen and game over status, into the “in game” status.
  • Game state machine control functions (628 bytes): Transitions into the different game states (title, game over and “in game”)

Coming up next, final postmortem and future of the game!

 

ArcherFire: Duet of Aces – js13k 2018 – Part 2

JS13k 2018 has gone by! this is the second of a series of posts detailing my journey, as well as the structure of the game I built. You can play it online here!

Links to the full series: part1part3postmortem

Day 4

First thing I did was fixing the build scripts since I really needed to know how I was doing vs the 13KB limit (last year I spent a lot of time by the end of the time-frame, removing things). I figured out the build problems by checking the script for Lost of Asterion; I had to replace a dependency (gulp-uglify) with the ES6 ready version (gulp-uglify-es) since I was using ES6 features in my code (cannot live without arrow functions now). The zipped archive was 5.36KB, and I had 46 hours to go.

I created a list of priorities in Trello, as I said there was a game there already, so what was left was polishing some rough edges and add fancy stuff. The last missing core thing was making the levels consistent (that is, they should be the same every time the player plays). Of course, the trick because of the size restrictions is not having the levels hand-designed but rather using a seedable (and small) pRNG, I ended up using an implementation of  Park/Miller LCG based on this.

function LCG(s) {
  return function() {
    s = Math.imul(16807, s) | 0 % 2147483647;
    return (s & 2147483647) / 2147483648;
  }
}

I seeded it with 13312, and it’s used only for the enemy wave generation.

Another annoying thing I was pending fixing was replacing the temporary setTimeout based timers with something that relied on the game update cycle instead so that the game wouldn’t go bananas when the animation was paused (say because the game’s tab became inactive) but the timers kept running. I added a simple function to the RAF loop to keep track of a list of timers on every frame update, reducing a timeout value by the update delta, and executing a callback when it reached zero.

Next up was showing the “current wave” in the UI, so that players could have a sense of progress besides the score so they could brag about being able to reach wave X. This was also used to increase the difficulty of the waves, so the further the player is the harder the enemies and the shorter their reaction time (so they shoot more bullets)

There were some weird issues where mobs were being “killed” out of nowhere, I thought this may be due to the way they were being sliced out of the lists during the update phase which might cause the wrong mob to be deleted. I changed it so that when a mob’s update function deemed it necessary for the mob to be killed, it is marked and then all the marked mobs are deleted, instead of doing it on the spot. It seemed to work.

Also added some cosmetic changes on the explosion SFX, changing the colors so that it looked a bit darker and different when fizzling, and a scaling effect so the ships would look like they were “landing” on the game (but it didn’t look very good)

Finally, continuing with the idea of adding a music track, I asked on the js13k slack and was lucky to have Ryan Malm offer to create a track for the game, as long as I could set up SoundBox on it.  So I did that and added one of the sample tracks.

Screen Shot 2018-09-18 at 10.34.22 PM
SoundBox in action

Day 5

The final day of development was long, but not really too crazy compared to last year.

I proceeded to add more variation to the different enemy formations, adding the following:

  • Enemies coming from below
  • Horizontal row of mines
  • Vertical row of mines

I also did the best I could to enhance the appearance of the turret “platforms” and the mines.

20180913_210908
Designing the appearance for the enemies

Added some planets to the background, they are a circle filled with a gradient, their generation is tied to the wave generation so they serve as milestone markers to see how far you’ve gone (so far I have only been able to reach the second, purple planet, in my highest score)

Did some playtesting and balanced the difficulty a bit, then, since the game bootup was a bit crappy, I added a “loading” screen to cover the process of converting the soundbox script into a WAV stream, in turn, I also added a simple title screen with the name of the game, some credits, and instructions. This required adding some “mode” handling to the game and a simple state machine.

Was getting close to midnight when I got the theme song by Ryan, it was awesome! because of time constraints, it was a bit short (about 15 seconds long) but it did a great job at enhancing the atmosphere of the game.

It should be noted that this 15 seconds track, including the whole “library” to play it, is 2.5KB of compressed source code. Compared that to 361 KB for the OGG export. It’s really wonderful.

I did some work on the player bullets, changing them from red balls to missiles, using a different sound effect for them, and throttling the fire rate so it was more controlled and predictable. Also, since I still had plenty of space, added sounds for the explosion when a ship was destroyed, and a beep for starting the game.

Continued with small tweaks, removing the “ships landing” scaling effect which didn’t really look too good, changing the keybindings for the “down” key for player 2 to be “5” instead of “2”.

The game was almost ready to ship, I did some basic CSS styling for the containing page (black background, centered canvas), but more importantly scaling the canvas to 100% height so that it looked good on most horizontal display cases.

I hesitated a lot, but in the end, decided to jump into allowing the player to restart the game without having to refresh the page when dying. Anyone who has participated in a jam knows how tricky it can be to reset the game state, especially if you didn’t design for that in advance. But I went ahead and did it, and I think being able to restart quickly  became an important part of the game (and makes it look much more polished)

As part of the final playtesting, I added “shield” to the ships so the player can take 3 hits before dying instead of exploding instantly, and increased the acceleration so it’s easier to dodge bullets. I also fixed an issue with the Numpad not working in Safari and Firefox

afdoa

Next up, a view of the complete structure of the game, and then some final thoughts!

ArcherFire: Duet of Aces – js13k 2018 – Part 1

JS13k 2018 has gone by! this is the first of a series of posts detailing my journey, as well as the structure of the game I built. You can play it online here!

Links to the full series: part2part3postmortem

Before Coding

I wasn’t really sure what to do, I actually was wondering if I was going to be able to participate at all, but the weeks before coding I toyed in my head with several different ideas… one of them would be a mobile entry based on my Energy Radar project (which is inspired by Pokemon Go), running completely offline but allowing players to interact and capture monsters as a team. I decided against it because of it being maybe too big in scale.

20180913_210812

Another one would have been an offline life simulator, someone living on the forest, fishing, something more of an experience than a game since there would be little stress, this would have been more heavy on the graphical side so I abandoned it (more so as the deadline was getting closer)

20180913_210757

Finally, had an idea of a non-linear “Space shooter”, keeping some of the Energy Radar ideas on offline interactivity, players could fly from planet to planet; once in a planet, they would input a code from another player on the same planet, which would allow them to advance on the plot.

20180913_210742

Knowing that I may very well wound up doing something completely different, but I had to start somewhere, I went with this idea.

Day 1

At first, I tried to use source from Lost in Asterion (my js13k from 2017), but lost a lot of time. I went instead with a fresh copy of js13k boilerplate. I modified the example and was able to have a static starfield in little time.

Since this was going to be a non linear shooter, and I thought having a “lerping” camera effect would be cool, I invested a lot of time trying to make the “camera” work (again, based on Lost in Asterion). It worked, almost, since I wasn’t really tweening it but rather handling it as an object on-screen with acceleration and position, so it was hard to make it “stick” to the player once it reached him.

I also added simple keyboard input to move the “ship” around, and with the camera following it, it was a rudimentary space scene.

Screen Shot 2018-09-03 at 11.05.36 AM.png

Day 2

After giving it some thought in my head, and reading my postmortem from 2017, I decided to go on a different route. I would instead focus on making a simple arcade game, and use the 13K to add as much eye and ear candy as possible.

I ditched all the work that I had done in the camera since it was now going to be a linear game (and it wasn’t really working very well)

With a more clear vision of what the game was to be about, I implemented a lot of things,

  • Collisions between player and enemies.
  • Bullets killing enemies, increasing the player score.
  • Removing mobs when out of the screen (stars, enemies, bullets).
  • “Serial rendering” of mobs allowing potential complex representations.
  • Render score with LCD like display.

Since I needed something to test my “rendering” system, I decided to design the player ship, I based myself on the ship from the original ArcherFire made in QBasic in 2002.

Screen Shot 2018-09-13 at 9.30.34 PM
Original QBasic Archerfire, 2002

Doing vectorial art, however, is something I don’t have any experience with. I can do _some_ pixel art, but this is a different beast. Plus I had to manually input the sequence of commands to draw each shape. I did the best I could with the little time I had.

20180913_210847

In the end, this design is represented as follows in the code:

‘#eeeeee’,’p’,-2,2,-4,4,-6,0,-4,-1,-2,-4,0,-4,0,2,’f’,’o’,’#0000ff’,’p’,-3,3,-4,4,-6,4,-8,0,-6,-3,-4,-4,-5,-1,’f’,’o’,’#dddddd’,’v’,0,-6,2.2,2.2,’f’,’o’,’#888888′,’vh’,0,1,2.5,2,Math.PI,2*Math.PI,’f’,’o’,’#ff3333′,’p’,0,1,-2.5,1,-2.5,2,-1.5,3,0,3,’f’,’o’,’#000000′,’v’,0,-6,2,1.5,’f’,’o’,’#ff0000′,’vh’,0,-6,2,1.5,0.5,Math.PI-0.5,’f’,

(Note that this is meant to be only half of the ship, the other half is drawn mirrored)

Since I was already drawing a scaled version of it, I figured I’d try to include a practical 3d looking effect when turning the ship, it did look pretty good.

Tried to build the game by the end of the day to see how I was doing with the size but found out there was a problem with uglify which didn’t let me thru.

js13k2

Day 3

Since I was no longer going for the “offline social” component, I wondered how to incorporate the theme. One obvious option was to provide hotseat multiplayer, and I ended up adding that.

Made enemies being able to shoot at the nearest player, and added the infrastructure to be able to create enemies given a set of parameters. Also added enemies cruising from left to right of the screen, and platforms with 4 mounted turrets.

Added explosion effects, since I didn’t have any tweening library and the rendering was being done manually, had to implement the explosion animation by drawing an expanding circle which would them be “hollowed” when dissipating. Drawing a “hollow” circle in canvas context2d was not as easy as I thought! I ended up using a weird trick to compose the path to fill: Draw the outer circle clockwise and the inner one counter-clockwise. I still don’t understand how that worked.

For SFX, I included again the good old trusty jsfxr. It keeps being useful even after years of not being updated. I added sounds for the explosions and the firing of bullets.

I saw that I still had plenty of space left so I began wondering how to include music. I tried minimusic, set it up and made it work inside the game with a test melody, but was unable to come up with anything half decent (guess why, I’m not a musician!). I left it there, asking a friend to see if he could maybe device something out of it.

Also designed one of the enemy ships (again based on ArcherFire 2002). I tried to implement some way to “rotate” its rendering but after spending some time on it gave up.

Finally, I added one first version of the “wave generator”, that is the thing that puts up new enemies on the stage as the player goes thru. After putting that I found myself with a rudimentary but complete game that someone might even enjoy!

day3.5.gif

Journey onward to Day 4 and 5, and then a detailed rundown of the game’s structure and some conclusions and thoughts!

Trailer for the Roguelike Celebration 2018

The Roguelike Celebration is happening again this year, October 6 and 7. I will be flying to SanFran to assist and also give a talk about the History of Roguelikes.

Had an idea running on my head for a while to make a “trailer” for the event (no one asked me for it). At first, I thought of creating a playable classic roguelike using my JSRL roguelike template. I actually did create the foundations for it (as in walk in a predefined map), but it lacked the cinematic potential for a short trailer. In any case, I integrated the “torch” effect from the unicodetiles.js example into JSRL, which may be useful. You can check out the integration here.

Screen Shot 2018-08-10 at 7.30.17 AM

Then I had another idea and I just couldn’t be at peace until I implemented it. I think it occurred to me a day while driving and listening to the Mega Man III OST. I thought I had found the perfect tune for it. So, even in a busy week with lots of work, I just had to do it.

The trailer features the awesome speakers’ lineup in a “robot-masters” NES Megaman stage selected style.

I implemented it using JavaScript and Phaser, you can check the source code here and the demo running live here

Of course, there’s little structure to the project since it was meant to be a quick job (and is also pretty simple). Most of the relevant logic can be found in a single Object, the Game state. I set up a stage with a black background and the gray strip, as well a Sprite object for the character and 4 text fields. I used a Megaman 10 font (I had found another one for Megaman 2 but for some reason, it could not be loaded as a web font), I performed a simple centering function based on each line’s character count to keep the characters as sprites in the grid (thus getting a bit close to being a NES “background sprite”?).

There was also a simple “particle” animation in the background, instead of stars they were small @ signs because, you know, roguelike. I used the same color palette used on the Roguelike Celebration logo for them.

Of course, the most fun part was doing the pixel art for the speakers. I used a bunch of Mega Man 2 robot masters as a base and then I proceeded on tweaking them for each speaker. The ones I know in person where easier, for the others I had to do a bit of stalki Internet research, I hope I managed to capture their likeness.

Finally, I reused the “Retro TV with scanlines” from Cat Cafe.

 

ProcJam Summer 2018 – Pokemon Building Generator – Part 1

Procjam Summer 2018 has started so here I go. This will be a small project to create classic Pokemon style houses. (Guess what I might end up using it for)

This will be a two steps generator, the first thing to do is defining a logical model for the houses. We start by examining some examples to extract the structure and an initial set of variations:

Screen Shot 2018-06-20 at 3.23.33 PM

Structure

  • Blocks of 4 tiles
  • Windows and walls can be placed at tiles, having one tile for padding at every side (available tiles = blocks – 1) * 2, this padding is used to project the shadows of the building.
  • Doors can be placed at blocks, having one block for padding at every side.
  • Distorted perspective, the “depth” of the building is represented as blocks of the ceiling.
  • The last floor gets 2 less available tiles due to roof slant

Attributes:

  • Structure
    • Width: 6 blocks
    • Height: 2 blocks
    • Depth: 2 blocks
  • Front
    • 1st floor
      • Windows: Tiles 1, 2, 3, 6, 7, 8, 9 and 10
      • A door at block 3
      • Wooden wall (1 to 10)
    • 2nd floor
      • Windows: Tiles 2, 3, 4, 7, 8 and 9
      • Wooden wall (1 to 3)
      • Brick wall (4 to 10)
  • Roof
    • Slanted
    • Tiled

Next example:

Screen Shot 2018-06-20 at 3.34.38 PM

Front

  • 2nd floor
    • Bar border

Next Example:

Screen Shot 2018-06-20 at 3.43.19 PM

Structure: The last floor gets all available tiles if the roof is flat

  • Front, First floor
    • Poke sign at block 3
  •  Roof
    • Flat

Let’s confirm our model covers all wanted cases

Screen Shot 2018-06-20 at 3.52.51 PM

  • Structure
    • Width: 8 blocks
    • Height: 6 blocks
    • Depth: 2 blocks
  • Front
    • 1st floor
      • Windows: Tiles 6, 7, 10, 11
      • Doors at blocks 2 and 4
      • Mart sign at block 6
      • Brick wall
    • 2nd floor (…)
  • Roof
    • Flat
    • Tiled

Having this, we can start thinking on our higher level generator, its input will be the type of building and its size. Following are the types of buildings we’ll support: House, Gym, Mart. As for the sizes, they will be: Tiny, Small, Large, Huge.

The output of the high-level generator is a logical model of the building, which is used by the lower-level generator to produce a map of tiles. An example of the 1st output for a Large House would be:

Screen Shot 2018-06-20 at 3.34.38 PM

{
  width: 4,
  height: 2,
  depth: 2,
  floors: [
    {
      wall: 'wood',
      windows: [4, 5],
      doors: [1]
    },
    {
      wall: 'wood',
      windows: [2, 4, 5],
      border: true
    }
  ],
  roof: {
    type: 'slanted',
    material: 'tiles'
  }
}

Let’sa go! We fire subl and produce this:

const Random = {
  chance(c) {
    return this.range(0, 100) <= c;
  },
  range(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }
};


const SIZE_RANGES = {
  tiny: {
    minw: 3,
    maxw: 4,
    minh: 1,
    maxh: 1,
    mind: 1,
    maxd: 1
  },
  small: {
    minw: 4,
    maxw: 5,
    minh: 1,
    maxh: 2,
    mind: 1,
    maxd: 1
  },
  large: {
    minw: 5,
    maxw: 6,
    minh: 2,
    maxh: 3,
    mind: 1,
    maxd: 2
  },
  huge: {
    minw: 5,
    maxw: 8,
    minh: 3,
    maxh: 5,
    mind: 2,
    maxd: 4
  }
};

const SLANTED_ROOF_CHANCES = {
  house: 90,
  gym: 20,
  mart: 10
};

const WINDOW_CHANCES = {
  house: 50,
  gym: 20,
  mart: 50
};

// https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

const generator = {
  generate(type, size) {
    const model = {
      width: 0,
      height: 0,
      depth: 0,
      floors: [],
      roof: {},
      type,
      size
    }
    // Size of the building
    const sizeRanges = SIZE_RANGES[size];
    model.width = Random.range(sizeRanges.minw, sizeRanges.maxw);
    model.height = Random.range(sizeRanges.minh, sizeRanges.maxh);
    model.depth = Random.range(sizeRanges.mind, sizeRanges.maxd);
    // Type of roof
    model.roof.type = Random.chance(SLANTED_ROOF_CHANCES[type]) ? 'slanted' : 'flat';

    for (let i = 0; i < model.height; i++) {
      model.floors[i] = this.generateFloor(model, i);
    }
    return model;
  },

  generateFloor(model, floorNumber) {
    const floorModel = {
      wall: '',
      windows: [],
      features: []
    }
    const useableBlocks = [];
    for (let i = 0; i < model.width - 2; i++){
      useableBlocks[i] = true;
    }
    const useableTiles = [];
    for (let i = 0; i  {
      if (!t) {
        return;
      }
      if (Random.chance(WINDOW_CHANCES[model.type])) {
        floorModel.windows.push(i);
      }
    });
    return floorModel;
  },

  getRandomSpace(array) {
    const availables = array.find(x => x === true);
    if (!availables) {
      return undefined;
    }
    const spaces = array.map((x, i) => ({x, i})).filter(x => x.x === true);
    return shuffle(spaces)[0].i;
  }
}

const model = generator.generate('mart', 'huge');

console.log(JSON.stringify(model));

Running it with nodejs gives us a variety of models already:

{
  "width":6,
  "height":2,
  "depth":2,
  "floors":[
    {
      "wall":"",
      "windows":[
        4,
        7
      ],
      "features":[
        {
          "x":1,
          "type":"door"
        },
        {
          "x":3,
          "type":"gymSign"
        }
      ]
    },
    {
      "wall":"",
      "windows":[
        3,
        9
      ],
      "features":[

      ]
    }
  ],
  "roof":{
    "type":"flat"
  },
  "type":"gym",
  "size":"large"
}

 

{
  "width":8,
  "height":5,
  "depth":3,
  "floors":[
    {
      "wall":"",
      "windows":[
        0,
        4,
        5,
        13
      ],
      "features":[
        {
          "x":3,
          "type":"door"
        },
        {
          "x":0,
          "type":"martSign"
        }
      ]
    },
    {
      "wall":"",
      "windows":[
        1,
        3,
        5,
        6,
        7,
        9,
        10,
        11,
        12,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        3,
        4,
        5,
        7,
        10,
        12,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        5,
        7,
        8,
        9,
        11,
        13
      ],
      "features":[

      ]
    },
    {
      "wall":"",
      "windows":[
        0,
        1,
        4,
        5,
        8,
        9
      ],
      "features":[

      ]
    }
  ],
  "roof":{
    "type":"flat"
  },
  "type":"mart",
  "size":"huge"
}

Next step is using these models to create the maps of tiles.