Devlog: Een katapult bouwen voor Unreal Engine

Devlog: Een katapult bouwen voor Unreal Engine

Thijs ReusThijs Reus
·12 december 2025·27 min. leestijd
Let op: dit bericht is automatisch vertaald.

In dit artikel kijken we naar het bouwen van een katapult in Unreal Engine, als alternatief voor typische wapenmechanieken om een projectiel af te vuren. Een katapult is een 2-handig gereedschap: één hand houdt en richt, de andere hand grijpt en trekt het projectiel naar achteren om de uiteindelijke richting en lanceersnelheid te bepalen, en laat het los om het te lanceren.

Katapult in Mixed Reality
Katapult in Mixed Reality

Tech Stack

Voor deze verkenning gebruiken we de volgende tech stack:

Katapult-opbouw

We verdelen de katapult-implementatie in de volgende onderdelen:

  • Slingshot mesh - een Y-vormig mesh dat gegrepen kan worden
  • Projectile mesh - een bolvormig mesh dat gegrepen kan worden wanneer de katapult met de andere hand wordt vastgehouden
  • Actor Blueprint - combineert de verschillende componenten en voegt logica toe, bijvoorbeeld om een projectiel te lanceren
  • Projectile grab/release handling - de logica om het projectiel te verplaatsen wanneer het wordt gegrepen en het te lanceren wanneer het wordt losgelaten
  • Sling Niagara system - toont het dynamische elastiek tussen het katapult-mesh en het projectiel voordat het projectiel wordt gelanceerd
  • Aim Niagara system - toont een laserstraal in de richting waar het projectiel wordt afgevuurd om te helpen bij het richten
  • Physics Constraint - simuleert het projectiel dat in het elastiek hangt om het wat dynamischer te maken tijdens het bewegen

Slingshot Mesh

Elk Y-vormig mesh kan worden gebruikt om de katapult weer te geven. Als er geen dergelijk mesh beschikbaar is, kunnen we het eenvoudig maken met Unreal Engines Modeling Mode door de volgende stappen te volgen:

  • Maak een dunne cilinder voor het I-deel
  • Maak een grotere cilinder en trek een kleinere cirkel uit het midden om een O-vorm te maken
  • Plane-cut de O-vorm om een U-vorm te maken
  • Plaats de U-vorm bovenop het I-deel en merge ze om de uiteindelijke Y-vorm te maken
  • Verplaats de pivot naar center-min-Z zodat deze onderaan staat
Y-vormig mesh voor de katapult
Y-vormig mesh voor de katapult

In de Static Mesh Editor kunnen we enkele Sockets toevoegen om de positie en oriëntatie van belangrijke punten te markeren die we later in het Blueprint zullen gebruiken:

  • Grip - dit is waar de hand naar zal springen bij het grijpen van de katapult, zodat deze altijd in dezelfde positie/oriëntatie wordt vastgehouden
  • Aim - dit is waar we het Aim Niagara System plaatsen
  • Projectile - dit is waar we het Projectiel plaatsen wanneer het niet door de andere hand wordt vastgehouden
  • SlingLeft - dit is waar we het Sling Niagara System aan de linkerkant bevestigen
  • SlingRight - dit is waar we het Sling Niagara System aan de rechterkant bevestigen
Sockets voor de katapult
Sockets voor de katapult

Het gebruik van sockets maakt het later gemakkelijker om verschillende katapult-meshes met hetzelfde Blueprint te gebruiken.

Projectile Mesh

Voor het Projectiel-mesh gebruiken we een eenvoudige bol met de pivot in het midden.

Bol voor het Projectiel
Bol voor het Projectiel

Actor Blueprint

