Whirled on the JS Game Jam Code

Somehow JS13K Games appeared on my Twitter feed. I’ve heard about similar JavaScript game jams before, but this one was new to me. I checked its homepage and it says there are multiple categories, one of them is to create a VR game using A-Frame framework. It caught my attention, I remember I have an online course with this topic but I never watched it, I was thinking it is a good opportunity to do it because participation is enough motivation.

I watched the course, it was pretty short because A-Frame is not a huge topic. It’s an overlay around Three.js with extra functions, add VR view by default, also easy to describe the virtual scene, one object is an HTML tag, pretty straightforward.

I didn’t really have any idea what to do, what I did is just throw some objects on the scene and try to move them. This is what I did in the entire jam, I wasn’t even sure I will finish something by the end. Luckily I managed to upload something, it’s a very simple experience. The player inside a tube made by moving rings to make the illusion of constantly moving forward. Objects are coming, look at them for a short period of time makes the player move forward, don’t look at them move the player backwards, the goal is to move forward to the end of the tube. The name becomes Whirled on the Spirit Spiral thanks for shower thoughts.

The whole thing was pretty new to me, I’ve never tried to make any game in native JavaScript from scratch. I had some experience with the Phaser framework, but what I like is the Unity3D engine to create games. This why I spent much more time on it what I was planning. For example, in the beginning, I was generating all the objects with JavaScript, but I had to realise on this way I can’t disable A-Frame’s default camera and lightings, so I had to refactor a lot of things, but I’m kinda happy with the final structure. It would be easy to extend it. I didn’t really do any crazy optimization for the size limit, I was thinking if I use only primitive objects and pay attention to not over-engineer the code and messing up with global variables saves me plenty of space.

I still found many challenges during the development, I try to remember, collect and describe them below shortly with some basic example but I recommend to check the source code if you are interested, it’s short.

1st challenge: Setup development environment

It’s pretty easy, just use Gulp to run automated tasks.

  1. Pug to Html. I’m always using Pug instead of Html, it’s just much cleaner and I have to type less, which is good.
  2. Minify JavaScript and CSS files for the production version. Even I’m using EcmaScript6 I didn’t bother to setup Babel.JS for support old browsers, I’m expecting that if a Browser is able to run virtual reality experiences ES6 wouldn’t be a problem. Also, it saves space which is essential in this competition.

2nd challenge: The game loop

Unlike with using any game engine, I had to create my own game loop. I was using requestAnimationFrame instead of setTimeout because I could get the time difference between two frames and with this information I can be sure the speed is the same in all the machines at different speed.

gameLoop(timestamp)
{
	this.update(timestamp - state.lastRender)
	this.draw()

	window.requestAnimationFrame(this.gameLoop)
}

3rd challenge: The GameObject

I was creating my own JS class to hold an object, I could add additional information like position and rotation and its own render function.

class GameObject
{
	/**
	 * @param object obj Game object
	 * @param array pos Object position [x, y, z]
	 * @param float speed Object speed
	 * @param int type (0: ring, 1: obstacle)
	 */
	constructor(obj, pos, speed, type = 0)
	{
		this.obj = obj
		this.pos = pos
		this.speed = speed
		this.type = type
	}
}

4th challenge: Object container

I create all the object instances, in the beginning, the game and store the references in an array. I just found out later A-Frame has its own object pool system, I’m using it for instantiating objects but not for more, maybe next time.

5th challenge: Let it move

I’ve two methods runs in every frame, both go through all the game objects. The first method calculates the next position for each object, and store them in the game object.

6th challenge: Render

Simply iterate through the object container and tell to the engine where is the current position and let it render there. I didn’t render the objects after the position calculation straight away, because I wanted to do all the renders as short time as possible.

7th challenge: Effects

There are multiple effects in the game, like rings appear on a funky way, the background fading, etc. This why the calculation and the render should happen separately. If I have more time I could add extra effects, but we just got the basic once, these are not very heavy, the framerate stays ok in VR.

8th challenge: Smooth render

Once an object reached the end of the container moves back to the beginning. Fix “manually” the possibly miscalculated swap position.

if (firstValue >= state.minZ + distance) {
	pool[lastIndex].pos[2] = state.minZ
}

9th challenge: Create the player

The player is an empty game object with camera child. It’s better than using the camera object itself because moving the player forward/backwards really have the moving feeling in VR.

a-entity#player
	a-camera(
		camera-cursor
		look-controls
		rotation-listener
		fov="60")

		//- Crosshair

10th challenge: The crosshair

I just added the crosshair as a child of the camera object, so it always in the middle of the screen. A-Frame has embedded raycast function, I just did set which objects should interact with it and that’s it and the target objects know if they got shot what to do, disappear.

11th challenge: Aiming

Every obstacle got a component which made them able to take care about their own death. It’s pretty easy to switch object’s deathable with html/js by simply add/remove a specific class.

if (
	this.el.classList.contains('obs') &&
	this.el.getAttribute('position').z > state.playerPosZ
) {
	Game.destroy(this)
}

12th challenge: Score system

This receives events and can decide which direction should the player move.

13th challenge: Mobile vs Desktop

The game is using default settings like how many objects are in the screen at the same time etc, and the initial setting has a mobile and a desktop version. When the player chooses the version the initial values populated from the correct array.

14th challenge: The outlook

A-Frame has a very nice visual inspector tool which helps me set up the lighting, just make the objects visible.

I think I could continue to write this list for long, menu, sound etcetera, but I think the point is clear. Even it’s a very short and basic experience there are plenty of things to take care. It would be fun to continue the code, it’s very easy to extend now, add more effects, make the mobile version better, the things I could do before the submission, I just didn’t have too much time to tweak it, and it’s good as it is.

Thank you for reading this post. It’s time to play the game or check the source code.

Leave a Reply

Your email address will not be published.