Advertisement
  1. Code
  2. Augmented Reality

Erstellen Sie ein Augmented Reality-Spiel im Pokémon GO-Stil mit Vuforia: Image Targets

Scroll to top
Read Time: 22 min
This post is part of a series called Create a Pokémon GO Style Augmented Reality Game With Vuforia.
Create a Pokémon GO Style Augmented Reality Game With Vuforia: Part 2
Tips and Tricks for Augmented Reality With Unity and Vuforia

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

In diesem Tutorial tauchen wir wieder in die Vuforia Augmented Reality (AR)-Bibliothek ein und erkunden eine ihrer interessantesten Ressourcen – das Image Target. Wir werden das Shoot the Cubes-Spiel, das wir in früheren Lektionen erstellt haben, erweitern und ein neues Level hinzufügen, in dem der Spieler seine Basis vor angreifenden Würfeln verteidigen muss.

Dieses Tutorial kann alleine abgeschlossen werden. Wenn Sie jedoch eine Einführung in AR mit Vuforia und Unity3D wünschen, lesen Sie die früheren Beiträge der Serie.

Bildziele

Jede Art von Bild kann ein Vuforia-Image Target sein. Je detaillierter und komplexer das Bild jedoch ist, desto besser wird es vom Algorithmus erkannt.

Viele Faktoren werden Teil der Erkennungsberechnung sein, aber grundsätzlich muss das Bild ein angemessenes Maß an Kontrast, Auflösung und Unterscheidungsmerkmalen aufweisen. Ein Foto mit blauem Himmel würde nicht sehr gut funktionieren, aber ein Bild von etwas Gras würde anmutig funktionieren. Image Targets können mit der Anwendung geliefert, über die Cloud in die Anwendung hochgeladen oder vom Benutzer direkt in der App erstellt werden.

Hinzufügen eines Ziels

Beginnen wir damit, unserem Unity-Projekt ein ImageTarget-Element hinzuzufügen.

Laden Sie zunächst die Kursinhalte über die Schaltfläche in der Seitenleiste herunter. Erstellen Sie dann in Ihrem Unity-Projekt eine neue Szene namens DefendTheBase: Wählen Sie im Projektfenster den Ordner Szenen aus und klicken Sie auf Erstellen > Szene. Öffnen Sie nun diese Szene und entfernen Sie alle Standardszenenobjekte aus der Hierarchie.

Als nächstes fügen wir ein Licht und eine Kamera hinzu. Klicken Sie auf Hinzufügen > Licht > Gerichtetes Licht, um ein gerichtetes Licht hinzuzufügen. Wählen Sie dieses neue Licht aus und stellen Sie Weicher Schatten als Option für den Schattentyp ein.

Ziehen Sie danach ein ARCamera-Objekt per Drag & Drop aus Vuforia > Prefabs. Wählen Sie das ARCamera-Objekt aus und legen Sie im Inspektorfenster den auf der Vuforia-Entwicklerseite erstellten App-Lizenzschlüssel fest (Anweisungen finden Sie im ersten Tutorial). Wählen Sie DEVICE_TRACKING für die World Center Mod aus.

Ziehen Sie schließlich ein ImageTarget per Drag & Drop in die Hierarchie von Vuforia > Prefabs.

Jetzt müssen wir eine Vuforia-Datenbank hinzufügen. Navigieren Sie zunächst zu https://developer.vuforia.com/target-manager. Klicken Sie auf Datenbank hinzufügen und wählen Sie einen Namen.

Es stehen drei Arten von Datenbanken zur Auswahl:

  1. Gerät: Die Datenbank wird auf dem Gerät gespeichert und alle Ziele werden lokal aktualisiert.
  2. Cloud: Datenbank auf den Vuforia-Servern.
  3. VuMark: Datenbank exklusiv für VuMark-Ziele. Es wird auch auf dem Gerät gespeichert.

Wählen Sie in diesem Fall die Option Gerät und klicken Sie auf Erstellen.

Wählen Sie die neue Datenbank aus, damit wir ihr Ziele hinzufügen können. Jetzt ist es an der Zeit, der Datenbank Ziele hinzuzufügen. Im Moment verwenden wir nur die Option Einzelbild.

Navigieren Sie zu den zuvor heruntergeladenen Dateien, wählen Sie ImageTarget1 und setzen Sie die Breite auf 1 und klicken Sie auf Hinzufügen. (Hinweis: Wenn Sie es vorziehen, Ihr eigenes Image-Target zu erstellen, lesen Sie zuerst die Anleitung.)

Vuforia DatabaseVuforia DatabaseVuforia Database

