Creating Voxel Games in Modern Browsers

If you’ve ever done any programming in JavaScript or Coffee-script, you’ve probably heard of Three.js, or at least heard the name.

What is Three.js? Three.js is a JavaScript library that helps you make WebGL based games. It takes the hundreds of lines of code you would normally need to make WebGL objects, and simplifies it into easy to use objects and functions, such as ‘var cube = new THREE.Mesh( geometry, material );’.

Now of course you could go and write your own Voxel engine to make a Voxel game in Three.js, but why not use an existing engine instead of writing it all yourself? Voxel.js is a JavaScript Voxel Engine written on top of Three.js.

Since it is written on Three.js, that means that is has all the features, power, and performance Three.js has (for better or for worse). Now on top of being an easy to use Voxel engine, you have all the Three.js features such as non-voxel meshes, particles, and even lens flares.

Getting Started with Voxel.js

Some commands can take a few minutes to run/install. They may look like they are not doing anything while they are really downloading large packages. Please be patient.

Now voxel.js does have a getting started section and video but they don’t cover much, so I’m going to be going over how to get running using Voxel.js with Node.js.

First steps

First off if you don’t have it, your’re going to need to install Node.js, so head over to the Node download page and download and install the latest version for your OS.

Once it’s done installing, open a command prompt (on Windows), or a terminal on mac/Linux, and type the command ‘npm’ It should say something like this:

Usage: npm <command>

where <command> is one of:

 access, add-user, adduser, apihelp, author, bin, bugs, c,

 cache, completion, config, ddp, dedupe, deprecate, dist-tag,

 dist-tags, docs, edit, explore, faq, find, find-dupes, get,

 help, help-search, home, i, info, init, install, issues, la,

 link, list, ll, ln, login, logout, ls, outdated, owner,

 pack, prefix, prune, publish, r, rb, rebuild, remove, repo,

 restart, rm, root, run-script, s, se, search, set, show,

 shrinkwrap, star, stars, start, stop, t, tag, test, tst, un,

 uninstall, unlink, unpublish, unstar, up, update, upgrade,

 v, verison, version, view, whoami

npm <cmd> -h quick help on <cmd>

npm -l display full usage info

npm faq commonly asked questions

npm help <term> search for help on <term>

npm help npm involved overview

Specify configs in the ini-formatted file:

 C:\Users\ldd\.npmrc

or on the command line via: npm <command> --key value

Config info can be viewed via: npm help config

npm@2.7.4 C:\Program Files\nodejs\node_modules\npm

If it looks like this then your’re good. If it said the command does not exist, you may need to restart your computer. If it still doesn’t work after that, there was probably an issue when installing Node.

Creating a Project

Now let’s get started making our first Voxel.js game, your’re going to have to decide where you want to keep your game’s files, so create a folder somewhere and name it “my_first_voxel_game” (or whatever you want, it doesn’t matter).

Now open a command prompt/terminal and cd to the folder you just created. On Windows sometimes you can shift+rightclick in Windows Explorer and select ‘command window here’ to open it already in that folder, then you don’t have to cd.

Now in our terminal (just gonna call it a terminal from now on, command prompt, terminal, same thing),  type ‘npm init’. It will ask you some questions that will generate a project file for us. If you don’t have an answer for the question, or just want to leave it blank just press enter, we can change it later. One thing to note is that when it asks you for a name, it has to be all lowercase, and have dashs (-) instead of spaces. (NO SPACES!)

Once your’re done that, we’re almost ready to start programming 🙂

Adding packages

Before we can start programming, we need to add a few JavaScript libraries (called packages with Node.js) to our project.

The first one we’re going add is called Beefy. Beefy allows us to basically write a smaller javascript file then we normally would have to, and then convert it to the bigger file the browser needs. It also has a built in server which we’ll be using to test our Voxel game.

To install Beefy, run this command in your terminal:

npm install -g beefy 

Now lets explain what this command does:

  • ‘npm’ is the base command for the Node.js package manager
  • ‘install’ is telling the ‘npm’ command we want to install a package
  • ‘-g’ the g flag tells npm to install the package globally, in other words it installs it in a way that allows it to be accessed by any node project. It also adds the beefy command to your path, which is what we need
  • ‘beefy’ the name of the package your’ve telling it to install

After you run the command you should see something like this:

beefy@2.1.5 C:\Users\keith\AppData\Roaming\npm\node_modules\beefy