We maken een nieuw Blueprint met GrippableStaticMeshActor van de VR Expansion Plugin als parent-klasse, die al de VRGrip Interface implementeert en een uitstekende basis biedt voor onze katapult:

  • We configureren de actor-eigenschappen
    • Gebruik het katapult-mesh als Static Mesh in de root-component
    • Slot Default Grip Type is ingesteld op Attachment Grip zodat de katapult aan de hand wordt bevestigd terwijl deze wordt vastgehouden
    • Gameplay Tags zijn ingesteld op DropType.OnPrimaryGripRelease en GrabType.OnPrimaryGrip om grijpen/loslaten met standaardbesturingen mogelijk te maken
    • Schakel Simulate Physics in zodat de katapult niet in de lucht zweeft wanneer deze niet wordt vastgehouden
    • Collision presets zijn ingesteld op PhysicsActor
    Blueprint met het katapult-mesh
    Blueprint met het katapult-mesh
  • We voegen een Hand Socket Base component PrimaryGrip toe voor de primaire grijppositie/oriëntatie en passen de handpose aan zodat deze de katapult goed omvat
    • Schakel Flip For Off Hand in zodat een linkshandige greep de gespiegelde pose gebruikt
    • Schakel Use Custom Pose Deltas in zodat de geconfigureerde handpose daadwerkelijk wordt gebruikt
    PrimaryGrip component met handpose
    PrimaryGrip component met handpose
  • We voegen een Scene component ProjectileOrigin toe en bevestigen deze aan de Projectile socket
    Projectile origin component
    Projectile origin component
  • We voegen een GrippableStaticMeshComponent Projectile toe en bevestigen deze aan de ProjectileOrigin, en configureren deze correct:
    • Slot Default Grip Type en Free Default Grip Type zijn ingesteld op Custom Grip omdat we aangepast gedrag zullen hebben terwijl het projectiel wordt vastgehouden
    • Gameplay Tags zijn ingesteld op DropType en GrabType om grijpen/loslaten standaard uit te schakelen (we schakelen dit alleen in wanneer de katapult zelf wordt vastgehouden)
    Projectile component
    Projectile component
  • We voegen een Hand Socket Base component ProjectileGrip toe voor de projectielgrijppositie/oriëntatie en passen de handpose aan zodat deze het projectiel goed omvat
    • Schakel Flip For Off Hand in zodat een linkshandige greep de gespiegelde pose gebruikt
    • Stel Mirror Axis in op Y zodat de handpose correct is bij het gebruik van de linkerhand om het projectiel te grijpen
    • Schakel Use Custom Pose Deltas in zodat de geconfigureerde handpose daadwerkelijk wordt gebruikt
    ProjectileGrip component met handpose
    ProjectileGrip component met handpose

Opmerking: Normaal gesproken zouden we de PrimaryGrip component aan de Grip socket van het katapult-mesh bevestigen, maar deze component werkt niet goed met sockets. In plaats daarvan stellen we in het Begin Play event de locatie/oriëntatie in op die van de socket.

Projectile Grab/Release Handling

Momenteel kunnen we de katapult met beide handen grijpen, maar we kunnen nog niet met het projectiel interageren, omdat we de standaardinstellingen hebben ingesteld om alle grijp-/loslaatacties te negeren.

Daarom voegen we wat logica toe wanneer de katapult wordt gegrepen/losgelaten om het projectielgrijpen in/uit te schakelen door de corresponderende VR Grip Interface methoden op de actor te implementeren:

  • OnGrip - schakel het projectielgrijpen/loslaten in door de Gameplay Tags GrabType.OnPrimaryGrip / DropType.OnPrimaryGripRelease toe te voegen aan de projectielcomponent
  • OnGripRelease - schakel het projectielgrijpen/loslaten uit door de Gameplay Tags GrabType.OnPrimaryGrip / DropType.OnPrimaryGripRelease te verwijderen van de projectielcomponent
OnGrip / OnGripRelease logica
OnGrip / OnGripRelease logica

Nu moeten we afhandelen wanneer het projectiel zelf wordt gegrepen door de corresponderende events op de Projectile component te implementeren:

  • OnGripped - sla de grijp informatie op en begin met het bijwerken van de projectielcomponentlocatie/oriëntatie op basis van de handlocatie/oriëntatie in het actor Tick event
  • OnDropped - lanceer een projectiel en breng de projectielcomponent terug naar de oorspronkelijke locatie/oriëntatie
  • Event Tick - als het projectiel wordt vastgehouden, werk de positie/oriëntatie bij naar die van de hand die het vasthoudt
Projectile OnGripped / OnDropped / Tick logica
Projectile OnGripped / OnDropped / Tick logica

