Starten met programmeren van een 3d omgeving in Unreal Engine – HUD en UI

print
Deze handleiding maakt deel uit van het programmeertraject:


Inhoud


Wat vooraf ging


Inleiding

De waarde van variabelen moeten vaak weergegeven worden op het scherm, de Print String functie is een tijdelijke oplossing maar zeker geen blijvende.

Een blijvende oplossing is de variabelen weer te geven op via de HUD.

Een HUD bevat meestal meerdere onderdelen, Widgets. In deze handleiding bespreek ik enkel het aanmaken van een enkel Widget. Het effectief aanmaken van een HUD zien we in een latere handleiding.

Situering van deze handleiding binnen Unreal Engine


Wat is de HUD?

HUD staat voor Head-Up Display en verzorgt de UI (User Interface).

De UI is een “overlay” die wordt gebruikt om informatie weer te geven, denk aan allerhande informatiebalken (health bar,…), tellers, minimappen, “mikpunten” (crosshairs),… en die interactie van de gebruiker toelaat om het programma te besturen via knoppen, menu’s,…

Unreal Engine gebruikt de tool Unreal Motion Graphics UI Designer (UMG) om deze HUD’s aan te maken.

De kern van UMG zijn Widgets, een reeks vooraf gemaakte ontwerpen die kunnen worden gebruikt om de interface te construeren met behulp van knoppen, aankruisvakken, schuifregelaars, voortgangsbalken,….

Deze Widgets worden bewerkt in een gespecialiseerde Widget Blueprint, die twee tabbladen gebruikt voor de constructie:

  • het Designer-tabblad maakt de visuele lay-out van de interface en basisfuncties mogelijk,
  • terwijl in het tabblad Graph de functionaliteit achter de gebruikte Widgets kan worden geprogrammeerd.

Laten we als heel eenvoudige kennismaking onze naam bovenaan het scherm plaatsen.

Widget Blueprint

We bouwen verder op de handleiding rond variabelen.

Er waren reeds variabelen toegevoegd aan de ThirdPersonCharacter Blueprint. Ook was er reeds een Event BeginPlay geprogrammeerd die de waarde van de variabele MaxGezondheid toekend aan Gezondheid.

  • Voeg er nog een Z-Event aan toe zodat bij het drukken op de Z-toets de gezondheid vermindert met 10.

We maken een Widget aan via de Unreal Motion Graphics UI Designer op basis van een Widget Blueprint.

  • Klik in de Content Browser, in de gewenste map, met de rechtermuisknop ingedrukt op de achtergrond (of klik op de knop Add New).
  • Kies voor User InterfaceWidget Blueprint.

  • Geef het een gepaste naam.
  • Dubbelklik de net aangemaakte Widget Blueprint.

We maken even kennis met de Widget Editor.

  1.  De gebruikelijke Menubalk
  2. Knoppenbalk met de knoppen Compile, Save, Find, Play,…
  3. Rechtsboven de 2 modes: Designer (ontwerpen) en Graph (programmeren).
  4. Palette met Widget die je kunt gebruiken en via Drag en Drop kunt toevoegen aan de Widget Editor. De verschillende UI-objecten die u kunt toevoegen (Button, Image, Text, Text Box,…). Een volledig overzicht vindt u hier.
  5. Hiërarchie, de ontwerpstructuur van de Widget.
  6. Visual Designer, de visuele weergave van de Widget.
  7. Het gebruikelijke Details-panel met de eigenschappen van het geselecteerde object.
  8. De Animation Track waar u animaties kunt toevoegen aan de Widget.

Tekst toevoegen

  • Sleep een Text-object ongeveer naar het midden van het scherm bovenaan.
  • In het Details-panel vult u bij ContentText uw naam in en u druk op Enter.

  • Vink Size To Content aan.
  • Gebruik de Anchors om de Tekst bovenaan te centreren (X = 0.5 en Y = 0), druk op de Ctrl-toest om de centrering te zien.

