Starten met Programmeren van een 3D omgeving in Unreal Engine – Een Timeline toevoegen

print
Deze handleiding maakt deel uit van het programmeertraject:


Inhoud


Wat vooraf ging


Inleiding

In een vorige handleiding hebben we reeds interactie met de omgeving geprogrammeerd. Heel vaak zal deze interactie verlopen over een zeker tijd. Een deur gaat niet meteen van toe naar open maar zal dit doen over een tijdspanne van bv. 2 seconden. Hiertoe hebben we een Timeline nodig.

Deze handleiding bouwt verder op de handleiding Interactie met de omgeving waarin het praktische voorbeeld van het openen van een deur werd uitgewerkt zonder gebruik te maken van een Timeline.

Ik ga ook nog eens het werken met een Level Blueprint en met een Blueprint Class hernemen door het voorbeeld in beiden uit te werken.


Deur openen en sluiten met een Timeline

Zoals gezegd wil ik dit voorbeeld uitwerken zowel vanuit de Level Blueprint als vanuit een Blueprint Class zodat u beide werkwijzen eens naast mekaar ziet.

Het voordeel van een Blueprint Class is dat u deze Blueprint Class, deze deur, gemakkelijk kunt hergebruiken op verschillende plaatsen in het level, in verschillende levels en zelfs in verschillende projecten, daar waar een Level Blueprint gebonden is aan die specifieke deur in dat specifiek level.

Voor het programmeren van een deur is een Blueprint Class dan ook aangewezen!

Level Blueprint

We hebben een deel van de Level Blueprint reeds uitgewerkt in de handleiding Interactie met de omgeving. Ik herneem dit even.

  • Sleep de Static Meshes SM_Door en SM_DoorFrame in het level.
  • Gebruik de gekende technieken om deze actors de plaatsen en eventueel te roteren en te schalen.

  • Omdat de deur moet kunnen roteren moet de Mobility van SM_Door op Movable staan.

Om een object, een deur, interactief te maken moet u een Trigger toevoegen.

  • Voeg een BoxTrigger (die ik de naam DeurTriggerBox heb gegeven) toe zodat deze de deur langs beide zijden van de deur overlapt.

Met alle actors op zijn plaats en correct ingesteld kunnen we aan de programmeren slaan.

Wel, de deur moet open gaan, of meer specifiek, de deur moet 90° roteren. De deur (SM_Door) is het object waarmee iets moet gebeuren.

  • Selecteer SM_Door.

Het programmeren in dit voorbeeld gebeurt in Level Blueprint.

  • Met SM_Door nog steeds geselecteerd, klik in de knoppenbalk van de Viewport op BlueprintsOpen Level Blueprint.
  • Klik met de rechtermuisknop ingeduwd in Level Blueprint. Omdat we de actor SM_Door geselecteerd hebben kunnen we gemakkelijk een referentie naar de actor aanmaken door te kiezen voor Create a Reference to SM_Door.

Een referentie naar de actor SM-Door uit het persistent level is toegevoegd.

Nu we een referentie naar ons object MS_Door toegevoegd hebben aan Level Blueprint kunnen we dit gebruiken.

Blueprint Visual Scripting

Wat moet er gebeuren met deze deur? Wel, de deur moet roteren rond zijn eigen as. Dit kan via de functionaliteit SetActorRelativeRotation (omdat de rotatie relatief is ten opzichte van de actor zal deze ook blijven werken moesten we de actor verplaatsen). Moest u zich afvragen of ik met deze kennis (dat de functionaliteit SetActorRelativeRotation moet gebruikt worden) geboren ben, wel, nee. Dit is een kwestie van opzoeken en een beetje gezond verstand gebruiken.

  • Sleep dus een node vanuit onze referentie naar MS_Door en zoek naar SetActorRelativeRotation.

  • Klik deze aan als u ze gevonden hebt. Merk op dat SM_Door als Target wordt gekoppeld.

  • Er moet 90° geroteerd worden rond de Z-as. U kunt nu gewoon die 90 intypen bij Z.

Wanneer moet de deur open gaan?

