RC Deathmatch

PLAY NOW DEV BLOG

Choose a vehicle & enjoy! Each vehicle has its own unique properties plus a nifty grappling hook.
http://www.jumpstartsdk.com/live/RCDM.html

Developing RC Deathmatch in AltspaceVR w/ three.js

by developer Elijah Newman-Gomez

Concept

One of my favorite things to do in VR is inspect models. In most deathmatch games the characters move very quickly and it's hard to appreciate their epicness in VR. I wanted a more chill & casual deathmatch game that let you enjoy VR with your friends without frantically dodging bullets just to survive.

The most important gameplay elements to achieve this would be slow-moving vehicles and easy-going controls that allow for momentary distractions. Taking a moment to inspect a model up-close, teleporting yourself to a new position, or looking over at a friend to say something shouldn't result in insta-death like in regular deathmatch games.

Slow-moving remote control cars, planes, & helicopters in a fight for survival seemed like a perfect fit for the virtual environments of AltspaceVR. Plus the simple concept of RC vehicles provides endless gameplay possibilities for singleplayer missions, multiplayer coop, and of course multiplayer team deathmatch.

Prototype

Before jumping straight into the JavaScript, I decided on the technical design goals that I'd need to achieve in order to pull this off. Having these features in a working prototype would mean that the rest of my plans would be possible.
  • Vehicles must be easy to control on both standard gamepads and VR gamepads.
  • Vehicles must be smoothly synced in a multiplayer environment.
  • The experience of just flying your vehicle around needs to be fun.

With that I had everything I needed to start coding RC Deathmatch in JavaScript. This wasn't my first app, so I already had a framework ready to go. I just dropped in a helicopter model w/ some spinning blades, added some listeners and callback functions, and the prototype was ready to go!

The good people at the AltspaceVR SDK Developer Meetup were more than happy to test out the prototype and give the feedback that I needed to keep going with the concept: it was fun!


Expanding Gameplay: Grappling Hook

Even without weapons, flying around and trying not to crash into the ground was fun. To build this into the core gameplay, a short grappling hook was added. This made flying low to the ground to grab powerups using your hook essential. However, for this to work, the powerups that you get for ship would have to be pretty cool.

The ability for all vehicles to carry something also opened up other gameplay possibilities, such as capture-the-flag or drop-the-bomb.


Expanding Gameplay: Vehicle Customization

Players love to customize stuff, especially when it provides unique stat upgrades that lets them fine-tune and specialize their vehicles to how they play.

In multiplayer games, being able to express yourself through unique vehicle customizations adds not only to the social aspect, but also to replay value as the player builds their stats to unlock rarer customization options.

The first major change to RCDM's design was an extensive vehicle power-up & upgrade system. This system allows for an arbitrary number of add-on "parts" to be associated with each vehicle type, in addition to the vehicle's body, that each perform their own logic.

These behaviors are applied on top of the base RCDM behaviors that apply to ALL vehicle types, such as health, taking damage, and auto-syncing.


Expanding Gameplay: Arena Customization

Custom arena building gives creators another outlet for self-expression, and provides players with fresh new addon arenas created by their friends.

For custom arena building to work, there would have to be generalized prop behaviors to control the different objects that the player might spawn in their arena. The first of these prop behaviors was the "grippable" behavior.

Simply applying the grippable behavior to a prop made it able to be carried by a vehicle's grappling hook. This could be used for something as simple as a wrecking ball, to something as complex as a bomb who's fuse lights as soon as it's picked up.

Some other very useful behaviors for props are the "cylinderCollide" and "sphereCollide" behaviors which make vehicles see props as solid objects. Or the "physics" behavior which causes props to fall to the ground or be launched into the air.

These simple behaviors combined with a variety of 3D models to apply them to could provide for a very wide range of interactive props for players to fill their arenas with.

Asynchronous Loading, Bubble-In, & Drop Shadows

With such a huge variety of addon vehicle customizations possible, pre-caching the assets for *every* vehicle part would be impractical if not impossible. So I created yet another behavior that would asynchronously load the model of a custom part in while not interfering with the functioning of the part itself.

In particular, the asyncModel behavior provides a temporary bounding radius until the model is fully loaded and the actual bounding radius can be calculated. It also provides callbacks for when the model is fully loaded so additional logic can be performed.

Instead of objects just appearing out of nowhere after they are loaded, they use the bubbleIn behavior. This behavior animates the scale of the newly loaded model to bubble-in from near-zero to full-scale. The effect is a very nice compliment to the asyncModel behavior.

The dropShadow behavior causes the object to cast a shadow onto the floor of the enclosure equal to the size of the object's bounding radius. Drop shadows are extremely important as they are the primary visual cue that players use to determine their vehicles position in relation to other flying objects. All grippable props, vehicles, and bullets all use the dropShadow behavior.