├── leftpad@0.0.0
├── pretty-bytes@0.1.2
├── find-global-packages@0.0.1
├── ansicolors@0.3.2
├── ignorepatterns@1.0.1
├── which@1.0.9
├── response-stream@0.0.0
├── through@2.2.7
├── open@0.0.3
├── minimist@0.0.8
├── mime@1.2.11
├── portfinder@0.2.1 (mkdirp@0.0.7)
├── xtend@2.1.2 (object-keys@0.4.0)
├── readable-stream@1.1.13 (inherits@2.0.1, isarray@0.0.1, string_decoder@0.10.3
1, core-util-is@1.0.1)
├── resolve@0.6.3
├── concat-stream@1.5.0 (inherits@2.0.1, typedarray@0.0.6, readable-stream@2.0.2
)
├── chokidar@1.0.5 (arrify@1.0.0, is-glob@1.1.3, path-is-absolute@1.0.0, async-e
ach@0.1.6, glob-parent@1.2.0, is-binary-path@1.0.1, readdirp@1.4.0, anymatch@1.3
.0)
└── script-injector@1.0.0 (duplexer2@0.0.2, through2@0.6.5, trumpet@1.7.1)

If you get errors, do a Google search for them. There are a lot of online solutions, and I don’t have the time to help all of you who might get stuck 😉

Now that we have installed Beefy, we can go ahead and install the other packages we need for our project.