Om een projectiel te lanceren wanneer de projectielcomponent wordt losgelaten, implementeren we onze LaunchProjectile methode:

  • We zorgen ervoor dat de projectielcomponent zich in een geldig bereik bevindt (bijvoorbeeld minimaal 20 cm achter de oorspronkelijke positie), anders lanceren we geen projectiel, zodat het projectiel kan worden teruggeplaatst zonder te worden gelanceerd
  • We bepalen de lanceerrichting door de Look At Rotation te vinden van de projectielcomponent naar waar de oorspronkelijke positie zich momenteel bevindt
  • We spawnen een nieuw BP_Projectile en stellen de oriëntatie in volgens de lanceerrichting
  • We spelen een 'whoosh' geluid af om een succesvolle lancering aan te geven
Launch projectile logica
Launch projectile logica

Tussentijds Resultaat 1

De onderstaande video laat zien dat we nu een functionele katapult hebben in onze Mixed Reality testmap.

Video Voorvertoning

Als je op de afspeelknop klikt, wordt de YouTube-speler ingesloten en kunnen cookies van derden worden ingesteld en gegevens van YouTube worden verzameld.

Natuurlijk kunnen we veel verbeteringen toevoegen, waarvan we er enkele in de volgende secties zullen behandelen.

Sling Niagara System

Momenteel lijkt het projectiel in de katapult te zweven, dus laten we een elastiek maken tussen de katapult en het projectiel.

Eerst maken we een materiaal voor het elastiek zoals getoond in de afbeelding hieronder. Omdat we Niagara beams zullen gebruiken voor het elastiek en het standaard beam-materiaal additief is en een gradient heeft (wat betekent dat het niet volledig ondoorzichtig is), maken we ons eigen beam-materiaal dat volledig ondoorzichtig kan zijn en zelfs een beetje fade langs de beamrand toevoegt om het idee van een niet-vlakke beam te geven.

Sling materiaal voor de Niagara beams
Sling materiaal voor de Niagara beams

Vervolgens maken we een Niagara System met 2 emitters, één voor elke kant van het elastiek.

Sling Niagara System met een emitter voor elke elastiekhelft
Sling Niagara System met een emitter voor elke elastiekhelft
Tweede elastiekhelft emitter
Tweede elastiekhelft emitter

De emitters zijn ingesteld op Local Space zodat het elastiek met de katapult meebeweegt, anders kunnen de elastieken achterblijven bij het bewegen van de katapult. Als bonus hoeven we het start- en eindpunt niet elke frame bij te werken, omdat ze constant blijven ten opzichte van de katapult.

We definiëren 5 parameters om het elastiek vanuit het blueprint te besturen:

  • SlingStart - het begin van de eerste helft van het elastiek, relatief ten opzichte van de Niagara System component
  • SlingMiddle - het einde van beide helften van het elastiek, relatief ten opzichte van de Niagara System component
  • SlingEnd - het begin van de tweede helft van het elastiek, relatief ten opzichte van de Niagara System component
  • SlingColor - de kleur van de elastieken
  • SlingWidth - de breedte van de elastieken

Opmerking: de Beam End locatie is relatief ten opzichte van Beam Start, dus in de emitter moeten we de Beam Start waarde aftrekken van de SlingMiddle waarde om een correcte positie voor Beam End te garanderen.

Nu het Niagara System klaar is, voegen we het toe aan het katapult blueprint, bevestigen het aan de SlingLeft socket en geven enkele betekenisvolle standaardwaarden voor de parameters:

  • SlingStart blijft op (0, 0, 0) wat overeenkomt met de locatie van de SlingLeft socket
  • SlingMiddle is ingesteld op (9, 0, -1) wat overeenkomt met het midden van het projectiel
  • SlingEnd is ingesteld op (18, 0, 0) wat overeenkomt met de locatie van de SlingRight socket
    • We zouden wat logica kunnen toevoegen aan Begin Play om daadwerkelijk de juiste waarde van de socket te nemen en in te stellen, we laten dit als oefening voor de lezer
  • SlingWidth is ingesteld op 1.0 wat dik genoeg is voor het elastiek
Katapult blueprint met sling Niagara system
Katapult blueprint met sling Niagara system