These are just some of the generic behaviors used to create the RC Deathmatch app, which will be expanded upon as more addon vehicle types & arena props are created for the system.

JavaScript Examples

Here's some examples of what it took to get my helicopter all rigged up using my app framework, called JumpStart. Of course, you could use similar logic with any app framework because it's all just three.js in the end. Awesome!

As always, the tricky part is coding it all in a way that is multiplayer-friendly. This means a lot of listeners & callbacks instead of good 'ol linear code, but it still turns out to be pretty linear when you read it.

To start things off, the vehicle type of a basic chopper could be defined as:

CODE:
var vehicleType = {
	"id": "chopper",
	"name": "Rambo",
	"parts":
	{
		"body":
		{
			"modelFile": "models/chopper"
		},
		"blades":
		{
			"modelFile": "models/chopper_blades",
			"offset": new THREE.Vector3(0, 8.81, 2.88),
			"rotate": new THREE.Vector3(0, 0, 0),
			"rotSpeed": -5.0
		},
		"backBlades":
		{
			"modelFile": "models/chopper_blades_back",
			"offset": new THREE.Vector3(0, 3.982, -27.848),
			"rotate": new THREE.Vector3(0, 0, 0),
			"rotSpeed": -8.0
		}
	}
};

Each vehicle will have unique parts, and each part will have it's own unique set of customizable properties. The only part that all vehicles must have is the body because it is used to calculate the vehicle's collision radius.

Spawning the vehicle that uses this chopper vehicle type is as easy as:

CODE:
// spawn an object with no model as a container for our vehicle
var vehicle = jumpStart.spawnInstance(null);

// apply the base rcdm behavior using the chopper vehicle type
vehicle.applyBehavior("rcdm", {"custom": {"vehicleTypeName": "chopper"}});

// automatically remove this object when the local user disconnects
vehicle.applyBehavior("autoRemoval");

// sync object to the multiplayer session
vehicle.sync();

The base rcdm behavior will automatically rig up the vehicle and put the parts into the userData.rcdm.parts object for the vehicle type's code to work with. It will also trigger callbacks in the vehicle type's code so it can do important things like applying the logic for those unique parts:

CODE:
// apply logic to blades
this.userData.rcdm.parts.blades.addEventListener("tick", function()
{
	// get a reference to this vehicle to get user-customized values
	var vehicle = this.userData.vehicle;

	// get a reference to this vehicle type in case we need default values
	var vehicleType = jumpStart.behaviors.rcdm.getVehicleType("chopper");

	// apply the default rotSpeed
	var rotSpeed = vehicleType.parts.backBlades.rotSpeed;

	// override with a custom value if available
	if( !!vehicle.syncData.rcdm.custom.parts.back &&
		vehicle.syncData.rcdm.custom.parts.back.rotSpeed )
		rotSpeed = vehicle.syncData.rcdm.custom.parts.back.rotSpeed;

	// animate the blades
	this.rotateY(rotSpeed * jumpStart.deltaTime);
});

Of course spinning blades is the simplest behavior that a part can perform. More interesting parts, such as cannons, perform more complex logic that even spawns additional objects into the scene.

The modular design of the vehicle system allows for players to create extremely unique vehicles without altering any code. And thanks to the hierarchical nature of the base rcdm class controling the basic behaviors of *all* vehicles, they are all able to interact with other vehicles & props that could potentially exist in the same enclosure.

Art Assets

Up to this point, I could have coded the entire app using nothing but a default box as a placeholder model. But for the app to be fun to look at, it needed some quality art assets for the different vehicles.

Instead of spending the time to create the art assets myself from scratch, I went over to CGTrader.com and found a very nice low-poly airplane pack that was well worth its price.

Dropping these assets into the app and rigging them up with default part logic turned RC Deathmatch into a very fun & visually appealing experience. There's something special about seeing the little parts move on the toy vehicles inside of VR.

I gave all the vehicles unique nicknames so that players could easily communicate which their favorites were. When addon parts are added to vehicles, such as cannons, they are painted to match the color of the vehicle's body.

Further Improvements

Now that the systems for supporting all this user-generated-content of vehicle customizations, addon vehicles types, & addon deathmatch arenas are in-place, the tools for generating them must be created. This will be the focus as development moves forward with RC Deathmatch.

Menu systems for customizing your vehicle, a wide assortment of powerups & parts to collect, and an arena-building mode are next on the development road-map. After these are incorporated, RC Deathmatch will be ready to take on a life of its own powered by user-generated-content from the players themselves.

See you soon on the battlefield in version 1.0!

BACK TO TOP