Onderstaande video toont het positioneren binnen UMG.

  • Verhoog Y-positie naar 20 om wat ruimte bovenaan te krijgen.
  • U kunt eventueel ook nog het lettertype

  • en de kleur,… wijzigen via het kleurenwiel.

  • We houden het “bescheiden”.

  • Compile en Save.

Onderstaande video geeft een woordje meer uitleg over het gebruik van het Text-object.


Binding

Binding de Naam aan een Textblock

We wensen nu de variabele Naam weer te geven, dit gebeurt door de variabele Naam te verbinden met het Text-object.

Om de Naam van ons ThirdPersonCharacter te pakken te krijgen moeten we een casting naar ons ThirdPersonCharacter uitvoeren en deze dan promoveren tot een variabele (zie hierboven). We kunnen zeggen dat we een referentie naar ThirdPersonCharacter moeten creëren.

Oké, maar waar moeten we deze referentie toevoegen?

  • Vanuit de Widget Blueprint, klik rechtsboven op Graph.

U ziet onderstaande events klaar staan. De event die we nodig hebben is de Event Construct.

  • Vanuit Event Construct maakt u onderstaande casting aan. We hebben dit hierboven reeds gedaan, dus dit zal wel lukken zonder verdere uitleg.

Nu we een referentie hebben naar ons ThirdPersonCharacter, via de variabele MijnKarakter, kunnen we deze gebruiken.

We moeten de Naam van ons karakter weergeven in het Text-object.

  • Keer terug naar de Designer en selecteer het Text-object.
  • Zoek de eigenschap Text (deze eigenschap bepaalt de weer te geven tekst).
  • Achter de eigenschap Text ziet u Bind staan. Hiermee kunt u een Binding maken.
  • Klik op Bind.
  • Selecteer de variabele MijnKarakter.
  • U ziet hier de variabele Naam staan (met de wat ongelukkige Tooltip). Merk op dat u Gezondheid of MaxGezondheid niet ziet, dit komt omdat dit geen teksten zijn (ze zijn van het type Integer) en dus geen voor de hand liggende Binding zijn voor de eigenschap Text.

  • Klik op Naam.

De Binding is gemaakt.

U ziet deze echter nog niet verschijnen in het ontwerpscherm, daarvoor moeten we het programma eerst compileren, bewaren en starten. We doen dit straks maar eerst…

Gezondheid weergeven ten opzichte van de maximale gezondheid

We wensen ook de waarde van de variabele Gezondheid weer te geven ten opzichte van de variabele MaxGezondheid als een percentage.

  • Sleep een Progress Bar in ons ontwerp. Deze Progres Bar biedt de mogelijkheid om een procentuele verhouding weer te geven. Hoeveel is het percentage Gezondheid ten opzichte van de MaxGezondheid. We gaan ons niet bezig houden met een propere lay-out maar eventueel kunt u het via Anchor links verankeren en wat breder maken. U kunt het onderstaande eventueel overnemen.

Onderstaande video toont het gebruik van een Progress Bar.

De Binding dient te gebeuren met de eigenschap Percent. We kunnen nu echter geen directe Binding doen zoals met de variabele Naam, we dienen immers eerst het percentage te berekenen. We moeten dus een nieuwe Binding creëren.

Weet dat percentage wordt weergegeven als een decimale waarde tussen 0 en 1 (0.10 is dus 10%).

  • Klik op Bind achter de eigenschap Percent.
  • Klik op Create Binding.

U komt in de functie Get Percent 0 (u kunt deze naam eventueel wijzigen) en u ziet ook reeds de verbonden Return Node die de waarde voor de Binding zal teruggeven (Returnen).

We gaan nu de nodige programmeercode nog eens stap voor stap uitwerken.

  • Sleep de variabele MijnKarakter in de Widget Blueprint en GET de waarde (de referentie).

  • Sleep een verbindingslijn uit de MijnKarakter-node en zoek naar Get Gezondheid.

  • Doe hetzelfde voor Get MaxGezondheid.