Jetzt können Sie die Datenbank herunterladen und Unity Editor als gewählte Plattform auswählen. Öffnen Sie die Datei und wählen Sie alle zu importierenden Elemente aus. Wir müssen auch unsere Unity-Szene vorbereiten, um das ImageTarget mit dieser von uns erstellten Datenbank zu erkennen.

Klicken Sie im Unity-Editor auf das ImageTarget-Objekt. Suchen und erweitern Sie zunächst das Image Target Behavior im Objektinspektor. Wählen Sie einen vordefinierten Typ aus. Wählen Sie das Image-Ziel, das wir zuvor für Database erstellt haben. Stellen Sie abschließend sicher, dass die Optionen Erweitertes Tracking aktivieren und Smart Terrain aktivieren beide deaktiviert sind.

Image Target settingsImage Target settingsImage Target settings

Das ImageTarget-Präfab besteht aus einer Reihe von Komponenten, darunter einige Skripte wie Image Target Behavior, Turn Off Behavior und Default Tracker Event Handler. Wenn Sie die Funktionsweise des Systems gründlich verstehen möchten, lesen Sie diese Skripte und versuchen Sie, ihre Beziehung zu anderen Komponenten zu verstehen.

Für dieses Tutorial werden wir jedoch nicht zu tief graben. Wir müssen uns nur auf den Standard-Tracker-Ereignishandler konzentrieren, der Anrufe empfängt, wenn sich der Tracking-Status des Bildziels ändert. Lassen Sie uns dieses Skript also als Grundlage verwenden, um unser eigenes Skriptverhalten zu erstellen.

Erstellen Sie eine Kopie dieses Skripts, die wir erweitern können. Wählen Sie zuerst Standard-Tracker-Ereignishandler, klicken Sie auf Optionen und wählen Sie Skript bearbeiten. Erstellen Sie nun eine Kopie des Skripts. Wenn Sie MonoDevelop verwenden, klicken Sie auf Datei > Speichern unter und speichern Sie es als ImageTargetBehavior im Ordner Scripts.

Das TargetBehaviorScript-Skript

Wir werden den Vuforia-Namespace in unserem Skript nicht benötigen. Entfernen Sie die Zeile „namespace Vuforia“ und die Klammern. Das bedeutet, dass wir explizit auf den Vuforia-Namespace verweisen müssen, wenn wir auf seine Klassen zugreifen möchten:

1
using UnityEngine;
2
using System.Collections;
3
public class BaseScript : MonoBehaviour, Vuforia.ITrackableEventHandler
4
{
5
    // code here

6
}

Die wichtigste Methode in dieser Klasse ist die Methode OnTrackableStateChanged, die Aufrufe empfängt, wenn das Bildziel vom Kameragerät gefunden oder verloren wird. Je nach Zielstatus ruft es OnTrackingFound oder OnTrackingLost auf, und wir müssen auch diese Methoden bearbeiten. Aber denken wir zuerst darüber nach, wie sich das Image-Ziel verhalten soll.

In diesem Spiel verteidigt der Benutzer eine Basis, die auf einem Bildziel erscheint. Betrachten wir die folgenden Spielmechaniken:

  • Sobald das Ziel vom System erkannt wird, erscheint die Basis und Feinde beginnen zu spawnen und fliegen im Kamikaze-Stil auf die Basis zu.
  • Jedes Mal, wenn ein Feind die Basis trifft, nimmt die Basis Schaden und der Feind wird zerstört.
  • Um das Spiel zu gewinnen, muss der Benutzer alle Feinde erschießen und zerstören, bevor die Basis zerstört wird.
  • Wenn das Bildziel verloren geht (von der Gerätekamera nicht mehr sichtbar ist), startet das Spiel einen Countdown-Timer. Wenn der Timer auf Null geht, ist das Spiel verloren. Solange das Ziel verloren ist, werden alle Feinde aufhören, sich auf die Basis zu nähern.

Daher müssen wir diese Spielmechanik zusätzlich zu dem anpassen, was wir im letzten Tutorial erstellt haben. Wir werden die Spawning-Logik des Feindes im nächsten Abschnitt mit einem leeren Objekt namens _SpawnController erstellen, wobei die gleiche Logik verwendet wird, die im ersten Teil des Spiels verwendet wurde.

Sehen wir uns zunächst die Logik zum Verfolgen von gefundenen Daten an.

1
private void OnTrackingFound ()
2
{
3
    EnableRendererAndCollider ();
4
	// Inform the system that the target was found

5
	StartCoroutine (InformSpawnCtr (true));
6
}
7
8
private void OnTrackingLost ()
9
{
10
	DisableRendererAndCollider ();
11
	// Inform the system that the target was lost

12
	StartCoroutine (InformSpawnCtr (false));
13
}
14
15
// inform SpanController that base was founded

