An Interest In:
Web News this Week
- April 30, 2024
- April 29, 2024
- April 28, 2024
- April 27, 2024
- April 26, 2024
- April 25, 2024
- April 24, 2024
Create a Pokmon GO Style Augmented Reality Game WithVuforia: Part 2
In the last post of this series, we learned how to set up Vuforia and start developing an AR game from scratch, adopting a logic similar to the one used on Pokémon GO!
Create a Pokémon GO Style Augmented Reality Game With Vuforia
Pokémon GO Style Augmented Reality With Vuforia
Pokémon GO Style Augmented Reality: Markers
We've started development of an Augmented Reality game called Shoot the Cubes. Now it's time to improve the game by adding interaction and making the experience more engaging. We'll concentrate mostly on the possibilities Unity gives us, leaving aside Vuforia's specifics. Experience with the Unity engine is not mandatory.
1. Making the Cubes Look Alive
Let's start working on our game. So far we've managed to create an Augmented Reality scene that moves with the user's device. We'll improve this app by making the cubes spawn and fly around, and by letting the player search and destroy them with a laser shot.
1.1. Spawning the Elements
We've already set an initial position of the _SpawnController according to the device camera rotation. Now we'll establish an area around this point where our cubes will spawn. Now we'll update the SpawnScript
to make the _SpawnController instantiate the cube elements with different sizes and random positions, relative to the _SpawnController.
Let's edit the SpawnScript
class, adding some variables to control the spawning process.
public class SpawnScript : MonoBehaviour {
// Cube element to spawn
public GameObject mCubeObj;
// Qtd of Cubes to be Spawned
public int mTotalCubes = 10;
// Time to spawn the Cubes
public float mTimeToSpawn= 1f;
// hold all cubes on stage
private GameObject[] mCubes;
// define if position was set
private bool mPositionSet;
}
We'll create a coroutine called SpawnLoop
to manage the spawn process. It will also be responsible to set the initial position of the _SpawnController when the game begins. Notice that the Random.insideUnitSphere
method causes the cubes to be instantiated at random locations within a spherical area around the _SpawnManager.
public class SpawnScript : MonoBehaviour {
// Loop Spawning cube elements
private IEnumerator SpawnLoop()
{
// Defining the Spawning Position
StartCoroutine( ChangePosition() );
yield return new WaitForSeconds(0.2f);
// Spawning the elements
int i = 0;
while ( i <= (mTotalCubes-1) ) {
mCubes[i] = SpawnElement();
i++;
yield return new WaitForSeconds(Random.Range(mTimeToSpawn, mTimeToSpawn*3));
}
}
// Spawn a cube
private GameObject SpawnElement()
{
// spawn the element on a random position, inside a imaginary sphere
GameObject cube = Instantiate(mCubeObj, (Random.insideUnitSphere*4) + transform.position, transform.rotation ) as GameObject;
// define a random scale for the cube
float scale = Random.Range(0.5f, 2f);
// change the cube scale
cube.transform.localScale = new Vector3( scale, scale, scale );
return cube;
}
}
Finally, edit the Start()
function. Make sure to remove the StartCoroutine( ChangePosition() );
line and replace it with a call to start the SpawnLoop
coroutine.
public class SpawnScript : MonoBehaviour {
void Start () {
// Initializing spawning loop
StartCoroutine( SpawnLoop() );
// Initialize Cubes array according to
// the desired quantity
mCubes = new GameObject[ mTotalCubes ];
}
}
Now back in Unity you'll have to create a cube prefab to be instantiated by the script.
- Create a folder called Prefabs in the Project window.
- Change the Cube element scale on all axes to 1 and change the rotation to 0 on all axes.
- Drag the Cube to the Prefabs folder.
- Delete the Cube from the Hierarchy window.
- Select the _SpawnController and drag the Cube prefab from the Prefabs folder to the M Cube Obj field, located in the
SpawnScript
area of the inspector.
Now, if you press play in Unity and and run the project on the device, you should see the cubes spawning.
1.2. Rotating Cubes
We need to add movement to those cubes to make things more interesting. Let's rotate the cubes around their axes and over the ARCamera. It would be also cool to add some random factor over the cube movement to create a more organic feel.
Drag the Cube Prefab from the Prefabs folder to the hierarchy.
- On the Scripts folder create a new C# Script called CubeBehaviorScript.
- Drag the Script to the Cube prefab and open it to edit.
Each cube will have random characteristics. The size, rotation speed and rotation direction will be defined randomly, using some references previously defined. Let's create some controller variables and initialize the state of the cube.
using UnityEngine;
using System.Collections;
public class CubeBehaviorScript : MonoBehaviour {
// Cube's Max/Min scale
public float mScaleMax = 2f;
public float mScaleMin = 0.5f;
// Orbit max Speed
public float mOrbitMaxSpeed = 30f;
// Orbit speed
private float mOrbitSpeed;
// Anchor point for the Cube to rotate around
private Transform mOrbitAnchor;
// Orbit direction
private Vector3 mOrbitDirection;
// Max Cube Scale
private Vector3 mCubeMaxScale;
// Growing Speed
public float mGrowingSpeed= 10f;
private bool mIsCubeScaled= false;
void Start () {
CubeSettings();
}
// Set initial cube settings
private void CubeSettings(){
// defining the anchor point as the main camera
mOrbitAnchor = Camera.main.transform;
// defining the orbit direction
float x = Random.Range(-1f,1f);
float y = Random.Range(-1f,1f);
float z = Random.Range(-1f,1f);
mOrbitDirection = new Vector3( x, y , z );
// defining speed
mOrbitSpeed = Random.Range( 5f, mOrbitMaxSpeed );
// defining scale
float scale = Random.Range(mScaleMin, mScaleMax);
mCubeMaxScale = new Vector3( scale, scale, scale );
// set cube scale to 0, to grow it lates
transform.localScale = Vector3.zero;
}
}
Now it's time to add some movement to our cube. Let's make it rotate around itself and around the ARCamera, using the random speed and direction defined earlier.
// Update is called once per frame
void Update () {
// makes the cube orbit and rotate
RotateCube();
}
// Makes the cube rotate around a anchor point
// and rotate around its own axis
private void RotateCube(){
// rotate cube around camera
transform.RotateAround(
mOrbitAnchor.position, mOrbitDirection, mOrbitSpeed * Time.deltaTime);
// rotating around its axis
transform.Rotate( mOrbitDirection * 30 * Time.deltaTime);
}
To make it more organic, the cube will scale up from size zero after it is spawned.
// Update is called once per frame
void Update () {
// makes the cube orbit and rotate
RotateCube();
// scale cube if needed
if ( !mIsCubeScaled )
ScaleObj();
}
// Scale object from 0 to 1
private void ScaleObj(){
// growing obj
if ( transform.localScale != mCubeMaxScale )
transform.localScale = Vector3.Lerp( transform.localScale, mCubeMaxScale, Time.deltaTime * mGrowingSpeed );
else
mIsCubeScaled = true;
}
2. Searching and Destroying
Those cubes are too happy flying around like that. We must destroy them with lasers! Let's create a gun in our game and start shooting them.
2.1. Shooting a Laser
The laser shot must be connected to the ARCamera and its rotation. Every time the player 'taps' the device's screen, a laser will be shot. We'll use the Physics.Raycast
class to check if the laser hit the target and if so we'll remove some health from it.
- Create a new empty object named _PlayerController and another empty object called _LaserController inside of it.
- Add a C# script called LaserScript inside the Scripts folder and drag it to _LaserController.
Inside LaserScript, we'll use a LineRenderer
to show the laser ray, using an origin point connected to the bottom of the ARCamera. To get the origin point of the laser ray—the barrel of the virtual gun—we'll get the camera Transform
at the moment when a laser is shot and move it 10 units down.
First, let's create some variables to control the laser settings and get mLaserLine
.
using UnityEngine;
using System.Collections;
public class LaserScript : MonoBehaviour {
public float mFireRate = .5f;
public float mFireRange = 50f;
public float mHitForce = 100f;
public int mLaserDamage = 100;
// Line render that will represent the Laser
private LineRenderer mLaserLine;
// Define if laser line is showing
private bool mLaserLineEnabled;
// Time that the Laser lines shows on screen
private WaitForSeconds mLaserDuration = new WaitForSeconds(0.05f);
// time of the until the next fire
private float mNextFire;
// Use this for initialization
void Start () {
// getting the Line Renderer
mLaserLine = GetComponent<LineRenderer>();
}
}
The function responsible for shooting is Fire()
. That will be called every time the player presses the fire button. Notice that Camera.main.transform
is being used to get the ARCamera position and rotation and that the laser is positioned 10 units below that. This positions the laser at the bottom of the camera.
// Shot the Laser
private void Fire(){
// Get ARCamera Transform
Transform cam = Camera.main.transform;
// Define the time of the next fire
mNextFire = Time.time + mFireRate;
// Set the origin of the RayCast
Vector3 rayOrigin = cam.position;
// Set the origin position of the Laser Line
// It will always 10 units down from the ARCamera
// We adopted this logic for simplicity
mLaserLine.SetPosition(0, transform.up * -10f );
}
To check if the target was hit, we'll use a Raycast
.
// Shot the Laser
private void Fire(){
// Hold the Hit information
RaycastHit hit;
// Checks if the RayCast hit something
if ( Physics.Raycast( rayOrigin, cam.forward, out hit, mFireRange )){
// Set the end of the Laser Line to the object hit
mLaserLine.SetPosition(1, hit.point );
} else {
// Set the enfo of the laser line to be forward the camera
// using the Laser range
mLaserLine.SetPosition(1, cam.forward * mFireRange );
}
}
At last, it's time to check if the fire button was pressed and call the laser effects when the shot is fired.
// Update is called once per frame
void Update () {
if ( Input.GetButton("Fire1") && Time.time > mNextFire ){
Fire();
}
}
private void Fire() {
// anterior code supressed for simplicity
// Show the Laser using a Coroutine
StartCoroutine(LaserFx());
}
// Show the Laser Effects
private IEnumerator LaserFx(){
mLaserLine.enabled = true;
// Way for a specific time to remove the LineRenderer
yield return mLaserDuration;
mLaserLine.enabled = false;
}
Back in Unity we'll need to add a LineRenderer
component to the _LaserController object.
- Select _LaserController and in the Inspector window, click on Add Component. Name it "Line Renderer" and select the new component.
- Create a new folder called Materials, and create a new material inside of it called Laser.
- Select the Laser material and change it to any color that you like.
- Select the _LaserController and drag the Laser material to the Materials field of the LineRenderer component.
- Still in LineRenderer, under Parameters set Start With to 1 and End With to 0.
If you test the game now you should see a laser being shot from the bottom of the screen. Feel free to add an AudioSource component with a laser sound effect to _LaserController to spice it up.
2.1. Hitting the Cubes
Our lasers need to hit their targets, apply damage and eventually destroy the cubes. We'll need to add a RigidBody to the cubes, applying force and damage to them.
Drag the Cube prefab from the prefabs folder to any place on the Stage.
Select the Cube and select Add Component in the Inspector window. Name the new component "RigidBody" and select it.- On the RigidBody component set Gravity and Is Kinematic to Off.
- Apply those changes to the prefab.
Now let's edit the CubeBehavior
script to create a function responsible for applying damage to the cube and another one for destroying it when the health falls below 0.
public class CubeBehaviorScript : MonoBehaviour {
// Cube Health
public int mCubeHealth= 100;
// Define if the Cube is Alive
private bool mIsAlive = true;
// Cube got Hit
// return 'false' when cube was destroyed
public bool Hit( int hitDamage ){
mCubeHealth -= hitDamage;
if ( mCubeHealth >= 0 && mIsAlive ) {
StartCoroutine( DestroyCube());
return true;
}
return false;
}
// Destroy Cube
private IEnumerator DestroyCube(){
mIsAlive = false;
// Make the cube desappear
GetComponent<Renderer>().enabled = false;
// we'll wait some time before destroying the element
// this is usefull when using some kind of effect
// like a explosion sound effect.
// in that case we could use the sound lenght as waiting time
yield return new WaitForSeconds(0.5f);
Destroy(gameObject);
}
}
Okay, the cube can take now damage and be destroyed. Let's edit the LaserScript
to apply damage to the cube. All we have to do is change the Fire()
function to call the Hit
method of the CubeBehavior
script.
public class LaserScript : MonoBehaviour {
// Shot the Laser
private void Fire(){
// code supressed for simplicity ...
// Checks if the RayCast hit something
if ( Physics.Raycast( rayOrigin, cam.forward, out hit, mFireRange )){
// Set the end of the Laser Line to the object hitted
mLaserLine.SetPosition(1, hit.point );
// Get the CubeBehavior script to apply damage to target
CubeBehaviorScript cubeCtr = hit.collider.GetComponent<CubeBehaviorScript>();
if ( cubeCtr != null ) {
if ( hit.rigidbody != null ) {
// apply force to the target
hit.rigidbody.AddForce(-hit.normal*mHitForce);
// apply damage the target
cubeCtr.Hit( mLaserDamage );
}
}
}
}
3. Conclusion
Congratulations! Our Augmented Reality game is finished! Yes, the game could be more polished, but the basics are there and the overall experience is pretty engaging. To make it more interesting you could add a particle explosion, like I did in the video, and on top of that, you could add a score system or even a wave system with a timer to make it more of a challenge. The next steps are up to you!
3.1. What's next?
We created an interesting AR experiment using Vuforia on Unity, however we still have a lot of cool features to cover. We didn't see any of the more sophisticated Vuforia resources: Targets, Smart Terrain, Cloud, and so on. Stay tuned for the next tutorials, where we'll cover more of those features, always using the same step-by-step approach.
See you soon!
Original Link:
TutsPlus - Code
Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.More About this Source Visit TutsPlus - Code