Nu we beiden waarden hebben kunnen we het percentage berekenen door Gezondheid te delen door MaxGezondheid. Dit levert ons een decimale waarde op tussen 0 en 1 (het percentage). Omdat we een decimale waarde moeten krijgen als resultaat moeten we een Float delen door een Float (omdat onze variabelen Gezondheid en MaxGezondheid beiden van het type Integer zijn zal er dus een conversie gebeuren (we hadden misschien beter toch meteen Float als datatype gekozen, maar dan had ik deze opmerking niet kunnen typen)).

  • Type / en kies voor Float / Float.

  • Maak nu de verbinden, en merk de conversie op (die automatisch wordt aangemaakt). Verbindt het resultaat van de deling ook al met de Return Value-node.

De Binding is gemaakt.

Als u terugkeert naar de Designer dan ziet u de Binding met de functie GetPercent_0 staan.

  • Compile en Save.
  • Start het programma en merk op dat …

U ziet de Widget nog niet verschijnen.

Onze Widget Blueprint moet nog toegevoegd worden aan de Viewport.


De Widget toevoegen aan de Viewport

We kunnen deze HUD/Widget oproepen vanuit verschillende plaatsen. In deze kennismakende handleiding ga ik het simpel houden en ik roep de Widget aan in de ThirdPersonCharacter Blueprint, waar zich alle variabelen bevinden die we in de HUD weergeven.

  • Ga naar de ThirdPersonCharacter Blueprint.
  • Vanuit de Event Begin Play sleept u een nieuwe verbindingslijn en u zoekt naar Create Widget.

  • Als Class selecteert u de net aangemaakte Widget Blueprint (hier TestWidget).

  • Vanuit de Exec-pin sleept u een nieuwe verbindingslijn en u zoekt naar Add to Viewport.
  • U verbindt nu de Return Value van de Widget Blueprint met de Target van de Viewport.

Tenslotte moeten we nog weergeven wiens HUD dit is, wie de Owning Player is. We doen dit door de Player Controller (het is de Player Controller die de HUD (of de Widget) controleert) op te vragen.

  • Sleep een verbindingslijn vanuit Owning Player en zoek naar Get Player Controller.

  • Merk de beeldschermpjes op die aanduiden dat deze informatie op het scherm komt.
  • Compile en Save.
  • Start het programma.

U krijgt het gewenste resultaat.


De objecten van een Widget wijzigen via programmeercode

Stel, u wilt een object, of meerdere objecten, die u hebt toegevoegd aan een Widget kunnen wijzigen via programmeercode.

U dient daartoe het object tot een variabele te maken.

  • Keer terug naar de Designer van de Widget Blueprint die u hierboven gebruikte.
  • Selecteer het object, bv. het Text-object dat onze naam bevat.
  • Geeft het eerst een gepaste naam, bv. TitelNaam.
  • Vink Is Variable aan.

  • Compile en Save.
  • Ga naar Graph.
  • In het My Blueprint-panel ziet u nu het Text-object als variabele staan.

U kunt dit vervolgens als een gewone variabele gebruiken.

  • Sleep de variabele in de Blueprint en kies voor een Get of Set (hieronder 2 maal een Get).
  • Vervolgens kunt u bv. de Tekst opvragen (GetText) of de tekst voor de Tooltip instellen (Set Tool Tip Text) via Blueprint Visual Scripting.

Merk op dat in bovenstaande afdruk de Progressbar de naam ProgressBar_266 heeft. Misschien toch niet de meest gelukkig naam. Wijzig deze naam, via de Designer, in het Detail-panel van de Progressbar naar iets meer duidend als GezondheidBar.


Updaten zonder Binding

Werken met Bindings is gemakkelijk maar niet efficiënt!

Een Binding wordt immers iedere Tick geüpdatet. dit is veel te vaak om goed te zijn. De TitelNaam moet enkel ingesteld worden bij het opstarten en de Gezondheidbar moet u pas wijzigen als de gezondheid van uw Character wijzigt. Dus zeker niet iedere Tick.

