Note: I made a better version of this post on Medium

D-Zone is a project I started in 2015 soon after joining Discord and learning to program bots with the API. View it in action!

How it started

My initial vision was to create a small virtual world populated by autonomous characters which represented the users in a Discord server. The characters would roam around the space and do various things, and their behavior would be influenced by the corresponding user’s activity. It wasn’t a game you could interact with directly, other than moving the camera.

I hadn’t intended on releasing it publicly and never considered the possibility of people outside of my friends being interested in the concept. It was published on NPM and the readme had basic installation instructions, but this was just for the sake of doing things “the right way” for open source projects.

I had just started learning NodeJS and had a small bot running in my friends’ Discord server. I was also recently working on an isometric pixel art game/engine in HTML canvas (the latest in a long line of abandoned Canvas/JavaScript games and experiments). D-Zone drew directly upon these fresh skillsets and experiences.

This was my first time writing NodeJS that compiled to browser-flavored JS. I modelled my engine off of a project called CRTRDG. I wanted to write as much of the engine code myself as I could. D-Zone is largely a learning experience for me.

Development Snapshots

I have gone back and re-compiled several old builds of D-Zone throughout its development in 2015, and uploaded live demos. Unlike the real D-Zone, no live user activity is in these demos, it’s all randomly generated test data.

