В этом уроке мы вернемся к библиотеке Vuforia Augmented Reality (AR), исследуя один из ее самых интересных ресурсов — Image Target . Мы расширим игру Shoot the Cubes, которую мы создали на предыдущих уроках, добавив новый уровень, где игрок должен защищать свою базу от атакующих кубов.
Этот учебник может быть выполнен в одиночку, хотя, если вы хотите познакомиться с AR с помощью Vuforia и Unity3D, ознакомьтесь с предыдущими статьями серии.
-
Мобильная разработкаПокемон GO Стиль дополненной реальности с Vuforia
-
Мобильная разработкаСоздайте игру дополненной реальности Pokémon GO Style с Vuforia
Цели изображения
Любое изображение может быть Vuforia Image Target . Однако чем детальнее и сложнее изображение, тем лучше оно будет распознаваться алгоритмом.
Многие факторы будут частью распознавания вычислений, но в основном изображение должно иметь разумный уровень контрастности, разрешения и отличительных элементов. Фотография голубого неба не сработает очень хорошо, но картинка с травой будет работать изящно. Целевые изображения могут быть отправлены вместе с приложением, загружены в приложение через облако или непосредственно созданы пользователем в приложении.
Добавление цели
Давайте начнем с добавления элемента ImageTarget
в наш проект Unity.
Сначала загрузите материалы курса с кнопки на боковой панели. Затем в своем проекте Unity создайте новую сцену с именем DefendTheBase : в окне « Проект» выберите папку « Сцены » и нажмите « Создать» > « Сцена». Теперь откройте эту сцену и удалите все объекты сцены по умолчанию из иерархии.
Далее мы добавим свет и камеру. Нажмите Add > Light > Directional Light, чтобы добавить направленный свет. Выберите этот новый источник света и установите « Мягкую тень» в качестве параметра « Тип тени» .
После этого перетащите объект ARCamera из Vuforia > Prefabs . Выберите объект ARCamera и на панели инспектора установите лицензионный ключ приложения, созданный на странице разработчика Vuforia ( инструкции см. В первом руководстве ). Выберите DEVICE_TRACKING для World Center Mod .
Наконец, перетащите ImageTarget в иерархию от Vuforia > Prefabs .
Теперь мы должны добавить базу данных Vuforia. Сначала перейдите на https://developer.vuforia.com/target-manager . Нажмите на Добавить базу данных и выберите имя.
Есть три типа базы данных на выбор:
- Устройство : база данных сохраняется на устройстве, и все цели обновляются локально.
- Облако : База данных на серверах Vuforia.
- VuMark : База данных, эксклюзивная для целей VuMark. Он также сохраняется на устройстве.
В этом случае выберите опцию « Устройство» и нажмите « Создать» .
Выберите новую базу данных, чтобы мы могли начать добавлять к ней цели. Теперь пришло время добавить цели в базу данных. Сейчас мы просто будем использовать опцию Single Image .
Перейдите к ранее загруженным файлам, выберите ImageTarget1 , установите его ширину 1 и нажмите « Добавить» . (Примечание. Если вы предпочитаете создавать собственную цель изображения, сначала прочтите руководство .)
Теперь вы можете скачать базу данных, выбрав Unity Editor в качестве выбранной платформы. Откройте файл и выберите все элементы для импорта. Мы также должны подготовить нашу сцену Unity для распознавания ImageTarget с этой базой данных, которую мы создали.
В редакторе Unity нажмите на объект I mageTarget . Сначала найдите и разверните Image Target Behavior в инспекторе объектов. Выберите тип предопределенного . Выберите цель изображения, которую мы создали ранее для базы данных . Наконец, убедитесь, что опции Enable Extended Tracking и Enable Smart Terrain отключены.
Префаб ImageTarget состоит из ряда компонентов, включая некоторые сценарии, такие как Image Target Behavior, T urn Off Behavior и обработчик событий по умолчанию для Tracker . Если вы хотите глубоко понять, как работает система, прочитайте эти сценарии и попытайтесь понять их связь с другими компонентами.
Для этого урока мы не будем копать слишком глубоко. Нам нужно сконцентрироваться только на обработчике событий по умолчанию для трекера , который принимает вызовы, когда изменяется статус отслеживания цели изображения. Итак, давайте использовать этот скрипт в качестве основы для создания нашего собственного поведения скрипта.
Создайте копию этого скрипта, которую мы можем расширить. Сначала выберите Обработчик событий по умолчанию , нажмите на опции и выберите Редактировать скрипт . Теперь сделайте копию сценария. Если вы используете MonoDevelop, нажмите « Файл» > « Сохранить как» и сохраните как ImageTargetBehavior , сохранив его в папке « Сценарии ».
Скрипт TargetBehaviorScript
Нам не понадобится пространство имен Vuforia
в нашем скрипте. Уберите строку « namespace Vuforia
» и скобки. Это означает, что нам нужно явно ссылаться на пространство имен Vuforia
когда мы хотим получить доступ к его классам:
1
2
3
4
5
6
|
using UnityEngine;
using System.Collections;
public class BaseScript : MonoBehaviour, Vuforia.ITrackableEventHandler
{
// code here
}
|
Наиболее важным методом в этом классе будет метод OnTrackableStateChanged
который принимает вызовы, когда целевое изображение найдено или потеряно устройством камеры. В соответствии с целевым статусом он вызывает OnTrackingFound
или OnTrackingLost
, и нам нужно будет также отредактировать эти методы. Но сначала давайте подумаем о том, как мы хотим, чтобы цель изображения работала.
В этой игре пользователь будет защищать базу, которая появляется на изображении цели. Давайте рассмотрим следующую игровую механику:
- Как только цель распознается системой, появляется база, и враги начинают появляться и летят к базе в стиле камикадзе.
- Каждый раз, когда враг поражает базу, база будет получать некоторый урон, и враг будет уничтожен.
- Чтобы выиграть игру, пользователь должен стрелять и уничтожать всех врагов, прежде чем база будет уничтожена.
- Если цель изображения потеряна (больше не видна с камеры устройства), игра запустит таймер обратного отсчета. Если таймер обнуляется, игра проиграна. Пока цель потеряна, все враги перестанут продвигаться к базе.
Поэтому нам нужно адаптировать игровую механику к тому, что мы создали в предыдущем уроке. В следующем разделе мы создадим логику появления врага с пустым объектом с именем _SpawnController , используя ту же логику, что и в первой части игры.
А пока давайте посмотрим на логику отслеживания найденных.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
private void OnTrackingFound ()
{
EnableRendererAndCollider ();
// Inform the system that the target was found
StartCoroutine (InformSpawnCtr (true));
}
private void OnTrackingLost ()
{
DisableRendererAndCollider ();
// Inform the system that the target was lost
StartCoroutine (InformSpawnCtr (false));
}
// inform SpanController that base was founded
private IEnumerator InformSpawnCtr (bool isOn)
{
// move spawning position
GameObject spawn = GameObject.FindGameObjectWithTag («_SpawnController»);
yield return new WaitForSeconds (0.2f);
// inform SpanController
if (isOn) {
spawn.GetComponent<SpawnScript2> ().BaseOn (transform.position);
} else {
spawn.GetComponent<SpawnScript2> ().BaseOff ();
}
}
|
Вернувшись в редактор Unity, мы можем создать базовый объект, который будет порождаться контроллером spawn.
Сначала на объекте ImageTarget отключите скрипт обработчика событий по умолчанию .
Затем нажмите « Добавить компонент» и выберите целевой сценарий поведения . На панели « Иерархия» щелкните правой кнопкой мыши ImageTarget и создайте новый куб с именем « Base ». Этот куб должен быть вставлен в объект ImageTarget .
Убедитесь, что на базе включены Box Collider и Mesh Renderer .
При желании вы также можете вставить объект Plane в ImageTarget, используя ImageTarget, ранее представленный в Vuforia, в качестве текстуры. Это создаст интересный эффект, проецируя тени от цели и создавая более богатый опыт.
Адаптация SpawnScript
Теперь мы адаптируем _SpawnController, использованный в последнем уроке. Сохраните текущую сцену и откройте ShootTheCubesMain из последнего урока. На панели « Иерархия» выберите _SpawnController и перетащите его в папку « Prefabs », чтобы сделать его « Unity Prefab» .
Сохраните эту новую сцену и снова откройте DefendTheBase . Перетащите _SpawnController из папки prefabs на панель « Иерархия» . Выбрав _SpawnController , нажмите « Добавить тег» на панели « Инспектор» . Назовите новый тег _SpawnController и примените его к объекту.
В окне «Проект» выберите элемент « Куб» в папке « Prefab » и установите для его тега « Инспектор» значение «Враг».
Наконец, откройте папку Scripts и откройте SpawnScript . Нам нужно, чтобы этот скрипт адаптировался к загруженной сцене.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
using Vuforia;
public class SpawnScript : MonoBehaviour
{
#region VARIABLES
private bool mSpawningStarted = false;
// Cube element to spawn
public GameObject mCubeObj;
// Qtd of Cubes to be Spawned
public int mTotalCubes = 10;
private int mCurrentCubes = 0;
// Time to spawn the Cubes
public float mTimeToSpawn = 1f;
private int mDistanceFromBase = 5;
private List<GameObject> mCubes;
private bool mIsBaseOn;
private Scene mScene;
#endregion // VARIABLES
#region UNITY_METHODS
// Use this for initialization
void Start ()
{
mScene = SceneManager.GetActiveScene();
mCubes = new List<GameObject> ();
if ( mScene.name == «ShootTheCubesMain» )
{
StartSpawn();
}
}
// Update is called once per frame
void Update ()
{
}
#endregion // UNITY_METHODS
|
Далее нам нужно создать два открытых метода для приема вызовов от TargetBehaviorScript
когда цель найдена или потеряна:
-
BaseOn (Vector3 basePosition)
, когда цель обнаруживается камерой и отображается объект Base . Он изменит позицию нереста, запустит процесс и проинформирует все кубы, которые были ранее добавлены на сцену, о том, что база видна. -
Метод
BaseOff()
будет использоваться, когда цель потеряна. Это остановит процесс постановки и сообщит всем элементам куба, что база была потеряна.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#region PUBLIC_METHODS
// Base was found by the tracker
public void BaseOn (Vector3 basePosition)
{
Debug.Log («SpawnScript2: BaseOn»);
mIsBaseOn = true;
// change position
SetPosition (basePosition);
// start spawning process if necessary
StartSpawn ();
// inform all cubes on screen that base appeared
InformBaseOnToCubes ();
}
// Base lost by the tracker
public void BaseOff ()
{
mIsBaseOn = false;
mSpawningStarted = false;
// inform all cubes on screen that base is lost
InformBaseOffToCubes ();
}
#endregion // PUBLIC_METHODS
|
SetPosition (System.Nullable<Vector3> pos)
использует текущую позицию цели для изменения осей x, y и z объекта, а также может получить null
значение, когда загруженная сцена — ShootTheCubesMain .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#region PRIVATE_METHODS
// We’ll use a Coroutine to give a little
// delay before setting the position
private IEnumerator ChangePosition ()
{
Debug.Log («ChangePosition»);
yield return new WaitForSeconds (0.2f);
// Define the Spawn position only once
// change the position only if Vuforia is active
if (VuforiaBehaviour.Instance.enabled)
SetPosition (null);
}
// Set position
private void SetPosition (System.Nullable<Vector3> pos)
{
if (mScene.name == «ShootTheCubesMain») {
// get the camera position
Transform cam = Camera.main.transform;
// set the position 10 units ahead of the camera position
transform.position = cam.forward * 10;
} else if (mScene.name == «DefendTheBase») {
if (pos != null) {
Vector3 basePosition = (Vector3)pos;
transform.position =
new Vector3 (basePosition.x, basePosition.y + mDistanceFromBase, basePosition.z);
}
}
}
|
InformBaseOnToCubes()
и InformBaseOffToCubes()
отвечают за информирование всех поэтапных кубов о текущем базовом состоянии.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// Inform all spawned cubes of the base position
private void InformBaseOnToCubes ()
{
// Debug.Log(«InformBaseOnToCubes»);
foreach (GameObject cube in mCubes) {
cube.GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
}
}
// Inform to all cubes that the base is off
private void InformBaseOffToCubes ()
{
// Debug.Log(«InformBaseOffToCubes»);
foreach (GameObject cube in mCubes) {
cube.GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
}
}
|
SpawnLoop()
и SpawnElement()
используют почти ту же логику, что и в предыдущем уроке.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
// Start spawning process
private void StartSpawn ()
{
if (!mSpawningStarted) {
// begin spawn
mSpawningStarted = true;
StartCoroutine (SpawnLoop ());
}
}
// Loop Spawning cube elements
private IEnumerator SpawnLoop ()
{
if (mScene.name == «ShootTheCubesMain») {
// Defining the Spawning Position
StartCoroutine (ChangePosition ());
}
yield return new WaitForSeconds (0.2f);
// Spawning the elements
while (mCurrentCubes <= (mTotalCubes — 1)) {
// Start the process with different conditions
// depending on the current stage name
if (mScene.name == «ShootTheCubesMain» ||
(mScene.name == «DefendTheBase» && mIsBaseOn)) {
mCubes.Add (SpawnElement ());
mCubes [mCurrentCubes].GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
mCurrentCubes++;
}
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;
}
#endregion // PRIVATE_METHODS
|
Создание врагов
Теперь нам нужно создать несколько врагов. Мы будем использовать объект Cube, который мы создали в последнем уроке, внося некоторые изменения в его скрипт.
В папке Prefabs добавьте объект Cube в иерархию. Затем выберите объект и отредактируйте CubeBehaviorScript .
Мы сохраним почти ту же логику в этом скрипте, но со следующими отличиями:
- Куб будет преследовать Базу, когда цель найдена камерой.
- Когда Куб поразит Базу , он разрушит себя и нанесет некоторый урон Базе .
- Сценарий должен знать имя загруженной сцены и соответственно адаптироваться.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class CubeBehaviorScript : MonoBehaviour {
#region VARIABLES
public float mScaleMax = 1f;
public float mScaleMin = 0.2f;
public int mCubeHealth = 100;
// Orbit max Speed
public float mOrbitMaxSpeed = 30f;
public float velocityToBase = 0.4f;
public int damage = 10;
// Orbit speed
private float mOrbitSpeed;
// Orbit direction
private Vector3 mOrbitDirection;
// Max Cube Scale
private Vector3 mCubeMaxScale;
// Growing Speed
public float mGrowingSpeed = 10f;
private bool mIsCubeScaled = false;
private bool mIsAlive = true;
private AudioSource mExplosionFx;
private GameObject mBase;
private bool mIsBaseVisible = false;
private Vector3 mRotationDirection;
private Scene mScene;
#endregion
|
Если сцена называется DefendTheBase
, она должна найти объект Base и начать двигаться к нему.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#region UNITY_METHODS
void Start () {
// Get Scene name
mScene = SceneManager.GetActiveScene();
CubeSettings();
}
void Update () {
// makes the cube orbit and rotate
RotateCube();
if ( mScene.name == «DefendTheBase» ) {
// move cube towards the base, when it’s visible
MoveToBase ();
}
// scale cube if needed
if ( !mIsCubeScaled )
ScaleObj();
}
#endregion
|
CubeSettings()
также необходимо адаптировать в соответствии с загруженной сценой. Куб вращается только по оси Y для сцены DefendTheBase
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#region PRIVATE_METHODS
private void CubeSettings ()
{
// defining the orbit direction
float x = Random.Range ( -1f, 1f );
float y = Random.Range (-1f, 1f);
float z = Random.Range ( -1f, 1f );
// TODO update tutorial with new code
// define settings according to scene name
if ( mScene.name == «ShootTheCubesMain» )
{
mOrbitDirection = new Vector3( x, y, z );
}
else if ( mScene.name == «DefendTheBase» )
{
// orbit only on y axis
mOrbitDirection = new Vector3 (0, y, 0);
// scale size must be limited
mScaleMin = 0.05f;
mScaleMax = 0.2f;
velocityToBase = 0.2f;
}
// rotating around its axis
float rx = Random.Range (-1f, 1f);
float ry = Random.Range (-1f, 1f);
float rz = Random.Range (-1f, 1f);
mRotationDirection = new Vector3 (rx, ry, rz);
// 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 later
transform.localScale = Vector3.zero;
// getting Explosion Sound Effect
mExplosionFx = GetComponent<AudioSource> ();
}
|
Мы добавим новую логику в метод RotateCube()
. Объекты куба будут вращаться вокруг базы, пока цель видна. Когда цель не видна, они будут продолжать вращаться вокруг камеры , используя ту же логику, что и в предыдущем уроке.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Rotate the cube around the base
private void RotateCube ()
{
// rotate around base or camera
if (mIsBaseVisible && mBase != null && mIsAlive) {
// rotate cube around base
transform.RotateAround (
mBase.transform.position, mOrbitDirection, mOrbitSpeed * Time.deltaTime);
} else {
transform.RotateAround (
Camera.main.transform.position, mOrbitDirection, mOrbitSpeed * Time.deltaTime);
}
transform.Rotate (mRotationDirection * 100 * Time.deltaTime);
}
// 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;
}
|
Чтобы переместить объект к базе, нам нужно сначала проверить, присутствует ли база, а затем применить шаги позиционирования к объекту.
1
2
3
4
5
6
7
8
9
|
// Move the cube toward the base
private void MoveToBase ()
{
// make the cube move towards the base only if base is present
if (mIsBaseVisible && mIsAlive && gameObject != null && mBase != null) {
float step = velocityToBase * Time.deltaTime;
transform.position = Vector3.MoveTowards (transform.position, mBase.transform.position, step);
}
}
|
Метод DestroyCube()
такой же, как и раньше, но теперь мы добавим новый метод — метод TargetHit(GameObject)
который будет вызываться при ударе по базе. Обратите внимание, что BaseHealthScript, указанный в TargetHit()
еще не создан.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// make a damage on target
private void TargetHit (GameObject target)
{
Debug.Log («TargetHit: » + target.name);
if (target.name == «Base») {
// make damage on base
MyBase baseCtr = target.GetComponent<MyBase> ();
baseCtr.TakeHit (damage);
StartCoroutine (DestroyCube ());
}
}
// Destroy Cube
private IEnumerator DestroyCube(){
mIsAlive = false;
mExplosionFx.Play();
GetComponent<Renderer>().enabled = false;
yield return new WaitForSeconds(mExplosionFx.clip.length);
Destroy(gameObject);
}
#endregion
|
Наконец, мы добавим открытые методы, которые будут вызываться, когда куб получает удар, когда он сталкивается с базой или когда база меняет статус.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#region PUBLIC_METHODS
// Cube gor Hit
// return ‘false’ when cube was destroyed
public bool Hit( int hitDamage ){
mCubeHealth -= hitDamage;
if ( mCubeHealth >= 0 && mIsAlive ) {
StartCoroutine( DestroyCube());
return true;
}
return false;
}
public void OnCollisionEnter (Collision col)
{
TargetHit (col.gameObject);
}
// Receive current base status
public void SwitchBaseStatus (bool isOn)
{
// stop the cube on the movement toward base
mIsBaseVisible = isOn;
if (isOn) {
mBase = GameObject.Find («Base»);
} else {
mBase = null;
}
}
#endregion
|
Контроль базового здоровья
Враги ставятся и летят к базе, но они не наносят никакого урона при столкновении — ни на базу, ни на противника. Нам нужно создать скрипт для реагирования на коллизии, а также добавить панель состояния на экран, чтобы пользователь знал, насколько хорошо они работают.
Давайте начнем добавлять панель здоровья. На панели « Иерархия» в редакторе Unity выберите « Создать» > « Интерфейс» > « Слайдер» . Новый элемент Canvas будет добавлен в иерархию. Он содержит элементы пользовательского интерфейса, в том числе новый слайдер . Разверните холст и выберите ползунок .
Измените имя элемента слайдера на UIHealth . На панели « Инспектор» разверните « Прямоугольное преобразование» и установите « Ширина» на 400 и « Высота» на 40 . Установите Pos X на -220 , Pos Y на 30 и Pos Z на 0 .
Теперь разверните скрипт слайдера в иерархии. Отмените выбор опции Interactable . Для Target Graphic , нажмите на маленькую «точку» справа и выберите фоновое изображение.
- Установите минимальное значение 0 и максимальное значение 100 .
- Выберите Целые числа .
- Установите значение 100 .
Теперь разверните панель « Слайдер», чтобы отобразить его дочерние элементы: фон , область заливки и область обработки слайдов .
- Удалить область слайда ручки .
- Выберите Фон и установите его Цвет на более темный оттенок зеленого, например
#12F568FF
. - Разверните Fill Area и выберите объект Fill и установите его цвет
#7FEA89FF
.
Вот так должно выглядеть окно игры с индикатором здоровья.
Базовый сценарий здоровья
Код очень прост; он просто вычитает урон, нанесенный противникам, из общего количества здоровья базы. Как только здоровье становится равным нулю, игрок проигрывает игру. Это также добавит анимацию вращения на базу. Создайте новый C # скрипт с именем MyBase .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class MyBase : MonoBehaviour
{
#region VARIABLE
public float rotationSpeed = 10f;
public int health = 100;
public AudioClip explosionSoundFx;
public AudioClip hitSoundFx;
// TODO choose a different sound for the Hit
private bool mIsAlive = true;
private AudioSource mAudioSource;
public Slider mHealthSlider;
#endregion // VARIABLES
#region UNITY_METHODS
// Use this for initialization
void Start ()
{
mAudioSource = GetComponent<AudioSource> ();
mHealthSlider.maxValue = health;
mHealthSlider.value = health;
}
// Update is called once per frame
void Update ()
{
RotateBase ();
}
#endregion // UNITY_REGION
#region PRIVATE_METHODS
private void RotateBase ()
{
if ( mIsAlive && gameObject != null ) {
// implement object rotation
transform.Rotate ( Vector3.up, rotationSpeed * Time.deltaTime);
}
}
// Destroy base
private IEnumerator DestroyBase ()
{
mIsAlive = false;
mAudioSource.clip = explosionSoundFx;
mAudioSource.Play ();
GetComponent<Renderer> ().enabled = false;
// inform all Enemies that Base is Lost
GameObject[] enemies = GameObject.FindGameObjectsWithTag («Enemy»);
foreach (GameObject e in enemies) {
e.gameObject.GetComponent<EnemyScript> ().SwitchBaseStatus (false);
}
yield return new WaitForSeconds (mAudioSource.clip.length);
Destroy (gameObject);
}
#endregion // PRIVATE_METHODS
#region PUBLIC_METHODS
// receive damage
public void TakeHit (int damage)
{
health -= damage;
mHealthSlider.value = health;
if (health <= 0) {
StartCoroutine (DestroyBase ());
} else {
mAudioSource.clip = hitSoundFx;
mAudioSource.Play ();
}
}
#endregion // PUBLIC_METHODS
}
|
Теперь нам нужно добавить и настроить скрипт.
Выберите Base в иерархии, нажмите Add Component и добавьте аудиоисточник . Теперь перетащите MyBase на элемент Base и на панели « Инспектор» разверните MyBase . Выберите звуковой эффект для взрыва и нажмите. Я использовал клип для взрыва, использованный в последнем уроке, но не стесняйтесь добавлять свой. Наконец, в Health Slider , выберите элемент UISlider .
Защита базы
Наш новый игровой опыт почти закончен. Нам нужно только выстрелить лазерами, чтобы начать защищать нашу базу. Давайте создадим скрипт для лазера!
Сначала перетащите _PlayerController из папки Prefab в иерархию. Разверните _PlayerController и выберите _LaserController . На панели « Инспектор» найдите Laser Script и нажмите « Изменить» .
Единственное, что нам нужно изменить в этом скрипте — это положение лазера.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
// 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;
// Show the Laser using a Coroutine
StartCoroutine (LaserFx ());
// Holds the Hit information
RaycastHit hit;
// Set the origin position of the Laser Line
// It will add 10 units down from the ARCamera
// We adopted this logic for simplicity
Vector3 laserStartPos = new Vector3 (cam.position.x, cam.position.y -2f, cam.position.z);
mLaserLine.SetPosition (0, laserStartPos);
// 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);
// check target type
if (hit.collider.tag == «Enemy») {
CubeBehaviorScript cubeCtr = hit.collider.GetComponent<CubeBehaviorScript> ();
if (cubeCtr != null) {
if (hit.rigidbody != null) {
hit.rigidbody.AddForce (-hit.normal * mHitForce);
cubeCtr.Hit (mLaserDamage);
}
}
}
} else {
// Set the enfo of the laser line to be forward the camera
// using the Laser range
mLaserLine.SetPosition (1, cam.forward * mFireRange);
}
}
|
Пробовать игру
Это было много работы, но теперь пришло время играть в игру! Распечатайте целевое изображение и попробуйте запустить игру на своем телефоне или планшете. Повеселитесь и посмотрите, сможете ли вы придумать способы улучшить игру!
На этом этапе вы хорошо понимаете, как работает система Vuforia и как ее использовать с Unity. Я ожидаю, что вам понравилось это путешествие так же, как и мне. До скорого!
Чтобы узнать больше об дополненной реальности с Vuforia и Unity, посмотрите наш видеокурс здесь на Envato Tuts +!