16
private IEnumerator InformSpawnCtr (bool isOn)
17
{
18
	// move spawning position

19
	GameObject spawn = GameObject.FindGameObjectWithTag ("_SpawnController");
20
21
	yield return new WaitForSeconds (0.2f);
22
23
	// inform SpanController

24
	if (isOn) {
25
		spawn.GetComponent<SpawnScript2> ().BaseOn (transform.position);
26
	} else {
27
		spawn.GetComponent<SpawnScript2> ().BaseOff ();
28
	}
29
}

Zurück im Unity-Editor können wir das Basisobjekt erstellen, das vom Spawn-Controller gespawnt wird.

Deaktivieren Sie zunächst für das ImageTarget-Objekt das Skript für den standardmäßigen nachverfolgbaren Ereignishandler.

Klicken Sie anschließend auf Komponente hinzufügen und wählen Sie das Zielverhaltensskript aus. Klicken Sie im Hierarchiebereich mit der rechten Maustaste auf ImageTarget und erstellen Sie einen neuen Cube namens "Base". Dieser Würfel sollte in das ImageTarget-Objekt eingefügt werden.

Stellen Sie sicher, dass in der Basis Box Collider und Mesh Renderer aktiviert sind.

Optional können Sie auch ein Plane-Objekt in das ImageTarget einfügen, indem Sie das zuvor in Vuforia eingereichte ImageTarget als Textur verwenden. Dies würde einen interessanten Effekt erzeugen, Schatten vom Ziel projizieren und ein reicheres Erlebnis schaffen.

Hierarchy and Image Target final settingsHierarchy and Image Target final settingsHierarchy and Image Target final settings

Das SpawnScript anpassen

Nun werden wir den im letzten Tutorial verwendeten _SpawnController anpassen. Speichern Sie die aktuelle Szene und öffnen Sie ShootTheCubesMain aus dem letzten Tutorial. Wählen Sie im Hierarchiebedienfeld den _SpawnController aus und ziehen Sie ihn in den Prefabs-Ordner, um ihn zu einem Unity-Prefab zu machen.

Speichern Sie diese neue Szene und öffnen Sie DefendTheBase erneut. Ziehen Sie _SpawnController aus dem Prefabs-Ordner in das Hierarchie-Panel. Klicken Sie bei ausgewähltem _SpawnController im Inspektorfenster auf Tag hinzufügen. Benennen Sie das neue Tag _SpawnController und wenden Sie es auf das Objekt an.

Wählen Sie im Projektfenster das Cube-Element im Prefab-Ordner aus und setzen Sie sein Tag wieder im Inspektor auf 'Enemy'.

Set Cubes tag to EnemySet Cubes tag to EnemySet Cubes tag to Enemy

Öffnen Sie schließlich den Ordner Scripts und öffnen Sie SpawnScript. Wir müssen dafür sorgen, dass sich dieses Skript an die geladene Szene anpasst.

