我们已经开始开发名为Shoot the Cubes的增强现实游戏。 现在是时候通过增加互动和增加体验来改进游戏了。 我们将主要关注Unity给我们带来的可能性,而忽略Vuforia的细节。 并非必须具有Unity引擎的经验。
1.使立方体看起来活着
让我们开始游戏吧。 到目前为止,我们已经成功创建了一个可以与用户设备一起移动的增强现实场景。 我们将通过使多维数据集生成并在周围飞行,并让玩家使用激光射击搜索并销毁它们来改进此应用程序。
产生元素
我们已经根据设备摄像机的旋转设置了_SpawnController的初始位置。 现在,我们将在此点附近建立一个区域,在该区域将生成多维数据集。 现在,我们将更新SpawnScript
以使_SpawnController实例化相对于_SpawnController具有不同大小和随机位置的多维数据集元素。
让我们编辑SpawnScript
类,添加一些变量来控制生成过程。
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;
}
我们将创建一个名为SpawnLoop
的协同程序来管理生成过程。 游戏开始时,还将负责设置_SpawnController的初始位置。 注意, Random.insideUnitSphere
方法使多维数据集在_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;
}
}
最后,编辑Start()
函数。 确保删除StartCoroutine( ChangePosition() );
行并替换为启动SpawnLoop
协程的调用。
public class SpawnScript : MonoBehaviour {
void Start () {
// Initializing spawning loop
StartCoroutine( SpawnLoop() );
// Initialize Cubes array according to
// the desired quantity
mCubes = new GameObject[ mTotalCubes ];
}
}
现在回到Unity,您必须创建一个多维数据集预制模块,以通过脚本实例化。
- 在“ 项目”窗口中创建一个名为Prefabs的文件夹。
- 将所有轴上的多维数据集元素比例更改为1,并将所有轴上的旋转比例更改为0 。
- 将多维数据集 拖到Prefabs文件夹。
- 从“ 层次结构”窗口中删除多维数据集。
- 选择_SpawnController并将Cube预制件从Prefabs文件夹拖到位于检查器
SpawnScript
区域中的M Cube Obj字段。
现在,如果您在Unity中按play并在设备上运行项目,则应该看到生成了多维数据集。
旋转立方体
我们需要向这些立方体添加运动以使事情变得更加有趣。 让我们绕立方体的轴旋转并越过ARCamera 。 在立方体运动上添加一些随机因素以创建更自然的感觉也是很酷的。
将“ 多维数据集预制”从“预制”文件夹拖到层次结构中。
- 在“ 脚本”文件夹中,创建一个名为CubeBehaviorScript的新C#脚本 。
- 将脚本拖到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;
}
}
现在是时候向立方体添加一些运动了。 让我们使用之前定义的随机速度和方向使其围绕自身和ARCamera旋转。
// 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);
}
为了使其更加有机,在生成多维数据集之后,多维数据集将从零开始放大。
// 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.搜索和销毁
那些立方体像那样飞来飞去太高兴了。 我们必须用激光摧毁它们! 让我们在游戏中制造一把枪,然后开始射击。
射击激光
激光束必须连接到ARCamera及其旋转。 每次播放器“敲击”设备屏幕时,都会发射激光。 我们将使用Physics.Raycast
类来检查激光是否击中目标,如果是,我们将从中移除一些生命值。
- 创建一个名为_PlayerController一个新的空对象和另一个叫它_LaserController内空的对象。
- 在Scripts文件夹内添加一个名为LaserScript的C#脚本 ,并将其拖到_LaserController 。
在LaserScript内部,我们将使用LineRenderer
通过连接到ARCamera底部的原点显示激光束 。 为了获得激光的起点(虚拟枪的枪管),我们Transform
在发射激光时将相机Transform
为“ Transform
”并将其向下移动10个单位。
首先,让我们创建一些变量来控制激光设置并获取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>();
}
}
负责射击的函数是Fire()
。 每当玩家按下击键时,就会调用该命令。 请注意,正在使用Camera.main.transform
来获取ARCamera的位置和旋转,并且将激光器放置在其下方10个单位处。 这会将激光定位在相机的底部。
// 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 );
}
为了检查目标是否被击中,我们将使用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 );
}
}
最后,是时候检查射击按钮是否按下并在射击时调用激光效果了。
// 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;
}
回到Unity,我们需要向_LaserController对象添加LineRenderer
组件。
- 选择_LaserController,然后在“ 检查器”窗口中,单击“ 添加组件” 。 将其命名为“ Line Renderer ”,然后选择新组件。
- 创建一个名为Materials的新文件夹,并在其中创建一个名为Laser的新材料。
- 选择激光材料并将其更改为所需的任何颜色。
- 选择_LaserController并将Laser材质拖动到LineRenderer组件的Materials字段。
- 仍在LineRenderer中 ,在“ 参数”下将“ 开始为1”和“ 结束为0” 。
如果现在测试游戏,您应该会从屏幕底部看到一束激光。 随意用激光声音效果_LaserController添加的AudioSource组件香料它。
击中立方体
我们的激光器需要击中目标,对其造成伤害并最终破坏立方体。 我们需要向立方体添加一个RigidBody ,对其施加力和损坏。
- 将 Cube预制件从prefabs文件夹中拖到舞台上的任何位置。
- 选择 多维数据集,然后选择添加组件 检查器窗口。 将新组件命名为“ RigidBody ”并选择它。
- 关于RigidBody分量集的重力和运动到关 。
- 将这些更改应用于预制件。
现在,让我们编辑CubeBehavior
脚本,以创建一个函数,该函数负责对多维数据集施加损害,而另一个函数则在运行状况低于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);
}
}
好的,魔方现在可以受到伤害并被摧毁。 让我们编辑LaserScript
以对立方体施加伤害。 我们要做的就是更改Fire()
函数以调用CubeBehavior
脚本的Hit
方法。
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.结论
恭喜你! 我们的增强现实游戏结束了! 是的,游戏可能会更加精致,但是基础知识已经存在,整体体验非常吸引人。 为了使它更有趣,您可以像在视频中一样添加粒子爆炸,此外,还可以添加计分系统或带有计时器的波动系统,使其更具挑战性。 下一步由您决定!
下一步是什么?
我们在Unity上使用Vuforia创建了一个有趣的AR实验,但是我们仍然要涵盖很多很酷的功能。 我们没有看到任何更复杂的Vuforia资源:目标,智能地形,云等。 请继续关注下一个教程,在本文中,我们将始终使用相同的逐步方法来介绍更多这些功能。
再见!