Explosive Tutorial With Unity3D and VRTK

Robert Rice .NET, Technology Snapshot, Tutorial Leave a Comment

Opinions on the emerging Virtual Reality market vary. One one end, there are those who say it’s just a gimmick and will pass shortly. On the other end, there are those who herald it as the birth pangs of a paradigm shift in how we interact with technology.

I sit somewhere in the middle. I own an HTC Vive and it is pretty dang awesome. The experience is not perfect, of course, but with interest growing and prices coming down, it’s just going to get better.

One expression of VR’s growing popularity is that Unity3D supports VR programming. And, with the free VRTK (Virtual Reality Tool Kit) framework, it’s becoming much easier to get started programming for VR. VRTK implements many basic components, such as:

  • various movement implementations
  • object interaction
  • projectiles

Working on a fun little side project, I noticed one implementation it did not have: a virtual reality bomb. So, I set upon to create one myself. This post details the process I went through for creating a timed, throwable, explosive object for virtual reality using Unity3D & VRTK. I include highly-commented code samples at the end of this tutorial.

A caveat…unlike many tutorials I see online, I’m going to skip what I assume are some basic knowledge requirements, such as what Unity3D is and how to navigate it and its store interface. It’s pretty easy to educate yourself on this elsewhere and it’s actually pretty intuitive.

Let’s Get Started

So, given that you have already installed or know how to install at least the free version of Unity3D, start a new 3D project.

At the very least, import the VRTK from the Unity Store, and the VR headset API (in my case, SteamVR), if applicable. Otherwise, VRTK implements a “fake” VR view to test your changes (basically a standard flat screen FPS view). VRTK will prompt you on import to keep a bunch of default settings; yes, keep them all.

There are a few pieces of existing functionality we need: grabbing an object and using an object. I used project 008_Controller_UsingAGrabbedObject as my base, as it contains exactly what we need and little else.

First thing we want to do is to get rid of all unnecessary objects in the scene. In the Hierarchy view, under ExampleWorldObjects, delete the Gun object and every thing under and including the TypeTests object.

Delete the highlighted objects.

Drop the attached Bomb.cs script (included in the download) into the ExampleResources/Scripts folder. Remove the Whirlygig script from the Whirlygig object and drop the Bomb.cs script in its place.

As opposed to instructing the code in the Bomb.cs script line by line, I have instead included a highly commented version of it at the end of this article. Also, go ahead and add an empty game object to the scene and name it Wall. We’ll need this later when we create something for the bomb to blow up. I’m including it now so we can just be done with editing the hierarchy.

Delete the Capsule shape from the Whirlygig object. Replace the cube(mesh filter) on the Whirlygig object with a sphere mesh filter. Remove the box collider from the Whirlygig object and add a sphere collider in its place. Finally, rename the Whirlygig object to Bomb. You should end up with this:

Visual

We will need to create an explosion Particle System to visually represent the explosion by following the instructions here. Note that this page describes using fire add image, which does not appear to exist. I used a particle called Firecloud instead. You will need to be sure to also uncheck Play on Awake and Looping in the Inspector view for the ParticleSystem.

Once you are satisfied with the way the particle looks, drag it from the Scene view into the Prefab folder in Project view. This converts the particle into a prefab, so that we can instantiate it on-demand via script. Once the prefab is created, delete the instance you created in the Scene view. The Bomb.cs script will have an explosion attribute you can see in the Inspector view. Select the explosion prefab you created and drop it onto the associated empty field.

Sound

We will also need an explosion sound. Add an Audio Source component to the Bomb object. Drop the attached audio file (included in the download) onto the AudioClip attribute. Ensure both Play on Awake and Is Looping are unchecked.

A few items of clean up. Ensure that on the Bomb.cs script attached to the Bomb object, that Is Useable and Is Grabbable are both checked. I have both Hold button to grab and Hold button to use unchecked, but that is up to personal preference. The effect of each should be fairly evident; the actions are toggled when these are unchecked.

Damage

An explosion wouldn’t be much fun without something to blow up. In this case, I’m not talking about damage, just a concussion effect on physical objects; makes the explosion a little more exciting.

Let’s create a wall of blocks to blow up. Drop the attached InstantiateWall.cs (included in the download) into the scripts folder (as before, I didn’t go line by line, but provide the commented source below). Drop this script onto the empty game object Wall we created earlier.