Let op, Bindings kunnen wel nuttig zijn, bv. voor de weergave van tijd of het updaten van het dashboard van een wagen, vliegtuig,… dat continu wijzigende informatie moet weergeven.

In ons voorbeeld is een Binding echter niet nuttig. We gaan nu bespreken hoe we waarden kunnen updaten zonder gebruik van een Binding.

Let op, ik bespreek hier een eenvoudige methode, in een latere handleiding, enkel toegankelijk voor cursisten van het PCVO Groeipunt, bespreek ik de meest efficiënte methode, gebruikmakend van een Event Dispatcher. Die handleiding vertrekt eveneens vanaf dit punt en gaat ervan uit dat onderstaande aanpassingen niet gebeurd zijn.

  • Ga naar de Designer van de Widget.
  • Selecteer de GezondheidBar.
  • Verwijder de Binding in het Details-panel onder ProgressPercent.

  • Doe hetzelfde voor TitelNaam.
  • Het berekenen van het percentage voor de GezondheidBar doen we nu via onderstaande Custom Event UpdateHealth. De code is gelijkaardig aan de code hierboven besproken maar kent wel het percentage toe via de eigenschap Set Percent van de GezondheidBar.

  • Ga naar de ThirdPersonCharacter Blueprint.
  • We moeten nu toegang hebben tot de Widget en zijn variabelen en functies (de Custom Event UpdateHealth). Dit doen we simpelweg door na de creatie van de Widget de Return Value te promoten tot een variabele (rechtsklikken op de Return Node en kiezen voor Promote to Variable).

  • Deze variabele (in onderstaand voorbeeld HUDReferentie genoemd) is van het type van de Widget en heeft bijgevolg toegang tot de Widget. In onderstaand voorbeeld wordt de Update van de GezondheidBar uitgevoerd via de Z-toets. In de praktijk zal dit gebeuren nadat uw Character Damage opgelopen heeft. Om het hier eenvoudig te houden heb ik dit vereenvoudigd uitgewerkt in onderstaand voorbeeld.


Hiërarchisch ontwerpen van een Widget

Tot nu toe hebben we een heel eenvoudige Widget gebouwd. Een Widget kan echter ook Panels bevatten die op hun beurt weer andere elementen kunnen bevatten (zoals het reeds gebruikte Canvas Panel). Op deze manier kan een hiërarchische Widget gebouwd worden.

We bekijken hier een eenvoudig voorbeeld. Ik werk dit voorbeeld enkel theoretisch uit, maar moest u het willen uitwerken, dan vertrekt u vanuit een nieuwe Widget.

  • Sleep een Horizontal Box in het Canvas Panel.

  • Sleep binnen de HorizontalBox twee VerticalBoxen.

  • Plaats binnen de VerticalBoxen vervolgens TextBoxen en ProgressBars.

  • Het voorlopige resultaat.

Merk op dat de ProgressBars niet opvullend zijn.

  • Wijzig de eigenschap Size naar Fill voor de ProgessBars en de bijhorende VerticalBox.

  • Het eindresultaat.

Opmerking, wanneer de Widget niet schermvullend moet zijn, verwijder dan het Canvas Panel en vervang dit door een Size Box.


Positioneren

Om objecten te positioneren op het scherm gebruikt u de eigenschappen Positioning en Alignment. Bekijk onderstaande voorbeelden.

Centreren

De Alignment voor X en Y staan beiden op 0.5. De Position voor X en Y staat op 0.

Linksonder

De Alignment voor X = 0 en voor Y = 1. Position x = 40 Position (naar rechts) en Y = -40 (naar boven).

Rechtsonder

De Alignment voor X = 1 en voor Y = 1. Position x = -40 Position (naar links) en Y = -40 (naar boven)

Padding

De bovenste Button heeft een Padding (binnenrand) van 10 rondom, de onderste Button niet.


Praktische voorbeelden

Videotutorials voor wie al een stapje verder wilt gaan.

Boder Widget

Tekst weergeven

Animated Widgets

3D Widget

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.