Ludum Dare
Ludum Dare
Game Jolt
One Game a Month

Welcome to I'm Brian MacIntosh, and I am a game programmer in the Orange County area of Southern California. This site serves to host and distribute some of my games and my blog, below.

I have developed games and apps for the XBox 360, Windows PC, iPad, Amazon Alexa, and Windows 7 Phone. I'm particularly interesting in procedural generation, pixel art, and emergent gameplay, and I'm looking forward to developing more games with these technologies.

Blog RSS E-Mail

Previous Page | 85 total posts | page 1 of 17 | Next Page

ASCII Art Generator

March 26th, 2018 @ 1:27
Tags: random, javascript

A few years ago, I wrote a program that could produce ASCII art from raster input images. I was going to use it to generate paperdoll images for the equipment screen in an ASCII roguelike game. It worked great, but it was written using XNA and the images to convert had to be set at compile-time. Ick!

Now, I've finished converting the program to Javascript/HTML5, and made a number of other improvements. You can try it right here!

ASCII Art generator sample

You can find a number of ASCII art generators on the internet, but they usually operate simply by selecting characters with more or less "ink" based on the brightness of each character-sized cell in the image. This method requires pretty large output sizes for the image to be recognizable. My generator uses edge detection to find characters that actually follow the lines of the input image, which holds up a lot better at smaller sizes. The downside is that noisier images (such as photographs) can produce noisy output that requires a lot of cleanup, though there are some steps that try to mitigate this.

The source code is under the GPL (3.0), and images produced with the page are free to use. You can visualize what each step looks like by adjusting the Debug Stage in the Advanced settings, and there are a number of sliders to play with the tweak the results. Here is an overview of the steps in the algorithm.

  1. Greyscale the input image.
  2. Gaussian blur the image to reduce noise.
  3. Use Sobel edge detection to produce a greyscale image representing the edges present.
  4. Threshold the edge-detected image, leaving us with a black image with white lines.
  5. (Optional) Dilate the image, thickening the edges.
  6. (Optional) Erode the image, reducing the edges. When used in combination with equivalent dilation, this can help reduce noise.
  7. Blur the line image. This makes it easier for us to match up characters in the next step when the best match doesn't precisely line up with the grid.
  8. Split the image into a letter-sized grid. For each grid cell, overlay ("convolute" is the technical term) each ASCII character over the content. Whichever character best matches the content of that cell is the one we'll use. We also try the characters at small offsets to try to catch, say, a vertical line that doesn't land quite in the middle of a cell.

ASCII Art steps: original image, Sobel edge detection, overlaid ASCII characters


A Different Approach to Pip-Based Bars

November 23rd, 2017 @ 3:35
Tags: random, tricks

I've been checking out a number of different systems in Factorio while experimenting with making a factory-building game. While looking through the game's assets, I noticed an interesting health bar graphic that revealed Factorio's rather neat way of handling pip-based health bars. A pip-based bar uses filled or unfilled pips to indicate progress or health, rather than a continuous line:

Factorio health bar screenshot

The most obvious way to implement this element would be to use a number of different sprite instances, and have each of them flip between a "green" and a "grey" image as appropriate. This can be done in one draw call, if the two states are on one image, and one quad per pip. Here's the asset you would need to implement this:

Two health bar pips, one green, one grey

So I was initially confused when I saw that Factorio's health bar asset actually looked like this:

Factorio health bar with lots of green pips followed by lots of grey pips

Can you figure out how this asset might be used? My guess is that the bar is drawn as a single quad that's mapped to an appropriate part of this image using its UV coordinates. For example, if you wanted a 7-pip bar with 5 pips filled, you could map your UVs like so:

Factorio health bar asset with UV mapping illustration

This is more efficient because you only have to draw one quad. More significantly, it's simpler to implement because you only need a single sprite or entity in your engine, rather than having to create several and manage their positions. Your asset just needs to have twice as many pips as the maximum pip count you want to use.


Necromasser Release

March 25th, 2017 @ 15:50
Tags: necromasser, threejs, javascript

We just released a new online, in-browser game called Necromasser. Necromasser is an always-on multiplayer world where you try to build the most massive zombie horde to hit the top of the leaderboard. You can play it in your browser right now!

Necromasser Screenshot


Procedural Potion Icon Generator

March 08th, 2017 @ 2:35
Tags: random, javascript

Randomly inspired by a coworker, I took a weekend afternoon and made a webpage that procedurally generates 32px potion icons.

Make potions here

Sample procedural potion sheet


Persistent data in the Alexa Skills nodejs SDK

February 05th, 2017 @ 0:59
Tags: alexa, nodejs, random

I recently started use the Alexa Skills Kit SDK for nodejs to write an Amazon Alexa skill. I ran into one rather silly roadblock, which I will now share so others can avoid.

This SDK handles persisent data (with the same session and across sessions) by providing an attributes property on the skill handler (accessed by this.attributes). My problem was that sometimes properties I set on this object were apparently completely ignored by the next request (even if I kept the session open with an this.emit(":ask", ...) response). It is perhaps obvious in hindsight, but you must make all your changes to this.attributes before calling emit, as emit will immediately and synchronously prepare and send the response to Alexa, including the attributes you're trying to persist into the next session. But it took me quite some time to figure this out.


Previous Page | 85 total posts | page 1 of 17 | Next Page