Unity3D Opdracht 4: Een teleport/deur naar een andere locatie of wereld!
Introductie
In de vorige opdrachten heb je geleerd hoe je een 3D eiland level kan maken en hoe je van een dag-level een nacht-level kan maken. Maar hoe kun je er nou voor zorgen dat de speler in-game van het ene naar het andere level kan wisselen?
Een veelgebruikte manier om dit voor elkaar te krijgen is door gebruik te maken van zogeheten ‘triggers’ (trekkers).
Een trigger kun je een beetje vergelijken met een muizenval die ‘afgaat’ zodra de muis op de val gaat staan. Of je kan het vergelijken met een sensor van een schuifdeur die vanzelf opengaat als je in de buurt komt. Of een voordeur lamp die aangaat als je langsloopt.
Je kan met triggers iets op verschillende momenten laten gebeuren: zodra je speler de trigger aanraakt, terwijl de speler zich in de trigger zone bevind of wanneer de speler de trigger verlaat.
Wat er dan in je spel gebeurt als de speler (of een vijand) door zo’n trigger loopt kun je helemaal zelf bepalen d.m.v een script met code wat je aan de trigger koppelt.
De mogelijkheden van triggers voor een game zijn eindeloos en bijna iedere game maakt er op éen of meerdere manieren gebruik van.
Denk aan games waarin er ‘dingen’ gebeuren als je langs een bepaalde plek loopt, bijvoorbeeld een berg die instort of een touwbrug die het begeeft net op het moment dat je in het midden van de brug loopt.
In deze opdracht leer je hoe je een trigger kan gebruiken om je speler naar een andere locatie in je level te teleporteren/verplaatsen en hoe je de speler ermee naar een volgend level kan laten gaan!
Stap 1: Een nieuwe lege scene openen
Klik in de menu balk op File > New Scene om een nieuwe lege scene te openen.
Deze nieuwe lege scene gebruik je alleen tijdelijk om het teleport object in elkaar te zetten dus deze hoef je niet op te slaan. Soms is het makkelijker om iets in elkaar te zetten in een lege scene want dan wordt je niet afgeleid door de rest van de game-wereld en kun je gemakkelijk met je camera om het object waar je aan werkt heen draaien.
Nadat je de portal deur gemaakt hebt kun je er een prefab van maken en die daarna in je levels plaatsen. Hoe dat gaat leer je een paar stappen verder in deze opdracht.
Stap 2: Beginnen met een kubus
Klik in de menu balk op GameObject > 3D Object > Cube om een standaard Unity kubus te maken.
Klik in de Hierarchy view op de Cube om deze te selecteren en de componenten die aan de kubus vastzitten in de Inspector view te tonen.
Plaats de kubus in het midden van de wereld door in de Inspector view de x,y,z, position waardes op 0 te zetten.
Om de kubus daarna goed in beeld te krijgen kun je erop dubbelklikken in de Hierarchy view of door op je keyboard op F (van ‘frame’) te drukken.
Stap 3: De trigger activeren
Als je in de Inspector view kijkt met het Cube object geselecteerd zie je dat de kubus uit meerdere componenten bestaat. In het bovenste component, de transform, wordt de locatie, rotatie en schaal van het object opgeslagen.
Zonder dit component zou er geen kubus object in de game-wereld zijn. Dit is dus het belangrijkste component en kun je niet verwijderen.
De andere componenten zijn optioneel en kunnen afzonderlijk verwijderd, toegevoegd of van het ene naar het andere object gekopieerd worden met de rechter-muisknop.
Het kubus object heeft ook een Mesh Filter en een Mesh Renderer component.
In het Mesh Filter component wordt het 3D draadmodel van het object opgeslagen maar zonder de Mesh Renderer zou dit draadmodel onzichtbaar zijn. De Mesh Renderer zorgt ervoor dat het object zichtbaar wordt ‘ge-renderd’ in de 3D wereld. In de Mesh Renderer wordt ook het materiaal waar het object gebruik van maakt opgeslagen.
Het materiaal zorgt voor de glans of matheid van het object en aan het materiaal kan eventueel weer een texture gekoppeld worden.
Schakel tijdelijk het Mesh Renderer component uit door het uit te vinken in de Inspector.
Iets over colliders
Zoals je ziet verdwijnen in de Scene view de vlakken van de kubus en blijven er alleen groene randen zichtbaar. Als je in de Game view kijkt zie je dat de kubus geheel is verdwenen.
De groene lijnen geven de randen aan van het Collider component.
Het collider component zorgt ervoor dat het object kan ‘botsen’ met ander objecten die een collider hebben in de 3D wereld. Collider komt van het engelse ‘collision’ wat botsing betekent.
Zonder de collider zou je met je speler dwars door de kubus kunnen lopen.
“Achter de schermen” checkt een collider eigenlijk ieder frame/beeldje of het geraakt wordt of wordt overlapt door een ander object. Zo ja dan wordt het andere object door Unity tot stilstand gebracht.
Je kan via code ook dingen laten gebeuren tijdens zo’n collision van twee objecten, echter als je de collider instelt als trigger kun je er wél doorheen lopen en wordt de speler niet tot stilstand gebracht maar kun je ook nog steeds dingen laten gebeuren op het moment dat twee colliders elkaar overlappen. Dus wanneer de speler er doorheen loopt.
Druk in het Box Collider component op ‘Is Trigger’ om de collider als trigger in te stellen:
De volgende stap is het schrijven van een klein C# (see sharp) script dat regelt wat er gebeurt als de speler de trigger activeert.
Stap 4: Een trigger script maken
Klik onderaan in de Inspector view op ‘Add Component’ en scroll helemaal omlaag in de lijst.
Klik op ‘New Script’ en geef het bijvoorbeeld de naam TeleportScript.
Controleer of de ‘language’ op C Sharp staat en druk op ‘Create and Add’:
Dubbelklik op de naam van het script in het vakje naast ‘Script’ om het te openen in MonoDevelop:
Stap 5: Het trigger script schrijven
Als MonoDevelop is opgestart zie je daarin je geopende TeleportScript met alvast twee lege functies van Unity, Start () en Update ().
De Start () functie wordt door Unity automatisch éenmalig geactiveerd zodra je op Play drukt, dus bij het starten van de scene. De Start functie kun je bijvoorbeeld gebruiken om dingen ‘klaar te zetten’, bijvoorbeeld de hoeveelheid levens waar de speler mee begint of de positie waar de speler begint.
De Update () functie is bedoeld voor code die tijdens het spelen steeds “ge-update” wordt en wordt door Unity ieder frame opnieuw gestart. De Update functie gebruik je bijvoorbeeld als je een timer wilt laten oplopen of een object rond wilt laten draaien etc.
Deze functies kun je dus gebruiken om dingen op verschillende momenten tijdens je game te laten gebeuren.
Nog een voorbeeld: Als je in de Start () functie een regel code zet die een object 1 centimeter naar voren plaatst wordt dat object als je op Play drukt slechts 1 centimeter naar voren gezet en daarna niets meer. Als je diezelfde regel in de Update () functie zet wordt het object ieder frame 1 centimeter naar voren geplaatst (dus ongeveer 60 keer per seconde) en ziet het er in-game uit alsof het object beweegt.
Om iets te laten gebeuren op het moment dat de speler door de trigger heenloopt kunnen we Unity’s ingebouwde OnTriggerEnter () functie gebruiken. De OnTriggerEnter () functie wordt door Unity automatisch gestart op het moment dat de speler contact maakt met de collider ingesteld als trigger.
Kijk voor meer informatie over functies op deze blog bij Extra > Extra uitleg: Functies/Methoden en op de Unity site bij Learn > Tutorials > Variables and Functions.
Zorg ervoor dat je script er zo uit ziet:
using UnityEngine;
using System.Collections;
public class TeleportScript : MonoBehaviour{
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter (Collider col)
{
print ("De speler heeft de trigger geraakt!");
}
}
Sla het script op met Ctrl+S of klik op File > Save in de menubalk van MonoDevelop en keer terug naar Unity.
De volgende stap is het plaatsen en testen van de trigger in het eiland-level.
Stap 6: De trigger testen
Verander in de Hierarchy view de naam van Cube naar TeleportTrigger en sleep deze daarna uit de Hierarchy view naar de _Prefabs map in de Project view.
Unity maakt dan automatisch een prefab van de kubus met daaraan het TeleportScript vastgekoppeld.
Open éen van de eiland levels die je al hebt gemaakt waarin je de teleport wilt plaatsen door op de scene file te dubbelkikken in de _Scenes map in de Project view.
De huidige scene waarin je de kubus hebt gemaakt hoef je niet op te slaan.
Sleep de TeleportTrigger.prefab uit het _Prefabs mapje naar waar je het wilt hebben op je eiland in de Scene view.
Sleep daarna nog een TeleportTrigger.prefab naar een andere plek op je eiland waar je de speler naartoe wilt teleporteren.
Druk op Play en loop met je speler door een van de triggers. Je kan voor het gemakt de Mesh Renderer van de kubus weer aanzetten zodat je de anders onzichtbare trigger kunt zien.
Als je in de Console view kijkt (de tab naast de Project view tab) zul je zien dat het berichtje “De speler heeft de trigger geraakt!” steeds wordt geprint als je met je speler door de trigger loopt. Zo weet je alvast dat de trigger en de OnTriggerEnter() functie in je script werken.
Stap 7: De teleport code schrijven
Keer terug naar het TeleportScript in MonoDevelop en zorg dat je script er zo uitziet:
using UnityEngine;
using System.Collections;
public class TeleportScript : MonoBehaviour
{
public GameObject otherTeleport;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter (Collider speler)
{
print ("De speler heeft de trigger geraakt!");
speler.transform.position = otherTeleport.transform.position;
speler.transform.position += Vector3.forward * 1;
}
}
Let op dat je ook de regel boven de Start () functie met public GameObject otherTeleport;
overneemt in je script! Dit is een variabel van het type GameObject waaraan de andere teleport toegewezen kan worden.
De eerste van de twee regels die erbij zijn gekomen in de OnTriggerEnter () functie zorgt ervoor dat de collider’s/de speler’s positie wordt veranderd in de positie van de andere teleport in het level. Hierdoor komt de speler dus precies op de plek van de andere teleport te staan. Met deze regel code verander je dus de x,y,z, position waardes van de speler’s transform component net zoals je dat in de Inspector view van Unity kan doen, maar dan via script.
De regel daaronder plaats de speler daarna nog 1 meter extra naar voren om te zorgen dat de speler niet eindeloos heen en weer ge-teleporteerd wordt.
Het enige wat er nu nog gedaan moet worden om dit te laten werken is het script laten weten wat het andere teleport object is.
Sla het script op met Ctrl+S en keer terug naar Unity.
Stap 8: De “otherTeleport” variabel toewijzen
Selecteer éen van de twee TeleportTrigger kubussen in de Hierarchy view.
Onderaan in de Inspector view in het TeleportScript component zie je dat er een vakje is verschenen met de naam Other Teleport.
Sleep de andere TeleportTrigger die je niet hebt geselecteerd uit de Hierarchy view naar dit lege vakje.
Doe dit vervolgens ook voor de andere TeleportTrigger.
TeleportTrigger 1 moet dus in het “Other Teleport” vakje TeleportTrigger 2 hebben en andersom.
Druk op Play om de game te starten en test je teleport door er doorheen te lopen.
Je zal zien dat je speler binnen een fractie van een seconde naar de andere teleport wordt verplaatst!
Stap 9: De trigger aan een deur vastmaken
Om een deur te maken die spelers kan teleporteren hoef je nu alleen nog het TeleportTrigger object aan een 3D model van een deur vast te maken.
Je begrijpt dat het niet persé een deur hoeft te zijn waaraan je de trigger vastmaakt en dat je een script als dit eindeloos kan blijven hergebruiken!
Klik in de menu balk op Assets > Import Package > Custom Package.
Importeer het pakket met de naam TeleportDoor.unitypackage, deze vind je in de map UnityPackages in je Bureaublad map.
(Het TeleportDoor pakket is eventueel ook vanaf deze blog te downloaden. Klik met je rechtermuis op het bestand hieronder en klik op “Koppeling opslaan als..”.
Verwijder na het downloaden het “.doc” gedeelte van de bestandsnaam: TeleportDoor.unitypackage.doc)
Zoek in de _Prefabs map in de Project view naar de prefab met de naam “Door” en sleep deze naast éen van de twee TeleportTrigger kubussen die je in je level hebt geplaatst in de Scene view.
Sleep vervolgens in de Hierarchy view de TeleportTrigger kubus op het ‘Door’ object om de trigger ‘kind’/’child‘ te maken van ‘Door’.
In de Hierarchy view ziet het er daarna zo uit:
Omdat de TepelportTrigger child is van ‘Door’ kun je de deur verplaatsen en dan beweegt de trigger kubus met de deur mee.
De positie in het transform component van de TeleportTrigger is nu ook relatief aan die van zijn parent ‘Door’ i.p.v relatief aan de game wereld.
Dit wil zeggen dat de nul positie van TeleportTrigger nu de positie van ‘Door’ is geworden in de game wereld.
Selecteer de TeleportTrigger in de Hierarchy view en zet in de Inspector view de positie op 0,0,0.
Je zal zien dat de trigger kubus daarna precies in het midden van de deur zit.
Omdat het midden van de deur in dit geval onderaan zit (dit maakt het makkelijker om de deur precies op de grond te plaatsen) moet je de kubus daarna nog iets omhoog plaatsen op de y-as.
Je kan daarna ook de schaal instellen om te zorgen dat de trigger kubus precies in de deuropening past.
Hiervoor kun je de volgende transform waardes overnemen:
!Let wel op dat je de schaal op de z-as niet smaller maakt dan 0.5 omdat de speler iets te breed is voor de deur en anders geen contact maakt met de trigger. Je kan ook de deur groter maken of de spelers character collider radius kleiner.
Nu hoef je alleen nog de Mesh Renderer van de TeleportTrigger kubus uit te zetten en…Gefeliciteerd! Je teleport deur is klaar!!
Als je benieuwd bent naar hoe je van de teleport een deur naar een ander level kan maken (hiervoor zijn slechts een paar regels code nodig) en hoe je een spel kan opslaan als een echt spel dat andere mensen kunnen spelen volg dan de Extra stap hieronder.
Als je wilt weten hoe je ervoor kan zorgen dat je als het ware door de deur naar de andere locatie kan kijken (dit werkt met een camera en een render texture) volg dan deze tutorial over hoe je een portal gun kan maken zoals in het spel ‘Portal’: https://www.youtube.com/watch?v=sK9Qf8ElFHo
Tip: In het _Prefabs mapje zit een ‘DoorWithRenderTexture’ prefab die al een camera en render texture heeft!
(Extra) Stap 10: Een deur naar een ander level
Open de _Scripts map in de Project view en maak daarin een nieuw C# script met bijvoorbeeld de naam LevelTriggerScript.
Dit kun je doen door in de _Scripts map te klikken met de rechtermuisknop en hierna Create > C# Script te kiezen of in de menu balk: Assets > Create > C# Script.
Koppel het script aan de TeleportTrigger en verwijder het TeleportScript component of zet het op inactief door het script component uit te vinken.
Open het script in MonoDevelop door erop te dubbelklikken en zorg ervoor dat je code er zo uitziet, de Start () en Update () functies worden niet gebruikt dus die kun je verwijderen:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class LevelTriggerScript : MonoBehaviour {
public string nextLevelName;
void OnTriggerEnter (Collider speler)
{
SceneManager.LoadScene(nextLevelName);
}
}
Sla het script op met Ctrl+S en keer terug naar Unity.
In de inspector view is nu een leeg vakje in het script verschenen met ‘Next Level Name‘.
Schrijf hierin de naam van het level dat je wilt laden. Dus de naam van de scene file in het _Scenes mapje. Als je volgende level ‘Level 2’ heet vul je dat dus in.
Het laatste wat nodig is om de LoadScene functie te laten werken is de twee of meerdere levels die je gebruikt toe te voegen aan de ‘build settings’. Dit is een lijst waarin je de levels die echt in je uiteindelijke spel komen moet zetten. De scenes die je niet in je uiteindelijke spel wilt hebben, bijvoorbeeld test scenes, worden dan niet in het uiteindelijke spel bestand gestopt als je het spel tot een echt speelbaar spel maakt/’build’.
Ga in de menu balk naar File > Build Settings.
Sleep de scene files van je levels uit de _Scenes map naar het Scenes In Build vak van het Build Settings venster.
Hierna kun je het venster sluiten, dus zonder op build of build en run te klikken.
Je deur naar het volgende level is nu gereed voor gebruik!
Nadat je de level trigger hebt getest kun je eventueel teruggaan naar het Build Settings venster en op Build klikken. Selecteer als locatie bijvoorbeeld het bureaublad en geef het bestand de naam van je game.
Unity maakt dan een .exe (windows) of .dmg (mac) bestand van je game die je daarna buiten Unity als een echte game kan spelen!
Extra uitleg over de code
Zoals je ziet is er bovenaan in het LevelTrigger script een regel code met
using UnityEngine.SceneManagement;
bijgekomen. Deze regel is nodig omdat de functie die het volgende level laad afkomstig is van de ‘class’ SceneManagement.
Om de level laad functie te gebruiken moet er dus aangegeven worden dat we van die externe class SceneManagement gebruik maken.
SceneManagement is simpelweg een ander script waarvan we de functies naar ons eigen script importeren.
De regel boven de OnTriggerEnter () functie met public string nextLevelName;
is een public/publieke variabel van het type string met de naam nextLevelName. Omdat deze variabel public is kunnen we de waarde ervan, dus de naam van het volgende level, in de Inspector view invullen. Als je dit niet in de inspector wilt doen zou je de waarde van nextLevelName ook in je script kunnen toewijzen op de volgende manier:
public string nextLevelName = "Level 2";
En als je de variabel ‘private’ maakt in plaats van ‘public’ is deze helemaal niet in de Inspector view te zien.
In de OnTriggerEnter () functie staat nu de regel code SceneManager.LoadScene(nextLevelName);
. Dit is de functie die het volgende level laad en om die functie te laten weten om welk level het gaat wordt de variabel met de naam van het volgende level erin gestopt, dus via de haakjes die iedere functie achter de functie-naam heeft staan.
Je zou in plaats van een variabel van een string ook direct de naam van het volgende level in string formaat in de functie kunnen stoppen als volgt:
SceneManager.LoadScene("Level 2");
Het nadeel hiervan is dat je dan voor ieder level een apart script moet maken dus dat is minder handig. Dit nadelige principe wordt in de programmeer-wereld ‘hard-coding’ genoemd.
Tutorial over hoe je een portal gun kan maken zoals in de game ‘Portal’!
https://www.youtube.com/watch?v=sK9Qf8ElFHo
Extra informatie over triggers en colliders
http://unity3d.com/learn/tutorials/modules/beginner/physics/colliders-as-triggers
Extra informatie over Start ()
https://unity3d.com/learn/tutorials/modules/beginner/scripting/awake-and-start?playlist=17117
Extra informatie over Update ()
https://unity3d.com/learn/tutorials/modules/beginner/scripting/update-and-fixedupdate?playlist=17117
Extra informatie over functies
http://unity3d.com/learn/tutorials/modules/beginner/scripting/variables-and-functions?playlist=17117