Wel, wanneer de “speler” de ruimte bepaald door de DeurTriggerBox binnen treedt. Of nog meer concreet bij de Event OnActorBeginOverlap van de actor DeurTriggerBox.

  • Selecteer de DeurTriggerBox in uw level.
  • Keer terug naar Level Blueprint en klik met de rechtermuisknop ingedrukt in Level Bleuprint.
  • Omdat onze DeurTriggerBox geselecteerd is, kunt u gemakkelijk events voor deze DeurTriggerBox toevoegen. De event die we zoeken vindt u onder CollisionAdd On Actor Begin Overlap.

  • Klik deze aan.

De Event OnActorBeginOverlap van de actor DeurTriggerBox is toegevoegd.

  • Verbindt de node van de Event OnActorBeginOverlap met de node SetActorRelativeRotation.

Oké, laten we dit testen.

  • Compileer het Level Blueprint door te klikken op de knop Compile. Vergeet dit niet!
  • Build en start het level.

Het werkt!

Alle, toch bijna, de deur vliegt open en eens open gaat ze niet meer dicht.

Ah, geen probleem, we voegen een Delay toe zoals bij de lamp. Oké, maar nee, een Delay zal er enkel voor zorgen dat het iets langer duurt voor de deur met dezelfde snelheid open vliegt. Het is het openen van de deur zelf die moet vertraagd worden.

Een Timeline toevoegen

Een Timeline (tijdlijn) laat toe om een waarde over een zekere tijdspanne te wijzigen.

De rotatie van de deur moet niet van 0 naar 90 gaan in 0.0000 seconden maar pakweg in 2 seconden (dit is misschien wat te lang, praktischer zou bv. 1.2 seconden kunnen zijn, maar ik wil zeker zijn dat we het gezien hebben).

Hoe doen we dit?

  1. Eerst gaan we de Timeline-functionaliteit toevoegen. Deze zal moeten starten bij OnActorBeginOverlap.
  2. Binnen deze tijdslijn bepalen we dat de waarde van 0 naar 90 moet wijzigen in een tijdsspanne van 2 seconden.
  3. De tijdslijn wordt vervolgens gebruikt om de Z-waarde van SetActorRelativeRotation te “sturen”.

Laten we dit uitvoeren.

  • sleep een node uit de Event OnActorBeginOverlap en zoek naar Add Timeline.

Deze Timeline plaatst zich mooi tussen de huidige structuur eb is verbonden met OnActorBeginOverlap via Start en verbindt op zijn beurt SetActorRelativeRotation via Update. Na wat schuifwerk ziet u dit beter.

  • Dubbelklik nu de Timeline.

U komt terecht in de Editor voor de Timeline (meer specifiek Timeline_0 omdat we het nagelaten hebben een specifieke naam te geven). Hier moet u eerst bepalen welk soort van tijdslijn u wilt toevoegen, wat u wilt wijzigen over tijd.

  • F – Float track, animeert een Float waarde.
  • V – Vector track, animeert vectoren voor rotatie, locatie of schaal.
  • ! – Event track, dit levert een Event-pin die zal getriggerd worden op een bepaald moment in de tijdlijn.
  • C – Kleur track, animeert een kleur.
  • ~ – Voegt een bestaande curve in vanuit de Content Browser

In ons voorbeeld moet de waarde voor de rotatie gaan van 0 naar 90 over 2 seconden. We willen dus een waarde, meer specifiek een float wijzigen.

  • Klik dus op de f-knop (Add Float Track).

U krijgt onderstaande schermindeling.

  1. Track Name – De naam van de tijdlijn.
  2. External Curve group – Voeg een externe curve toe vanuit de Content Browser.
  3. Track timeline – Hier voegt u de Keyframes toe.
  • Vul een gewenste naam in (Bv. DeurRotatie).

We moeten nu twee punten toevoegen aan de tijdslijn om van 0 naar 90 te gaan in 2 seconden.

Een beginpunt op tijd 0 en een waarde van 0.

Een eindpunt op tijd 2 (seconden) met een waarde van 90.

  • Klik nu op de tijdlijn terwijl u de Shift-toets ingedrukt houdt. Er verschijnt een punt met als waarde voor de tijd de plek waarop u geklikt hebt.

  • Wijzig nu de Time van dit punt naar 0 (laat de waarde voor Value staan) en druk op Enter. Het punt schuift op helemaal naar links van de tijdlijn.