We will also need to go the the Tags and Layers view and add a new tag called Wall. This is to ensure that when the explosion force is determining which game objects to affect, it only affects the wall blocks (and not the floor, etc). Tagging objects is good practice for organization as well.

Bomb.cs Code

A few notes about the Bomb.cs code. The isActivated attribute was added since clicking on the use button calls the StartUsing method, but the responsibility of updating the object is in the Update method. A state needed to be set to communicate between the two methods, and isActivated accomplishes this.

And since we did not want to call the explosion immediately upon use, we check this status and use the Invoke method, which waits a length of time defined by its second parameter before calling the method defined by its first parameter.

using System.Collections;
using System;<span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>

namespace VRTK.Examples
{
    using UnityEngine;

    public class Bomb : VRTK_InteractableObject
    {
		public float fuseTime;//time between clicking the use button and detonation
		private bool isActivated = false;//true when use button is clicked, indicates that the "fuse has been lit"
		public ParticleSystem explosion;//explosion visual effects

		public float radius = 1000.0F;//radius to check for objects affected by explosion
		public float power = 1000.0F;//energy of explosion

        public override void StartUsing(VRTK_InteractUse usingObject)
        {
            base.StartUsing(usingObject);
			isActivated = true;//bomb state set to "lit"
        }

        public override void StopUsing(VRTK_InteractUse usingObject)
        {
            base.StopUsing(usingObject);
			isActivated = false;//bomb no longer "lit"
        }

		protected void Start() {
		}

        protected override void Update()
        {
            base.Update();
			if (isActivated) {//if use button has been clicked
				Invoke ("Detonate", fuseTime);
				isActivated = false;
			}
		}

		void Detonate(){
			var explosionSound = GetComponent<AudioSource> ();
			if (!explosion.IsAlive ()) {//to keep it from looping, since update gets called every "tick"
				Vector3 centerOfExplosion = gameObject.transform.position;
				AudioSource.PlayClipAtPoint (explosionSound.clip, centerOfExplosion);
				Destroy (gameObject);//destroy "bomb" first so it disappears at point of explosion
				Instantiate( explosion, centerOfExplosion, Quaternion.identity );
//This instantiates the explosion prefab we created and places it at the current position of the bomb object
				ImpactObjects (centerOfExplosion);
			}
		}

		void ImpactObjects(Vector3 explosionPosition)
		{
			/*
			 * Find all "Wall" objects within range of explosion and apply the explosive force to each
			 * */
			Vector3 explosionPos = explosionPosition;
			Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
			foreach (Collider hit in colliders)
			{
				if (hit.gameObject.CompareTag("Wall")) {
					Rigidbody rb = hit.GetComponent<Rigidbody>();
					if (rb != null) {
						rb.AddExplosionForce (power, explosionPos, radius, 3.0F, ForceMode.Impulse);
					}
				}

			}
		}

    }
}

Quick look at the InstantiateWall script. Basically it just creates a set of cubes with RigidBody components, which are need to exert physical force on. Note we also set each cube with the tag value Wall. Both the RigidBody and tag are needed for our explosion code to affect the cubes.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InstatiateWall : MonoBehaviour {

	// Use this for initialization
	void Start () {
		for (int y = 0; y < 5; y++) {
			for (int x = 0; x < 5; x++) {
				GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
				cube.AddComponent<Rigidbody>();
				cube.tag = "Wall";
				cube.transform.position = new Vector3(x, y, 5);
				cube.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
			}
		}
	}

	// Update is called once per frame
	void Update () {

	}
}

Ready To Go

Now it’s ready to go. Run your program (and slap on your headset if you have one).

Pick up the bomb (ball) and use it. Five seconds later it should explode. Toss it at the wall before that happens for the most spectacular effect. Here’s what you should see:

This is, of course, just a rudimentary implementation of a bomb. This example could be improved in several ways, like:

  • A better bomb model
  • A countdown effect like ticking, or color flashing
  • Damage to physical objects

Here’s a link to the Project Resources.

Thanks for reading!


About the Author
Robert Rice

Robert Rice

Robert Rice is a software developer with 11+ years of experience with Java technologies. Long-time consultant working with the creation, enhancement, and maintenance of a complete insurance management system. Other interests include health, fitness, and winning the 2015 Keyhole Software Halloween Costume Contest.


Share this Post

Leave a Reply