Nu moeten we ervoor zorgen dat het midden van het elastiek altijd overeenkomt met de locatie van het projectiel, dus voegen we een nieuwe functie UpdateSlingPosition toe aan het blueprint en roepen deze aan op 2 locaties in de EventGraph:

  • Nadat het projectiel is teruggebracht naar de oorspronkelijke locatie na het loslaten
  • Nadat het projectiel is verplaatst naar de locatie van de grijpende controller wanneer het wordt vastgehouden
Het activeren van de UpdateSlingPosition functie in de event graph
Het activeren van de UpdateSlingPosition functie in de event graph

Bij het bijwerken van het midden van het elastiek moeten we ervoor zorgen dat de positie die we instellen relatief is ten opzichte van de Niagara System component, want dat is wat ons Niagara System verwacht.

UpdateSlingPosition functie-implementatie
UpdateSlingPosition functie-implementatie

Nu hebben we een functionerend elastiek dat met het projectiel meebeweegt, wat de katapult al aanzienlijk verbetert. In toekomstige iteraties kunnen we het nog beter maken, bijvoorbeeld door:

  • De kleur en breedte van het elastiek aan te passen wanneer het langer wordt (door het projectiel te grijpen en naar achteren te bewegen) om toenemende spanning op het elastiek aan te geven
  • Een 'bucket'-mesh toe te voegen dat het projectiel vasthoudt en het elastiek eraan te bevestigen (in plaats van het elastiek te verbinden met het midden van het projectiel)

Aim Niagara System

Om de gebruiker te helpen bij het richten van de katapult, voegen we nog een Niagara System toe voor een laser die in de richting wijst waar het projectiel wordt afgevuurd. Het geeft ook aan wanneer het projectiel wordt gelanceerd bij het loslaten, omdat we de laser alleen inschakelen wanneer het projectiel meer dan 15 cm van de oorspronkelijke oorsprong verwijderd is.

Eerst maken we een materiaal voor het richten zoals getoond in de afbeelding hieronder, zodat we wat meer transparantie hebben naar de randen van de beam. In plaats van Additive gebruiken we een Translucent materiaal, zodat het ook zichtbaar is in gebieden waar passthrough is ingeschakeld.

Aim materiaal voor de Niagara beams
Aim materiaal voor de Niagara beams

Vervolgens maken we een Niagara System met 1 emitter.

Aim Niagara System met een enkele emitter voor de aim beam
Aim Niagara System met een enkele emitter voor de aim beam

De emitter is ingesteld op Local Space zodat het richten met de katapult meebeweegt, anders kan het richten achterblijven bij het bewegen van de katapult. Hier nemen we aan dat het begin van de aim beam altijd op de locatie van de Niagara System component is.

We definiëren 3 parameters om het richten vanuit het Blueprint te besturen:

  • AimEnd - het einde van de aim beam, relatief ten opzichte van de Niagara System component
  • AimColor - de kleur van de aim beam
  • AimWidth - de breedte van de aim beam

Nu het Niagara System klaar is, voegen we het toe aan het katapult blueprint, bevestigen het aan de Aim socket en geven enkele betekenisvolle standaardwaarden voor de parameters:

  • AimEnd is ingesteld op (100, 0, 0) zodat we het kunnen zien in de blueprint viewport en kunnen verifiëren dat het op de juiste locatie staat en de juiste oriëntatie heeft
  • AimWidth is ingesteld op 1.0 wat dik genoeg is voor het richten
Katapult blueprint met Aim Niagara system
Katapult blueprint met Aim Niagara system

Nu moeten we ervoor zorgen dat:

  1. de aim beam alleen zichtbaar is wanneer het projectiel minimaal 15 cm van de oorspronkelijke oorsprong verwijderd is (waar het loslaten een projectiel zou lanceren), en
  2. de richting van de aim beam overeenkomt met de richting waarin het projectiel nu zou worden gelanceerd, en
  3. de aim beam stopt bij het eerste zichtbare object/oppervlak dat het raakt (het zou niet door vaste objecten/oppervlakken moeten gaan)