Doe nu hetzelfde om het tweede punt toe te voegen.

  • Klik met de Shift-toets ingedrukt ergens op de tijdslijn (of klik met de rechtermuisknop ingedrukt op de tijdslijn en kies Add key to …). Wijzig de waarde van Time naar 2 en van Value naar 90 (en druk op Enter).

Wellicht verwacht u een lijn te zien maar ziet u deze niet meteen.

  • Klik dan op de knopjes Zoom To Fit Horizontal en het knopje ernaast Zoom TO Fit Vertical.

Nu ziet u wellicht wel de verwachte lijn.

Eigenlijk zouden we hier kunnen stoppen, de tijdslijn is gemaakt, maar ik ga nog twee kleine aanpassingen doen.

Ten eerste verloopt de overgang nu lineair, op zich niets mis mee maar he zou mooier ogen als de deur in het begin, en op het einde, iets langzamer beweegt.

  • Selecteer beide punten (door ze allebei aan te klikken met de Ctrl-toets ingedrukt).
  • Klik met de rechtermuisknop op één van beide punten en vink Auto aan.

  • Zet de totale lengte van de tijdslijn eveneens op 2 in het vakje Length en klik op de knoppen Compile en Save.

  • Sluit nu het tabblad van de Timeline en keer terug naar de Event Graph
  • Merk op dat er een “optie” Deur rotatie is bijgekomen.

De waarde van Deur rotatie moet nu gekoppeld worden met de Z-waarde van SetActorRelativeRotation.

  • Sleep de Deur rotatie naar New Relative Rotation en… merk op dat er een fout wordt getoond.

Deze fout zou u niet mogen verbazen. De Float-waarde van Deur rotatie is immers maar één waarde die we proberen te koppelen aan 3 rotatiewaarden (X, Y en Z) en dit kan dus niet (bovendien kwamen de kleurtjes groen en paars niet overeen).

De oplossing bestaat er uit de drie waarden van de rotatie op de splitsen in drie afzonderlijke waarden voor X, Y en Z. Dit doe je als volgt:

  • Klik met de rechtermuisknop ingedrukt op New Relative Rotation en kies voor Split Struct Pin.

U ziet nu drie verschillende New Relative Rotation voor X, Y en Z (elk met een groen kleurtje, dus van het type Float).

  • Sleep nu de Deur rotatie naar New Relative Rotation Z(Yaw) en… merk op dat het nu lukt!
    Let op, naargelang de oriëntatie van de deur kan het zijn dat u moet kiezen voor een andere as. Dus gaat de deur niet in de gewenste richting open, probeer het dan eens via een andere as.

Laten we dit testen.

  • Compileer de Level Blueprint door te klikken op de knop Compile.
  • Build en start het level.

Het werkt!

De deur sluiten

Rest ons nu nog de deur te sluiten.

Wanneer moet de deur sluiten?

Wel, wanneer de “speler” de ruimte, bepaald door de DeurTriggerBox, verlaat of meer concreet bij de Event OnActorEndOverlap van de actor DeurTriggerBox.

  • Selecteer de DeurTriggerBox in uw level.
  • Keer terug naar Level Blueprint en klik met de rechtermuisknop ingedrukt in Level Bleuprint.
  • Omdat onze DeurTriggerBox geselecteerd is, kunt u gemakkelijk events voor deze DeurTriggerBox toevoegen. De event die we zoeken vindt u onder CollisionAdd On Actor End Overlap.

  • Klik deze aan.

De Event OnActorEndOverlap van de actor DeurTriggerBox is toegevoegd.

De deur sluiten is eigenlijk het omgekeerde als de deur openen. Je zou kunnen zeggen, het is de tijd van de tijdslijn die de deur opent terugdraaien. Wel, dit gaan we dan ook doen.

  • Verbind de Event OnActorEndOverlap met de Reverse-actie van de Timeline.

Laten we dit testen.

  • Compileer het Level Blueprint door te klikken op de knop Compile.
  • Build en start het level.

Het werkt, onze deur gaat open en toe!

Een Blueprint Class

Een Blueprint Class, aan te raden is indien u meerdere deuren in uw level kunt hebben, gaat u als volgt te werk:

  • In de Content Browser, klik op Add NewBlueprint Class (of klik met de rechtermuisknop in de net aangemaakte folder en klik op Blueprint Class).

  • Kies de Parent Class Actor.

  • Geef het een gepaste naam (bv. MijnDeur).
  • Dubbelklik om de Blueprint te openen.