The core framework of Voxel.js: (https://www.npmjs.com/package/voxel-engine)

npm install voxel-engine --save

Some basic Voxel.js features: (https://www.npmjs.com/package/voxel)

npm install voxel --save

An actual player that we can walk around with: (https://www.npmjs.com/package/voxel-player)

npm install voxel-player --save

And some textures to use with the game so our voxels aren’t all black: (https://www.npmjs.com/package/painterly-textures)

npm install painterly-textures --save

Once all those packages are installed, we’re ready to go!

Programming the game

Now that we have all our packages ready to go, we can start programming a basic voxel game 🙂

index.html

First off, in our project folder we need to create an new html file called “index.html”. Put this into the index file:

<!DOCTYPE HTML>
<html lang="en">
    <head>
          <title>Voxel Engine</title>
          <meta charset="utf-8">
           <style type="text/css">
           body {
             font-family: Monospace;
             font-size: 12px;
             background-color: #f0f0f0;
             margin: 0px;
             overflow: hidden;
           }
           #container {
             -moz-user-select: none;
             -webkit-user-select: none;
            user-select: none;
        } 
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script type="text/javascript" src="./bundle.js"></script>
    </body>
</html>

In this file we have a container object, which will hold the html elements that display our game. We also reference the script “bundle,js”, which beefy will create later from the code we’ll write.

index.js

Now we need to create a JavaScript file called “index.js”, this is going to hold all our code.

References

var container = document.querySelector('#container')
var createGame = require('voxel-engine')
var painterlyPath = require('painterly-textures')(__dirname)

Creating the game

These lines of code are telling beefy to use the packages voxel-engine and painterly, as well as storing them and the html element for the game as variables we can use.

var game = createGame({

    texturePath: painterlyPath ,

    generate: function(x, y, z) {

        return y === 1 ? 1 : 0 || y < 1 && y > -30 ? 2 : 0

    }, 

    worldOrigin: [0, 0, 0]

})

Now we’re creating the actual game using the createGame variable we defined. Here is a breakdown of each line:

  • “texturePath: painterlyPath,” this is telling voxel-engine to look at the variable “painterlyPath” to get the path to where the textures are that it should use.
  • “worldOrigin: [0, 0, 0]” this tells Voxel.js that the center of the world is x0 y0 and z0
generate: function(x, y, z) {

        return y === 1 ? 1 : 0 || y < 1 && y > -20 ? 2 : 0

 }

The code above is creating our voxel world. It’s telling Voxel.js to use that function when it is generating blocks. The x, y, and z variables it gets passed are the x, y, and z of the current block it’s generating.

Lets break down the formula ”y === 1 ? 1 : 0 || y < 1 && y > -20 ? 2 : 0″ so it’s easier to understand.

The formula is in two parts, separated with ||. This tells it to use whichever of the parts matched the current case.

  • “y === 1 ? 1 : 0” when the y position (up and down) is equal to 1, tell the generator that the id for this block is 1 (grass), and it it’s not, set the id to 0 (air/nothing). “when y is 1 set block to 1 if not 1 set block to 0”. This part generates the top layer of grass
  • “y < 1 && y > -30 ? 2 : 0” This one is a bit harder, since it generates the stone layer. The stone layer goes from 1 block below the grass layer, to -30 (so it’s 30 blocks deep). If y is smaller then 1 (so anything below 0) and if y is bigger then -30 then set the material to 2 (currently brick, Voxel.js default), and if it’s not, set it to air.

Adding the game to the webpage

Now we have a game created, but we don’t have anywhere to display it. Now is when we use the container variable we defined at the start.

window.game = game

game.appendTo(container)

  • “window.game = game” this sets the window.game variable to the current game, it is used by some plugins I believe to get the game instance.
  • “game.appendTo(container)” this is telling the game to draw itself in the container element. Without this the game won’t display

Creating the player

You can put a minecraft 1.7 formatted skin in your project folder, and name it skin.png, then voxel-player plugin will use it was the player skin

var createPlayer = require('voxel-player')(game)

var player = createPlayer('skin.png')

  • “var createPlayer = require(‘voxel-player’)(game)” defines that the createPlayer function is the main function from the voxel-player plugin
  • “var player = createPlayer(‘skin.png’)” creates the actual player using the skin file called ‘skin.png’, if there isn’t a skin file your character will just be black

Now we have a player in the game, but we cannot control it yet. Lets do that now:

player.position.set(10, 10, -10)

player.possess()

  • “player.position.set(10, 10, -10)” this sets the player at the position x10 y10 z-10. Sometimes it isn’t a good idea to start them at the world center, as some weird stuff can happen with some plugins.
  • “player.possess()” this is telling the player plugin to control the camera, and receive mouse and keyboard controls

Now we have just one last thing to add, we have the option of moving our camera into a third person view, using voxel-player. So lets add a button for doing that:

window.addEventListener('keydown', function (ev) {

    if (ev.keyCode === 'R'.charCodeAt(0)) {

        player.toggle()

    }

}) 

  • “window.addEventListener(‘keydown’, function (ev)” this is telling java that we want to know when a key is pressed, it will call anything within this function.
  • “if (ev.keyCode === ‘R’.charCodeAt(0))” this is checking if the key pressed is R, and if it is, it runs the code in the if statement
  • “player.toggle()” this is telling the player plugin to switch between first person and third person

Save the file, and your’ve done all the programming 🙂

Testing

Now that we have the 2 files we need (index.html and index.js), it’s time to test them. Open a terminal in the project folder (or use the one you used in the first few steps if you didn’t close it), and run the command:

 beefy index.js:bundle.js 8080 -- -d

This is running the beefy command (the global package we installed earlier), and it’s telling it to take our index.js file, and create a version of it for the browser called bundle.js. (browsers do not normally understand the require() statements, beefy makes a file that has everything that is needed for the browser to understand it).

Then we’re telling it to host the file on the localhost port 8080. The “-d” flag tells it to also host the directories in the project file. This is needed so that it can find the painterly textures.

Now if you open a web browser, and go to “localhost:8080″ (or http://localhost:8080/ in some browsers”) you should see a working game!

If your game isn’t working, then read on.. If your game is working fine, well read on anyways!

To stop beefy, press “ctrl+c” (on windows you will need to type y or n when it asks to terminate the batch job), and it will stop the server. The start it again, just run the command again.

Troubleshooting

We’re almost always going to run into issues when running code. Maybe an example was for an outdated version of the programming language, or you typed something wrong, either way we need to know what’s up.

To debug a browser app, such as a Node.js/Voxel.js app, we need to use the developer tools. I highly recommend you use Google Chrome, or Firefox for testing, and they have really good developer tools.

To see where an error is, hit f12 on your keyboard and that should open the developer tools window. Find the console section, and in the console there will be red text with your error, and usually a link you can click that will show you where the error is in the files.

If you don’t understand what the error means, Google search it. Most of the errors you find, you’ll be able to find a fix for by Googling it.

If you get stuck on something and can’t fix it AFTER Googling, feel free to send me a message or leave a comment and I’ll try to help if I can 🙂

Conclusion

Now you have the base for a voxel game in your browser, you’ve learned how to create the basic game and generate a flat world, as well as add a controllable player.

From here on you can add more plugins, or start programming stuff yourself. I’ll probably have some more tutorials in the future, that cover more plugins, and adding in Three.js features, as well as things like writing your own plugin, and hosting your game online. But until I create those posts, here are some links to help you make your awesome game:

  • A search on npm for the word voxel, most of the results are Voxel.js plugins: https://www.npmjs.com/search?q=voxel (for documentation for some of them, you need to go to the github page linked on the right)
  • The Github organization for Voxel.js, contains all of all the repositories: https://github.com/voxel
  • List of Three.js examples, source code included for all of them (to get the instance of Three.js that the current Voxel.js game uses, use the variable “game.THREE”): http://threejs.org/examples/
  • The voxel.js site: http://voxeljs.com/
  • Three.js getting started guide (you can use anything on there in voxel.js, just get the THREE variable with “game.THREE”): http://threejs.org/docs/index.html#Manual/Introduction/Creating_a_scene

I’m planning on writing some documentation for Voxel.js and the Voxel plugins, but until then, I hope this helps those of you wanting to make a Voxel game with WebGl and Three.js 🙂

If you want to send me any messages, either leave them in the comments.

Advertisements

4 thoughts on “Creating Voxel Games in Modern Browsers

  1. Pingback: Publishing Your Voxel.js Game for Free to Heroku | Tekhne Today

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s