Hiervoor voegen we een nieuwe functie UpdateAimPosition toe aan het Blueprint en roepen deze aan op 3 locaties in de EventGraph:

  • BeginPlay event - dit zorgt ervoor dat de aim beam verborgen is aan het begin van het level, ervan uitgaande dat het projectiel op zijn oorsprong is
  • Nadat het projectiel is teruggebracht naar de oorspronkelijke locatie na het loslaten
  • Nadat het projectiel is verplaatst naar de locatie van de grijpende controller wanneer het wordt vastgehouden
Het activeren van de UpdateAimPosition functie in de event graph
Het activeren van de UpdateAimPosition functie in de event graph

De implementatie doet in wezen de volgende stappen:

  • Toon of verberg het richten op basis van de huidige afstand tussen het projectiel en de oorspronkelijke oorsprong
  • Stel de richting van de aim beam in op de richting van het projectiel als het nu zou worden gelanceerd
  • Voer een visibility LineTrace uit vanaf de aim start locatie in de aim richting en pas de aim beam lengte dienovereenkomstig aan (zodat het niet door vaste objecten/oppervlakken gaat)
UpdateSlingPosition functie-implementatie (1e deel)
UpdateSlingPosition functie-implementatie (1e deel)
UpdateSlingPosition functie-implementatie (2e deel)
UpdateSlingPosition functie-implementatie (2e deel)

Nu is het richten veel gemakkelijker, zelfs wanneer de aim start positie iets onder de werkelijke projectiellanceerlocatie ligt. Dit is geen groot probleem, gezien de relatief hoge lanceersnelheid en het feit dat het projectiel momenteel wordt beïnvloed door zwaartekracht, terwijl het richten een rechte lijn is.

Tussentijds Resultaat 2

De onderstaande video laat zien dat we nu een katapult hebben in onze Mixed Reality testmap met een functionerend elastiek en richten, die de gebruiker ook aangeeft wanneer een projectiel zou worden gelanceerd bij het loslaten van het projectiel, of wanneer het gewoon terug zou keren naar de oorspronkelijke oorsprong.

Video Voorvertoning

Als je op de afspeelknop klikt, wordt de YouTube-speler ingesloten en kunnen cookies van derden worden ingesteld en gegevens van YouTube worden verzameld.

Natuurlijk kunnen we nog steeds enkele verbeteringen toevoegen, met name een manier om de projectiellocatie minder rigide te maken wanneer deze niet wordt vastgehouden, zodat het eruitziet alsof het projectiel in het elastiek hangt.

Physics Constraint

Momenteel hangt het projectiel zeer rigide in de katapult, wat niet erg mooi is. Om het projectiel een beetje te laten bewegen op basis van de katapultbeweging, kunnen we een PhysicsConstraint toevoegen aan de katapult. We hebben besloten om een onzichtbare proxy te simuleren voor het projectiel (PhysicsProjectile) en de zichtbare projectiellocatie bij te werken naar de proxy-locatie wanneer deze niet wordt vastgehouden. Op die manier hoeven we de PhysicsConstraint niet te breken/terug te zetten wanneer de gebruiker het projectiel grijpt of loslaat.

Voor deze setup hebben we 3 extra componenten nodig:

  • Een PhysicsOrigin component die het vaste punt van de constraint is, die geen fysica simuleert en niet wordt beïnvloed door zwaartekracht
  • Een PhysicsProjectile component die de onzichtbare proxy voor het projectiel is, die fysica simuleert en wordt beïnvloed door zwaartekracht
  • Een PhysicsConstraint component die beide componenten verbindt en het PhysicsProjectile op de juiste plaats houdt, zelfs als we de katapult verplaatsen of roteren

De PhysicsOrigin heeft de volgende eigenschappen:

  • Deze is iets boven de ProjectileOrigin geplaatst, in dit geval 1 cm
  • Collision is ingesteld op No Collision
  • Hidden in Game is ingeschakeld, omdat we dit alleen gebruiken als referentiepunt voor de PhysicsConstraint
PhysicsOrigin component in het katapult blueprint
PhysicsOrigin component in het katapult blueprint

Het PhysicsProjectile heeft de volgende eigenschappen:

  • Simulate Physics is ingeschakeld
  • Collision is ingesteld op Physics Only, en alle collision responses zijn ingesteld op Ignore
  • Hidden in Game is ingeschakeld, omdat we dit alleen gebruiken voor de simulatie terwijl het projectiel niet wordt vastgehouden