Merk de DefaultSceneRoot op die de positie in het level zal bepalen, deze is reeds Movable.

Componenten toevoegen

Er moeten 2 componenten worden toegevoegd:

  • Een Static Mesh dat de deur bevat (met de naam Deur).

  • Een Box Collision (te vergelijken met een TriggerBox) voor de interactie (met de naam DeurTriggerBox).

  • U ziet de hieronder de toegevoegde componenten.

  • Voeg de Static Mesh SM_Door toe aan de eigenschap Static Mesh van Deur.

  • Eens toegevoegd, dubbelklik de deur (in de Eigenschap Static Mesh) en voeg Collision toe.
  • Plaats de DeurTriggerBox rond de deur.

Events

De deur moet opengaan als de DeurTriggerBox overlapt wordt en nadien weer gesloten bij het beëindigen van de overlapping.

  • Selecteer de DeurTriggerBox en vindt onderaan, bij Events, de event On Component Begin Overlap en On component End Overlap.

  • Klik op de +-knoppen van On Component Begin Overlap en On Component End Overlap.
  • Ga naar Event Graph.

Het programmeren verloopt gelijkaardig als het programmeren binnen de Level Blueprint. Het enige verschil is dat de Target van de functionaliteit SetActorRelativeRotation nu verwijst naar het Static Mesh component toegevoegd aan de Blueprint Class.

Merk de extra casting op die er voor zorgt dat de deur enkel maar open gaat als een PlayerCharacter (of een FirstPersonCharacter) de triggerbox overlapt. Deze extra controle mag ook toegevoegd worden aan de code in de Level Blueprint (ze is dus niet eigen aan een Blueprint Class)

Timeline

Deze Timeline is identiek aan de Timeline uit de Level Blueprint.


LERP (lineaire interpolatie)

Als aanvulling wil ik even stilstaan bij een veelgebruikte techniek LERP (lineaire interpolatie).

Bij een LERP wordt een waarde tussen A en B gekozen op basis van Alpha. Heel vaak wordt deze Alpha aangestuurd door een Timeline waardoor van de waarde van A naar de waarde van B wordt overgegaan gedurende een periode (tijd) bepaald door de Timeline.


Praktische voorbeelden

MijnDeur klasse

In een vorige handleiding hebben we een deur gemaakt die automatisch open ging. We hebben dit toen geprogrammeerd in de Level Blueprint.

De kans is echter groot dat we deze deur op meerdere plaatsen, in meerdere levels, ja, zelfs in meerdere projecten gaan hergebruiken.

Ideaal dus om hier een eigen klasse van te maken.

Maak eventueel een nieuwe folder aan waar u alle Blueprint Classes wenst te verzamelen.

  • In de Content Browser, klik op Add NewNew Folder.

Maak in deze nieuwe folder een nieuwe Blueprint Class aan met als Parent Class Actor.

  • In de Content Browser, klik op Add NewBlueprint Class (of klik met de rechtermuisknop in de net aangemaakte folder en klik op Blueprint Class).

  • Of, klik in het menu op BlueprintsNew Empty Blueprint Class….

  • Kies de Parent Class Actor.

  • Geef het een gepaste naam (bv. MijnDeur).
  • Dubbelklik om te openen.

Merk de DefaultSceneRoot op die de positie in het level zal bepalen, deze is reeds Movable.

Componenten toevoegen

Er moeten 2 componenten worden toegevoegd:

  • Een Static Mesh dat de deur bevat (met de naam Deur).

  • Een Box Collision (te vergelijken met een TriggerBox) voor de interactie (met de naam DeurTriggerBox).

  • U ziet de hieronder de toegevoegde componenten.

  • Voeg de Static Mesh SM_Door toe aan de eigenschap Static Mesh van Deur.

  • Eens toegevoegd, dubbelklik de deur (in de Eigenschap Static Mesh) en voeg Collision toe.
  • Plaats de DeurTriggerBox rond de deur.

Events