Version 0.0.7 (Nov 7, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.0.7

This was the first build that looked like anything. Just a square area of tiles and blocks. The zoom level changed automatically based on window size. I had basic JS modules like Entity , WorldObject , and HalfBlock . Sprites were put into a z-sorted buffer and rendered at 60 FPS.

Version 0.0.8 (Nov 8, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.0.8

The Actor module is born. Equipped with a single placeholder sprite and a “wander” behavior. Movement wasn’t grid-based as it is currently; collision detection and z-sorting was done with floating point values. This demo was greatly informative: http://bannalia.blogspot.com/2008/02/isometric-room.html

You’ll notice the character design (if you can call it that) is almost identical to what it is today. When I drew it, it was supposed to be a generic placeholder for users who I had not drawn a special sprite for. Remember, this was supposed to be just for my friends’ server of less than 10 people, so I had intended on each of us having our own custom sprites.

Version 0.0.12 (Nov 10, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.0.12

The Discord bot portion was implemented and communicating with the webpage via websockets. It sent a list of users with their statuses to initialize the world, and then any subsequent status updates in real-time.

A few more sprites were created for orienting and indicating offline status. Movement was slowed down, which makes the isometric movement look jittery.

Version 0.0.18 (Nov 12, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.0.18

Users in Discord can have their names appear in a certain color if they are assigned a role with that color. I used this info colorize their sprite. This had to be done on-the-fly, since a role could have any one of millions of colors. I used the canvas’ globalCompositeOperation in color mode to draw a 65% opacity fill of the role’s color over the sprite. I found these settings to give the best results. Other methods lead to over-saturation or ruining the sprite’s contrast. The only catch is that transparent areas are affected. So after colorizing, I restored the sprite’s original alpha channel.

Oh, and I added grass. I still like how it looked. If you look closely at where the grass touches a wall, you’ll notice there’s some fringe overlapping the wall. This required separate sets of the grass tile sprite, and the world generation code had to know where to use them. I used a marching squares technique to determine this.

It was around this point that izy521#7800, the author of the Discord library I was using noticed my NPM package as a dependent. It had a link to where I was hosting the latest live demo, and he was apparently impressed by it. The exact chronology of events here is fuzzy to me, and I can’t check the logs because the server in which it took place recently lost all its message history. As I remember, he posted a link to D-Zone in public chat and offered me a compliment. Some others saw it too and there was a small buzz of interest.

This took me by complete surprise. Not only was my project discovered out of the blue, but it actually intrigued people. This is the first time one of my programming projects ever had public interest, even at this small scale. I was giddy with excitement, but also mixed feelings. D-Zone was so incomplete and unimpressive compared to my vision for it. But here it was, making its initial impression on people, ready or not. But that was only the beginning.

Version 0.0.20 (Nov 16, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.0.20

This was a major update. I simplified the isometric engine by making it all grid-based. Actors just blipped from tile to tile, but they could also move up and down steps, and even sit on top of one another. I started changing up the world generation.

I also made them talk. That wasn’t part of my vision, but Izy (I think) suggested it and it made sense. If each user is represented by an actor with the proper role color and status, why shouldn’t they talk when the user sends messages in Discord? This made the simulation immediately more engaging. People were so tickled by seeing their virtual avatar in their web browser say what they had just typed in another program. This solidified what was, and still is, the core appeal of D-Zone. Its novelty outshone its lack of content and features.

Version 0.1.0 (Nov 25, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.1.0

Another major update that brought movement animations, multiple server support with a basic UI system, name tags, multi-line and multi-page message boxes, and the “beacon”.

Teleporting cubes was no good at all, so I was eager to create a movement animation. I knew I’d be going for some kind of hop, and that the cubes would be flexing a little in the process. I started by just drawing a little line and making it compress and hop and a fluid way. Acting as the cube’s “spine”, it was my guide for drawing the cube’s shape in each frame. The result was easier to achieve than I expected, but I did have difficulty drawing the faces in some of the frames. I would later revisit these mid-jump faces, as well as make several tweaks to the rest of the animation.

Like most of the engine, the UI system was custom-made but nothing special. Modules like Panel , Input and Button were inherited from a basic UI element module, and could be parented to each other. These elements could then be created and configured programmatically.

The text blotting system was also custom. The hand-drawn font is loaded from a sprite sheet and each character’s position and size had to be configured. The blotter would iterate through a message’s characters one by one and map each character to the textbox. This has to be done before actually drawing the text, so that the correct textbox size can be determined. Then the empty textbox appears with a little animation, and characters are drawn into it with the pre-generated metrics, line by line, page by page.

The strange structure featuring a painstakingly pixelized Discord logo is called the beacon. It represents the websocket connection to Discord in the back-end. The light on top blinks whenever data is received, such as a presence update or a chat message. A quirky idea, but fit D-Zone perfectly. It took me a while to come up with a good design.

Version 0.1.7 (Dec 1, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.1.7

Here is the first attempt at an actual behavior other than random hopping. Actors that are sending messages in the same channel will try to hop toward each other. This uses A* pathfinding. I wrote my own implementation for a previous project, but had to read several tutorials before A* really clicked for me. Unfortunately this behavior system was (and still is, in the main branch) buggy as heck. The demo for this version will probably crash after a few minutes.

Tile Rendering Rewrite (Dec 2-6)

I decided it was time to improve the tile graphics. That meant adding transitional tile graphics, which meant a heck of a lot of sprites. This is when I discovered a different way of creating and rendering tile sprites. The main take-away is that instead of creating a sprite for a tile, you’re creating a sprite for the intersection of 4 tiles. This allows you to create all possible tile transitions with a much smaller number of sprites. This was tough to wrap my head around, and my bitwise implementation may have not been the best, but I eventually got it. The only major pitfall was that I could not keep the varied elevation in the map. I kept running into z-ordering issues. So I flattened everything out, to avoid rage-quitting the project. One major benefit of this was that I could render the entire map as one big sprite, instead of rendering each tile on every frame.

The big break

On December 12th, Discord’s own Jake (Heinz?) sent me a DM asking if I’d like D-Zone to be mentioned in an upcoming blog post about what people have created using the Discord API. This meant huge exposure for D-Zone, and of course I was full of mixed feelings once again. The project is so unfinished! But holy crap I can’t pass up this opportunity! I was determined to improve D-Zone as much as possible before the post went up.

Version 0.1.9 (Dec 13, 2015)

Live Demo: http://pixelatomy.com/old-dzone/0.1.9

Finally we arrive at D-Zone’s current aesthetic. Wanting to make a good impression for the upcoming blog post, I read a bunch of pixel art tutorials to learn how to create better textures. I learned about unified color palettes. At first, the contrast between the smooth cubes and noisy terrain bothered me, but I think it works to avoid the actors blending in with their surroundings. I will probably redo the stone textures at some point.

For some extra flair, I added random flower patches (a suggestion from my friend Viper), which was a breeze to implement with the new tile rendering technique.

The blog post goes up (Dec 20, 2015)

https://blog.discordapp.com/the-robot-revolution-has-unofficially-begun-unofficial-api-23a3c722d5bf



Of course I was asleep when it went up, and so of course my D-Zone bot crashed at some point, leaving a broken demo for all to enjoy. Thankfully this was only a small window of time. In the following days, chatting with people on Discord about my project was (and still is) an incredibly enjoyable and gratifying experience. It still feels novel to me, even after 2 years. My desire to impress people and see my work being enjoyed continues to drive me.

This just about closes up 2015 for D-Zone. You may be wondering, “so what did you do in 2016 and 2017?” D-Zone’s development slowed down considerably, and took many breaks, but the main reason it still looks the same is that I began a complete rewrite of the engine in early 2016. While working on a new feature, I concluded that D-Zone’s code was just too messy to continue adding to.

When the rewrite reaches parity with the old version, I’ll finally merge it into the master branch and get back on track to fulfilling my initial vision. I may write a post or two about what I’m doing differently in the rewrite; there is one roadblock in particular that I feel would benefit me to write about.

If you want D-Zone on your server, you can run your own by following this guide. Or, if you want to just invite a public bot, check out DisWorld!