PhysicsProjectile component in het katapult blueprint
PhysicsProjectile component in het katapult blueprint

De PhysicsConstraint heeft de volgende eigenschappen:

  • Deze is geplaatst op de Projectile socket van de katapult
  • De constraint Component Names zijn ingesteld op PhysicsOrigin en PhysicsProjectile (dit moet exact overeenkomen met de componentnamen)
  • Disable Collision is ingeschakeld, omdat we het PhysicsProjectile slechts zeer beperkt (2 cm) binnen de katapult laten bewegen
  • Parent Dominates is ingeschakeld, omdat we alleen het PhysicsProjectile willen verplaatsen en de PhysicsOrigin beschouwen als een vast referentiepunt binnen de katapult
  • We stellen X / Y / Z Motion in op Limited en stellen de Limit in op 2 cm
  • We stellen de Angular Limits in op Locked omdat we ons momenteel niet interesseren voor rotaties
  • We stellen het Linear Motor Position Target in op 0, 0, 0 met 25 sterkte
  • We stellen het Linear Motor Velocity Target in op 0, 0, 0 met 1 sterkte
PhysicsConstraint component (1e deel) in het katapult blueprint
PhysicsConstraint component (1e deel) in het katapult blueprint
PhysicsConstraint component (2e deel) in het katapult blueprint
PhysicsConstraint component (2e deel) in het katapult blueprint

Om dit goed te laten werken bij het verplaatsen van de katapult, moeten we het PhysicsProjectile wekken en het Reference Frame elke tick aanpassen. We doen dit door een nieuwe functie UpdatePhysicsConstraint toe te voegen en deze aan het begin van de Event Tick in de EventGraph aan te roepen.

Event graph om de physics constraint elke tick bij te werken
Event graph om de physics constraint elke tick bij te werken
UpdatePhysicsConstraint implementatie
UpdatePhysicsConstraint implementatie

Het resultaat is te zien in de onderstaande video, die er nu veel beter uitziet met het hangende projectiel.

Video Voorvertoning

Als je op de afspeelknop klikt, wordt de YouTube-speler ingesloten en kunnen cookies van derden worden ingesteld en gegevens van YouTube worden verzameld.

Verdere verbeteringen

De katapult die we tot nu toe hebben gebouwd werkt al vrij goed, maar er zijn natuurlijk verdere verbeteringen mogelijk:

  • Schakel de tick-verwerking alleen in wanneer de katapult wordt vastgehouden
  • Gebruik een GrippableSphereComponent voor de projectielgreep (in plaats van een GrippableStaticMeshComponent), zodat we deze iets groter kunnen maken dan het projectiel zelf om de projectielgreep gemakkelijker te maken voor de gebruiker (momenteel kan de gebruiker per ongeluk de katapult zelf grijpen wanneer de hand te veel naar links of rechts van het projectiel is)
  • Scheid het projectiel van de katapult (zodat de gebruiker een projectiel ergens anders moet oppakken en het dan met de katapult kan gebruiken)
  • Beperk het bereik waarin een projectiel wordt gelanceerd, momenteel is elke richting toegestaan, zelfs wanneer het geen zin heeft (bijvoorbeeld het projectiel recht naar beneden door de katapult trekken)
  • Pas de gelanceerde projectielsnelheid aan op basis van hoe ver het projectiel van de katapult is teruggetrokken

Conclusie

Een katapult is een leuke variatie op de traditionele wapenmechanieken en kan extra immersie bieden door een leuke manier te bieden om projectielen te richten en te lanceren in een VR- of MR-omgeving.

Wij bij Immerstory zijn enthousiast om onze klanten te ondersteunen bij hun immersieve ervaringen en kijken ernaar uit om binnenkort meer verkenningstoezicht te delen.

Welke immersieve ervaring zou je graag willen zien? Laat het ons weten!

Aanvullende bronnen

Documentatie voor de MetaXR plugin, specifiek het Mixed Reality Utility Kit dat voor deze demo werd gebruikt, is hier te vinden

Geluidseffecten in de demo-app zijn dankbaar verkregen van Sonniss GameAudioGDC

Meer van de blog