De deur moet opengaan als de DeurTriggerBox overlapt wordt en nadien weer gesloten bij het beëindigen van de overlapping.

  • Selecteer de DeurTriggerBox en vindt onderaan, bij Events, de event On component Begin Overlap en On component End Overlap.

  • Klik op de +-knoppen.
  • Ga naar Event Graph.
  • Voeg onderstaande code toe, merk het kleine verschil op, het is niet SetActorRelativeRotation maar SetRelativeRotation en gebruik de Static Mesh Deur.

Constructor

Constructors stellen waarden in, of voeren functionaliteiten uit, bij het aanmaken van het object (toevoegen aan het level). Dit is in dit voorbeeld niet nodig. De Constructor blijft dan ook leeg.

  • Compile en Save.
  • Sleep een paar instanties van de klasse MijnDeur in het level en test het uit.

Schuifdeur

Een schuifdeur roteert niet maar verplaatst zich over één van de assen (dit kan zowel de X-as als de Y-as zijn naargelang de oriëntatie van de deur maar ook eventueel de Z-as indien u wenst dat de deur naar boven schuift).

Onderstaande code werkt dit uit.

  • Bij BeginPlay bepaal de locatie van de deur in de wereld via de functionaliteit GetWorldLocation en bewaar deze locatie in een variabele BeginLocatie.
  • Bij het BeginOverlap, en ook bij EndOverlap van een triggerbox, kijk eerst of de overlappende actor de speler is door een Cast uit te voeren, let op eventueel moet u casten naar ThirdPersonCharacter of het type van spelerkarakter dat u gebruikt.
  • Bij BeginOverlap van een triggerbox Play de Timeline, bij EndOvelap Reverse de Timeline.
  • De Timeline wordt hier gestuurd door een vector, zie hieronder, deze vector levert een gewijzigde locatie op voor één, of meer, van de assen (naargelang de verschuiving). Deze gewijzigde locatie, afgeleverd door de Timeline wordt vervolgens opgeteld bij de vastgestelde Beginlocatie en dit wordt de nieuwe locatie van de schuifdeur die ingesteld wordt met de functie SetWorldLocation.
  • De Timeline is op basis van een vector die de waarde van de X-as wijzigt over een tijd van bv. 2 seconden. In dit geval verschuift de X-as maar het kan ook een andere as (of assen) zijn.

Flikkerend licht

Onderstaande code toont hoe u een licht kunt laten flikkeren door een constante wijziging van zijn intensiteit (Set Intensity).

De Timeline neemt een grillige willekeurige vorm aan om het flikkeren weer te geven. Merk op dat Loop (herhalende lus) aangevinkt is zodat het flikkeren blijft duren.

Lichtintensiteit en rotatie

Onderstaand voorbeeld laat een actor roteren en de lichtintensiteit toenemen en afnemen. Hiertoe gebruikt u 2 tijdlijnen binnen dezelfde Timeline, één voor de lichtintensiteit (type Float) en één voor de rotatie (type Vector).

Merk ook op dat binnen de Timeline AutoPlay aangevinkt is zodat deze Timeline automatisch wordt afgespeeld en niet hoeft gekoppeld te worden aan een event (bv. Event BeginPlay).

Magnetische pickups

Onderstaande code demonstreert hoe u een actor (Pickup) naar u toe kunt laten bewegen (magnetisch), eens ze u bereiken (overlappen) worden ze vernietigd. De Outrange is een Sphere Collision die zich rondom de actor bevindt en bepaalt wanneer het “overvliegen” moet getriggerd worden.

  • In een vorig voorbeeld heb ik getest of de overlappende actor ons PlayerCharacter is via een Casting, hier gebruik ik een alternatieve techniek door te vergelijken.
  • U hebt zowel de locatie van zowel uw PlayerCharacter als de Actor nodig, ik gebruik hier 2 verschillende technieken (via GetActorTransform gevolgd door een Break Transform en GetActorLocation) die beiden de locatie opleveren.
  • Gebruik de functie VInterp To om de overgang tussen de twee locaties vlot te laten verlopen, bepaald door de variabele Snelheid (ik gebruik hier voor snelheid een waarde 15).
  • Dit levert een nieuwe locatie op die opgeteld wordt bij de waarde van de Timeline die lineair loopt van 0 naar 2 en bepaalt hoelang het “overvliegen” duurt.
  • Dit levert de nieuwe locatie op van de actor die wordt ingesteld via SetActorLocation.
  • Bij overlapping met uw Player Character moet de Actor vernietigd worden via de functionaliteit DestroyActor.