1
using UnityEngine;
2
using UnityEngine.SceneManagement;
3
using System.Collections;
4
using System.Collections.Generic;
5
6
using Vuforia;
7
8
public class SpawnScript : MonoBehaviour
9
{
10
11
    #region VARIABLES
12
    private bool mSpawningStarted = false;
13
14
    // Cube element to spawn

15
    public GameObject mCubeObj;
16
    // Qtd of Cubes to be Spawned

17
    public int mTotalCubes = 10;
18
19
    private int mCurrentCubes	= 0;
20
21
    // Time to spawn the Cubes

22
    public float mTimeToSpawn	= 1f;   
23
    
24
    private int mDistanceFromBase = 5;
25
26
    private List<GameObject> mCubes;
27
28
    private bool mIsBaseOn;
29
    private Scene mScene;
30
31
    #endregion // VARIABLES

32
33
34
    #region UNITY_METHODS
35
36
    // Use this for initialization

37
    void Start ()
38
    {
39
        mScene = SceneManager.GetActiveScene();
40
        mCubes = new List<GameObject> ();
41
42
        if ( mScene.name == "ShootTheCubesMain" )
43
        {
44
            StartSpawn();
45
        }
46
    }
47
48
    // Update is called once per frame

49
    void Update ()
50
    {
51
52
    }
53
54
    #endregion // UNITY_METHODS

Als Nächstes müssen wir zwei öffentliche Methoden erstellen, um Aufrufe von TargetBehaviorScript zu empfangen, wenn das Ziel gefunden oder verloren wird:

  • BaseOn (Vector3 basePosition) wird aufgerufen, wenn das Ziel von der Kamera gefunden und das Basisobjekt angezeigt wird. Es ändert die Spawnposition, startet den Prozess und informiert alle Würfel, die zuvor der Bühne hinzugefügt wurden, dass die Basis sichtbar ist.

  • Die BaseOff()-Methode wird verwendet, wenn das Ziel verloren geht. Es stoppt den Staging-Prozess und informiert alle Würfelelemente, dass die Basis verloren gegangen ist.

1
#region PUBLIC_METHODS

2
3
    // Base was found by the tracker

4
	public void BaseOn (Vector3 basePosition)
5
	{
6
		Debug.Log ("SpawnScript2: BaseOn");
7
8
		mIsBaseOn = true;
9
10
		// change position

11
		SetPosition (basePosition);
12
13
		// start spawning process if necessary

14
		StartSpawn ();
15
16
		// inform all cubes on screen that base appeared

17
		InformBaseOnToCubes ();
18
	}
19
20
	// Base lost by the tracker

21
	public void BaseOff ()
22
	{	
23
		mIsBaseOn = false;
24
		mSpawningStarted = false;
25
26
		// inform all cubes on screen that base is lost

27
		InformBaseOffToCubes ();
28
	}
29
30
	#endregion // PUBLIC_METHODS

Die SetPosition (System.Nullable<Vector3> pos) verwendet die aktuelle Position des Ziels, um die X-, Y- und Z-Achsen des Objekts zu ändern, und kann auch einen null wert erhalten, wenn die geladene Szene ShootTheCubesMain ist.

1
#region PRIVATE_METHODS

2
3
    // We'll use a Coroutine to give a little

4
	// delay before setting the position

5
	private IEnumerator ChangePosition ()
6
	{
7
		Debug.Log ("ChangePosition");
8
		yield return new WaitForSeconds (0.2f);
9
		// Define the Spawn position only once

10
11
		// change the position only if Vuforia is active

12
		if (VuforiaBehaviour.Instance.enabled)
13
			SetPosition (null);
14
		
15
	}
16
17
	// Set position

18
	private void SetPosition (System.Nullable<Vector3> pos)
19
	{
20
		if (mScene.name == "ShootTheCubesMain") {
21
			// get the camera position

22
			Transform cam = Camera.main.transform;
23
24
			// set the position 10 units ahead of the camera position

25
			transform.position = cam.forward * 10;
26
		} else if (mScene.name == "DefendTheBase") {
27
			if (pos != null) {
28
				Vector3 basePosition = (Vector3)pos;
29
				transform.position = 
30
					new Vector3 (basePosition.x, basePosition.y + mDistanceFromBase, basePosition.z);
31
			}
32
		}
33
34
	}

InformBaseOnToCubes() und InformBaseOffToCubes() sind dafür verantwortlich, alle bereitgestellten Cubes über den aktuellen Basisstatus zu informieren.

1
// Inform all spawned cubes of the base position

2
    private void InformBaseOnToCubes ()
3
	{
4
		//			Debug.Log("InformBaseOnToCubes");

5
		foreach (GameObject cube in mCubes) {
6
			cube.GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
7
		}
8
	}
9
10
	// Inform to all cubes that the base is off

11
	private void InformBaseOffToCubes ()
12
	{
13
		//			Debug.Log("InformBaseOffToCubes");

14
		foreach (GameObject cube in mCubes) {
15
			cube.GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
16
		}
17
	}

Die Methoden SpawnLoop() und SpawnElement() verwenden fast dieselbe Logik wie das letzte Tutorial.

1
// Start spawning process

2
    private void StartSpawn ()
3
	{
4
		if (!mSpawningStarted) {
5
			// begin spawn

6
			mSpawningStarted = true;
7
			StartCoroutine (SpawnLoop ());
8
		}
9
	}
10
11
	// Loop Spawning cube elements

12
	private IEnumerator SpawnLoop ()
13
	{
14
		if (mScene.name == "ShootTheCubesMain") {
15
			// Defining the Spawning Position

16
			StartCoroutine (ChangePosition ());
17
		}
18
19
		yield return new WaitForSeconds (0.2f);
20
		// Spawning the elements

21
		while (mCurrentCubes <= (mTotalCubes - 1)) {
22
			// Start the process with different conditions

23
			// depending on the current stage name

24
			if (mScene.name == "ShootTheCubesMain" ||
25
			    (mScene.name == "DefendTheBase" && mIsBaseOn)) {
26
27
				mCubes.Add (SpawnElement ());
28
				mCubes [mCurrentCubes].GetComponent<CubeBehaviorScript> ().SwitchBaseStatus (mIsBaseOn);
29
				mCurrentCubes++;
30
31
			}
32
33
			yield return new WaitForSeconds (Random.Range (mTimeToSpawn, mTimeToSpawn * 3));
34
		}
35
	}
36
37
	// Spawn a cube

38
	private GameObject SpawnElement ()
39
	{
40
		// spawn the element on a random position, inside a imaginary sphere

41
		GameObject cube = Instantiate (mCubeObj, (Random.insideUnitSphere * 4) + transform.position, transform.rotation) as GameObject;
42
		// define a random scale for the cube

43
		float scale = Random.Range (0.5f, 2f);
44
		// change the cube scale

45
		cube.transform.localScale = new Vector3 (scale, scale, scale);
46
		return cube;
47
	}
48
49
	#endregion // PRIVATE_METHODS

Die Feinde erschaffen

Jetzt müssen wir einige Feinde erstellen. Wir verwenden das Cube-Objekt, das wir im letzten Tutorial erstellt haben, und nehmen einige Änderungen an seinem Skript vor.

Fügen Sie im Ordner Prefabs ein Cube-Objekt zur Hierarchie hinzu. Wählen Sie dann das Objekt aus und bearbeiten Sie das CubeBehaviorScript.

Wir behalten in diesem Skript fast dieselbe Logik bei, jedoch mit den folgenden Unterschieden:

  • Der Cube verfolgt die Basis, wenn das Ziel von der Kamera gefunden wird.
  • Wenn der Cube die Basis trifft, zerstört er sich selbst und fügt der Basis etwas Schaden zu.
  • Das Skript muss den Namen der geladenen Szene kennen und sich entsprechend anpassen.
1
using UnityEngine;
2
using UnityEngine.SceneManagement;
3
using System.Collections;
4
5
public class CubeBehaviorScript : MonoBehaviour {
6
7
    #region VARIABLES
8
9
	public float mScaleMax	= 1f;
10
	public float mScaleMin	= 0.2f;
11
12
	public int mCubeHealth	= 100;
13
14
	// Orbit max Speed

15
	public float mOrbitMaxSpeed = 30f;
16
17
	public float velocityToBase = 0.4f;
18
	public int damage = 10;
19
20
	// Orbit speed

21
	private float mOrbitSpeed;
22
23
	// Orbit direction

24
	private Vector3 mOrbitDirection;
25
26
	// Max Cube Scale

27
	private Vector3 mCubeMaxScale;
28
29
	// Growing Speed

30
	public float mGrowingSpeed	= 10f;
31
	private bool mIsCubeScaled	= false;
32
33
	private bool mIsAlive		= true;
34
	private AudioSource mExplosionFx;
35
36
	private GameObject mBase;
37
	private bool mIsBaseVisible = false;
38
39
	private Vector3 mRotationDirection;
40
	private Scene mScene;
41
42
	#endregion

Wenn der Name der Szene DefendTheBase lautet, muss sie das Basisobjekt finden und sich darauf zubewegen.

1
#region UNITY_METHODS

2
3
    void Start () {
4
		// Get Scene name

5
		mScene = SceneManager.GetActiveScene();
6
		CubeSettings();
7
	}
8
9
	void Update () {
10
		// makes the cube orbit and rotate

11
		RotateCube();
12
13
		if ( mScene.name == "DefendTheBase" ) {
14
			// move cube towards the base, when it's visible

15
			MoveToBase ();
16
		}
17
18
		// scale cube if needed

19
		if ( !mIsCubeScaled )
20
			ScaleObj();
21
	}
22
	#endregion

Die CubeSettings() müssen sich auch entsprechend der geladenen Szene anpassen. Der Cube kreist für die DefendTheBase-Szene nur auf der y-Achse.

1
#region PRIVATE_METHODS

2
    private void CubeSettings ()
3
	{
4
		// defining the orbit direction

5
		float x = Random.Range ( -1f, 1f );
6
		float y = Random.Range (-1f, 1f);
7
		float z = Random.Range ( -1f, 1f );
8
9
		// TODO update tutorial with new code

10
		// define settings according to scene name

11
		if ( mScene.name == "ShootTheCubesMain" )
12
		{
13
			mOrbitDirection = new Vector3( x, y, z );
14
		}
15
		else if ( mScene.name == "DefendTheBase" )
16
		{
17
			// orbit only on y axis

18
			mOrbitDirection = new Vector3 (0, y, 0);
19
20
			// scale size must be limited

21
			mScaleMin = 0.05f;
22
			mScaleMax = 0.2f;
23
24
			velocityToBase = 0.2f;
25
		}
26
27
		// rotating around its axis

28
		float rx = Random.Range (-1f, 1f);
29
		float ry = Random.Range (-1f, 1f);
30
		float rz = Random.Range (-1f, 1f);
31
32
		mRotationDirection = new Vector3 (rx, ry, rz);
33
34
35
		// defining speed

36
		mOrbitSpeed = Random.Range (5f, mOrbitMaxSpeed);
37
38
		// defining scale

39
		float scale = Random.Range (mScaleMin, mScaleMax);
40
		mCubeMaxScale = new Vector3 (scale, scale, scale);
41
42
		// set cube scale to 0, to grow it later

43
		transform.localScale = Vector3.zero;
44
45
		// getting Explosion Sound Effect

46
		mExplosionFx = GetComponent<AudioSource> ();
47
	}

Wir werden der RotateCube()-Methode eine neue Logik hinzufügen. Die Würfelobjekte drehen sich um die Basis, während das Ziel sichtbar ist. Wenn das Ziel nicht sichtbar ist, drehen sie sich weiter um die Kamera, wobei dieselbe Logik wie im letzten Tutorial verwendet wird.

1
// Rotate the cube around the base

2
    private void RotateCube ()
3
	{
4
		// rotate around base or camera

5
		if (mIsBaseVisible && mBase != null && mIsAlive) {
6
			// rotate cube around base

7
			transform.RotateAround (
8
				mBase.transform.position, mOrbitDirection, mOrbitSpeed * Time.deltaTime);
9
		} else {
10
			transform.RotateAround (
11
				Camera.main.transform.position, mOrbitDirection, mOrbitSpeed * Time.deltaTime);
12
		}
13
		transform.Rotate (mRotationDirection * 100 * Time.deltaTime);
14
	}
15
    // Scale object from 0 to 1

16
    private void ScaleObj(){
17
18
		// growing obj

19
		if ( transform.localScale != mCubeMaxScale )
20
			transform.localScale = Vector3.Lerp( transform.localScale, mCubeMaxScale, Time.deltaTime * mGrowingSpeed );
21
		else
22
			mIsCubeScaled = true;
23
	}

Um das Objekt in Richtung der Basis zu bewegen, müssen wir zuerst prüfen, ob die Basis vorhanden ist, und dann die Positionsschritte auf das Objekt anwenden.

1
	// Move the cube toward the base

2
	private void MoveToBase ()
3
	{
4
		// make the cube move towards the base only if base is present

5
		if (mIsBaseVisible && mIsAlive && gameObject != null && mBase != null) {
6
			float step = velocityToBase * Time.deltaTime;
7
			transform.position = Vector3.MoveTowards (transform.position, mBase.transform.position, step);
8
		}
9
	}

Die Methode DestroyCube() ist dieselbe wie zuvor, aber jetzt fügen wir eine neue Methode hinzu – die Methode TargetHit (GameObject) – die aufgerufen wird, wenn die Basis getroffen wird. Beachten Sie, dass das in TargetHit() referenzierte BaseHealthScript noch nicht erstellt wurde.

1
// make a damage on target

2
    private void TargetHit (GameObject target)
3
	{
4
		Debug.Log ("TargetHit: " + target.name);
5
		if (target.name == "Base") {
6
			// make damage on base

7
			MyBase baseCtr = target.GetComponent<MyBase> ();
8
			baseCtr.TakeHit (damage);
9
			StartCoroutine (DestroyCube ());
10
		}
11
	}
12
13
	// Destroy Cube

14
	private IEnumerator DestroyCube(){
15
		mIsAlive = false;
16
17
		mExplosionFx.Play();
18
19
		GetComponent<Renderer>().enabled = false;
20
21
		yield return new WaitForSeconds(mExplosionFx.clip.length);
22
		Destroy(gameObject);
23
	}
24
25
	#endregion

Schließlich fügen wir die öffentlichen Methoden hinzu, die aufgerufen werden, wenn der Würfel einen Treffer erleidet, mit der Basis kollidiert oder wenn die Basis ihren Status ändert.

1
#region PUBLIC_METHODS

2
3
    // Cube gor Hit

4
	// return 'false' when cube was destroyed

5
	public bool Hit( int hitDamage ){
6
		mCubeHealth -= hitDamage;
7
		if ( mCubeHealth >= 0 && mIsAlive ) {
8
			StartCoroutine( DestroyCube());
9
			return true;
10
		}
11
		return false;
12
	}
13
14
	public void OnCollisionEnter (Collision col)
15
	{
16
		TargetHit (col.gameObject);
17
	}
18
19
	// Receive current base status

20
	public void SwitchBaseStatus (bool isOn)
21
	{
22
		// stop the cube on the movement toward base

23
		mIsBaseVisible = isOn;
24
		if (isOn) {
25
			mBase = GameObject.Find ("Base");
26
		} else {
27
			mBase = null;
28
		}
29
	}
30
31
	#endregion

Kontrolle der Basisgesundheit

Die Feinde werden inszeniert und fliegen auf die Basis zu, aber sie verursachen keinen Schaden, wenn sie kollidieren – weder der Basis noch dem Feind. Wir müssen ein Skript erstellen, um auf Kollisionen zu reagieren und dem Bildschirm eine Gesundheitsleiste hinzuzufügen, damit der Benutzer weiß, wie gut es ihm geht.

Beginnen wir mit dem Hinzufügen der Gesundheitsleiste. Klicken Sie im Hierarchiebereich des Unity-Editors auf Erstellen > UI > Schieberegler. Der Hierarchie wird ein neues Canvas-Element hinzugefügt. Es enthält UI-Elemente, einschließlich des neuen Slider. Erweitern Sie die Canvas und wählen Sie den Schieberegler.

Ändern Sie den Namen des Schiebereglerelements in UIHealth. Erweitern Sie im Inspektor-Bedienfeld Rect Transform und setzen Sie Width auf 400 und Height auf 40. Setzen Sie Pos X auf -220, Pos Y auf 30 und Pos Z auf 0.

Erweitern Sie nun das Slider-Skript in der Hierarchie. Deaktivieren Sie die Option Interagierbar. Klicken Sie für Zielgrafik auf den kleinen „Punkt“ auf der rechten Seite und wählen Sie das Hintergrundbild aus.

  • Setzen Sie den Min-Wert auf 0 und den Max-Wert auf 100.
  • Wählen Sie Ganze Zahlen.
  • Wert auf 100 setzen.
UIHealth SettingsUIHealth SettingsUIHealth Settings

Erweitern Sie nun das Slider-Bedienfeld, um seine untergeordneten Elemente anzuzeigen: Hintergrund, Füllbereich und Grifffolienbereich.

  • Grifffolienbereich löschen.
  • Wählen Sie Hintergrund und stellen Sie seine Farbe auf einen dunkleren Grünton ein, z. B. #12F568FF.
  • Erweitern Sie Füllbereich, wählen Sie das Füllobjekt aus und legen Sie seine Farbe auf #7FEA89FF fest.

So sollte das Spielfenster mit der Gesundheitsleiste aussehen.

Game window with health barGame window with health barGame window with health bar

Das Basis-Health-Skript

Der Code ist sehr einfach; Es zieht nur den Schaden der Feinde von der Gesamtgesundheit der Basis ab. Sobald die Gesundheit Null erreicht, verliert der Spieler das Spiel. Außerdem wird der Basis eine Rotationsanimation hinzugefügt. Erstellen Sie ein neues C#-Skript namens MyBase.

1
using UnityEngine;
2
using UnityEngine.UI;
3
using System.Collections;
4
5
public class MyBase : MonoBehaviour
6
{
7
    #region VARIABLE
8
9
	public float rotationSpeed = 10f;
10
11
	public int health = 100;
12
	public AudioClip explosionSoundFx;
13
	public AudioClip hitSoundFx;
14
	// TODO choose a different sound for the Hit

15
16
	private bool mIsAlive = true;
17
	private AudioSource mAudioSource;
18
	public Slider mHealthSlider;
19
20
	#endregion // VARIABLES

21
22
23
	#region UNITY_METHODS
24
25
	// Use this for initialization

26
	void Start ()
27
	{
28
		mAudioSource = GetComponent<AudioSource> ();
29
		mHealthSlider.maxValue = health;
30
		mHealthSlider.value = health;
31
	}
32
	
33
	// Update is called once per frame

34
	void Update ()
35
	{
36
		RotateBase ();
37
	}
38
39
	#endregion // UNITY_REGION

40
41
	#region PRIVATE_METHODS
42
43
	private void RotateBase ()
44
	{
45
		if ( mIsAlive && gameObject != null ) {
46
			// implement object rotation

47
			transform.Rotate ( Vector3.up, rotationSpeed * Time.deltaTime);
48
		}
49
	}
50
51
	// Destroy base

52
	private IEnumerator DestroyBase ()
53
	{
54
		mIsAlive = false;
55
		mAudioSource.clip = explosionSoundFx;
56
		mAudioSource.Play ();
57
58
		GetComponent<Renderer> ().enabled = false;
59
60
		// inform all Enemies that Base is Lost

61
		GameObject[] enemies = GameObject.FindGameObjectsWithTag ("Enemy");
62
		foreach (GameObject e in enemies) {
63
			e.gameObject.GetComponent<EnemyScript> ().SwitchBaseStatus (false);
64
		}
65
66
		yield return new WaitForSeconds (mAudioSource.clip.length);
67
		Destroy (gameObject);
68
69
	}
70
71
	#endregion // PRIVATE_METHODS

72
73
	#region PUBLIC_METHODS
74
75
	// receive damage

76
	public void TakeHit (int damage)
77
	{
78
		health -= damage;
79
80
		mHealthSlider.value = health;
81
82
		if (health <= 0) {
83
			StartCoroutine (DestroyBase ());
84
		} else {
85
			mAudioSource.clip = hitSoundFx;
86
			mAudioSource.Play ();
87
		}
88
	}
89
90
	#endregion // PUBLIC_METHODS

91
}

Jetzt müssen wir das Skript hinzufügen und konfigurieren.

Wählen Sie die Basis in der Hierarchie aus, klicken Sie auf Komponente hinzufügen und fügen Sie eine Audioquelle hinzu. Ziehen Sie nun MyBase auf das Basiselement und erweitern Sie im Inspektorfenster MyBase. Wählen Sie einen Soundeffekt für die Explosion und schlagen Sie zu. Ich habe den im letzten Tutorial verwendeten Explosionsclip verwendet, aber Sie können gerne Ihren eigenen hinzufügen. Wählen Sie schließlich im Health Slider das UISlider-Element aus.

Base settingsBase settingsBase settings

Verteidigung der Basis

Unser neues Spielerlebnis ist fast fertig. Wir müssen nur ein paar Laser abfeuern, um unsere Basis zu verteidigen. Lassen Sie uns ein Skript für den Laser erstellen!

Ziehen Sie zuerst den _PlayerController aus dem Prefab-Ordner in die Hierarchie. Erweitern Sie _PlayerController und wählen Sie _LaserController. Suchen Sie im Inspektorfenster nach Laser Script und klicken Sie auf Bearbeiten.

Das einzige, was wir in diesem Skript ändern müssen, ist die Position des Lasers.

1
// Shot the Laser

2
    private void Fire ()
3
	{
4
		// Get ARCamera Transform

5
		Transform cam = Camera.main.transform;
6
7
		// Define the time of the next fire

8
		mNextFire = Time.time + mFireRate;
9
10
		// Set the origin of the RayCast

11
		Vector3 rayOrigin = cam.position;
12
13
		// Show the Laser using a Coroutine

14
		StartCoroutine (LaserFx ());
15
16
		// Holds the Hit information

17
		RaycastHit hit;
18
19
		// Set the origin position of the Laser Line

20
		// It will add 10 units down from the ARCamera

21
		// We adopted this logic for simplicity

22
		Vector3 laserStartPos = new Vector3 (cam.position.x, cam.position.y -2f, cam.position.z);
23
		mLaserLine.SetPosition (0, laserStartPos);	
24
25
		// Checks if the RayCast hit something

26
		if (Physics.Raycast (rayOrigin, cam.forward, out hit, mFireRange)) {
27
28
			// Set the end of the Laser Line to the object hit

29
			mLaserLine.SetPosition (1, hit.point);
30
31
			// check target type

32
			if (hit.collider.tag == "Enemy") {
33
34
				CubeBehaviorScript cubeCtr = hit.collider.GetComponent<CubeBehaviorScript> ();
35
				if (cubeCtr != null) {
36
					if (hit.rigidbody != null) {
37
						hit.rigidbody.AddForce (-hit.normal * mHitForce);
38
						cubeCtr.Hit (mLaserDamage);
39
					}
40
				}
41
			}
42
43
		} else {
44
			// Set the enfo of the laser line to be forward the camera

45
			// using the Laser range

46
			mLaserLine.SetPosition (1, cam.forward * mFireRange);
47
		}
48
	}

Das Spiel ausprobieren

Das war viel Arbeit, aber jetzt ist es an der Zeit, das Spiel zu spielen! Drucken Sie das Zielbild aus und versuchen Sie, Ihr Spiel auf Ihrem Telefon oder Tablet auszuführen. Viel Spaß damit und sehen Sie, ob Sie einige Möglichkeiten finden, das Spiel zu verbessern!

An dieser Stelle haben Sie ein gutes Verständnis dafür, wie das Vuforia-System funktioniert und wie es mit Unity verwendet wird. Ich gehe davon aus, dass Sie diese Reise genauso genossen haben wie ich. Bis bald!

Um mehr über Augmented Reality mit Vuforia und Unity zu erfahren, sehen Sie sich unseren Videokurs hier auf Envato Tuts+ an!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.