De Timeline loopt lineair van 0 naar 2 en bepaalt de duur van het “overvliegen”.

Movement Platforms

Onderstaande video werkt bewegende platformen uit.

Mario Kart boost

We hebben het allemaal wel eens gespeeld, jaja geef maar toe, Mario Kart. Mario Kart bevat een aantal “platformen” dat de snelheid een boost geeft.

Hieronder ziet u een eigen uitwerking van deze “boost”. Wellicht een erg vereenvoudigde, maar werkende, oplossing.

Ik ga het project niet volledig uitwerken en beperk me tot de code. Ik gebruikte hiervoor een Advanced Vehicle Project.

Maak een Bluepint Class aan dat het “platform” bevat en een Box Collision component (bv. met de naam Trigger). Voeg ook een Arrow component toe die de richting, waarin moet overlapt worden, aangeeft.

In de Event Graph voegt u onderstaande code toe.

  • Bij het einde van de overlapping van de Box Collision (met de naam Trigger), dus bij een On component End Overlap-event, Cast to VehicleBlueprint (want enkel wagens krijgen een boost en geen per toeval overlopend konijntje).
  • Het overlappende voertuig heb ik in de variabele Voertuig bewaard voor later hergebruik.
  • Ik vraag de snelheid op via Get Velocity en bewaar deze in de variabele Snelheid (door de Velocity op te vragen en niet de Forward Vector kan het voertuig ook achterwaarts rijdend een boost krijgen).
  • Get Forward Vector van de Arrow levert ons de richting van het overlappende “platform” op (deze Arrow is een component in de Blueprint van het “platform”).
  • Nu we beiden richtingen, van het voertuig en van het “platform” kennen vergelijken we deze met een Dot product.
  • Indien het Dot Product een positieve waarde oplevert hebben het voertuig en het “platform” eenzelfde richting, en wordt de Boost toegepast.
  • Voor de Boost heb ik een eigen Custom Event aangemaakt. Gewoon, om het overzichtelijk te houden, dus niet uit “technische” redenen.
  • Ik heb ervoor gekozen dat de Boost 4 seconden duurt en een verdubbeling van de snelheid teweeg brengt. Ik gebruik hiervoor een tijdslijn die van 1 naar 2 gaat gedurende 1 seconde, nadien 2 seconden op 2 blijft en nadien weer gedurende 1 seconde terugzakt naar 1. Dit is de Versnelling.

  • De tijdslijn wordt telkens, bij iedere nieuwe overlapping, van het begin (Play from Start) afgespeeld.
  • De tijdslijn levert een Versnelling op (een waarde tussen 1 en 2) en deze Versnelling wordt vermenigvuldigd met de Snelheid (vastgelegd bij het overlappen, het is deze snelheid waarmee overlapt werd dat verdubbeld wordt).
  • Deze nieuwe snelheid wordt toegekend aan de parameter New Vel van de functionaliteit Set Physics Linear Velocity, de Target is het Voertuig (meer bepaald de Mesh van het voertuig).

Quickshots

Quickshots zijn korte, op zichzelf staande video’s, rond een specifiek onderwerp. Meestal aansluitend bij wat net besproken is.

Changing Things over Time


Behandelde Basiscompetenties uit de module ICT Programmeren – Specifieke ontwikkelomgeving: eenvoudige functionaliteiten

  • IC BC234 – kan de basisprincipes van programmeren in een specifieke ontwikkelomgeving toepassen
  • IC BC236 – kan eenvoudige wijzigingen aan een programma aanbrengen
  • IC BC241 – kan een programma in een specifieke ontwikkelomgeving maken
  • IC BC247 – kan de bouwstenen van een specifieke ontwikkelomgeving gebruiken
  • IC BC249 – kan de instellingen van een specifieke ontwikkelomgeving wijzigen
  • IC BC250 – kan bij het programmeren in functie van een specifieke ontwikkelomgeving, een juiste logica volgen

Geef een reactie

Deze website gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.

  • Abonneer je op deze website d.m.v. e-mail

    Voer je e-mailadres in om je in te schrijven op deze website en e-mailmeldingen te ontvangen van nieuwe berichten.