<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://jasperdelaat.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jasperdelaat.com/" rel="alternate" type="text/html" /><updated>2025-03-16T21:32:24+01:00</updated><id>https://jasperdelaat.com/feed.xml</id><title type="html">Jasper de Laat</title><subtitle>This is Jasper&apos;s personal website, it contains a blog and portfolio sections.</subtitle><author><name>Jasper de Laat</name></author><entry><title type="html">Damage in Unreal Engine 1: Introduction</title><link href="https://jasperdelaat.com/unreal-engine/damage-1/" rel="alternate" type="text/html" title="Damage in Unreal Engine 1: Introduction" /><published>2021-11-14T00:00:00+01:00</published><updated>2021-11-14T00:00:00+01:00</updated><id>https://jasperdelaat.com/unreal-engine/damage-1</id><content type="html" xml:base="https://jasperdelaat.com/unreal-engine/damage-1/"><![CDATA[<p><strong>Damage</strong> is a common concept in games and interactive experiences. Unreal Engine provides a handy little framework for dealing and receiving damage.</p>

<p>This tutorial aims to give you an introduction to the Damage system in blueprint and C++, including tips and tricks that I have learned from experience.</p>

<h2 id="damage-in-unreal">Damage in Unreal</h2>
<p>To <a href="https://youtu.be/JOJP0CvpB8w?t=6">borrow a phrase from Alex Forsythe</a>: With Unreal, damage comes standard. It’s a feature that is part of the <strong>Actor</strong> class, meaning that every actor class that you’ve created so far already natively supports dealing &amp; receiving damage!</p>

<p>Let’s start this tutorial with a quick introduction to the concept of instigator. After that, we’ll move the essentials of dealing and receiving damage in both blueprint and C++.</p>

<h2 id="instigator">Instigator</h2>
<p>You might already have seen the term “instigator” a few times while working in Unreal, most likely when spawning an actor. Every actor has an <code class="language-plaintext highlighter-rouge">Instigator</code> property, it is a reference to a <strong>Pawn</strong> and represents the pawn/character responsible for any actions the spawned actor will do.</p>

<p>The instigator is usually set when you spawn the actor. In blueprints, this is done like this:</p>

<p><img src="/assets/images/damage-1/spawn-instigator.png" alt="A call to SpawnActor in blueprint with the Instigator parameter" /></p>

<p>In C++, you can set the instigator pawn in the <code class="language-plaintext highlighter-rouge">FActorSpawnParameters</code> struct:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">AYourPawn</span><span class="o">::</span><span class="n">SpawnProjectile</span><span class="p">(</span><span class="k">const</span> <span class="n">TSubclassOf</span><span class="o">&lt;</span><span class="n">AActor</span><span class="o">&gt;</span> <span class="n">ProjectileClass</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Assert that FP_MuzzleLocation is a valid component.</span>
    <span class="n">check</span><span class="p">(</span><span class="n">FP_MuzzleLocation</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">);</span>

    <span class="c1">// Spawn a projectile at a specified transform, with instigator set to this pawn.</span>
    <span class="k">const</span> <span class="n">FTransform</span><span class="o">&amp;</span> <span class="n">SpawnTransform</span> <span class="o">=</span> <span class="n">FP_MuzzleLocation</span><span class="o">-&gt;</span><span class="n">GetComponentTransform</span><span class="p">();</span>
    <span class="n">FActorSpawnParameters</span> <span class="n">SpawnParams</span><span class="p">;</span>
    <span class="n">SpawnParams</span><span class="p">.</span><span class="n">Instigator</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
    <span class="n">World</span><span class="o">-&gt;</span><span class="n">SpawnActor</span><span class="o">&lt;</span><span class="n">AActor</span><span class="o">&gt;</span><span class="p">(</span><span class="n">ProjectileClass</span><span class="p">,</span> <span class="n">SpawnTransform</span><span class="p">,</span> <span class="n">SpawnParams</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The concept of instigators is incredibly useful for damage: It allows a damage receiver to act differently depending on who was responsible for dealing the damage. The classroom example for this is <em>friendly fire</em>: If you receive damage and the instigator of the damage is someone on your own team, you might decide to ignore the damage if friendly fire is disabled.</p>

<h2 id="dealing-damage">Dealing damage</h2>
<p>To inflict damage on an actor with blueprints, simply call the <code class="language-plaintext highlighter-rouge">ApplyDamage</code> function:</p>

<p><img src="/assets/images/damage-1/apply-damage.png" alt="A call to ApplyDamage in blueprint with the relevant arguments" /></p>

<p>Let’s briefly talk about some of the parameters:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">Damaged Actor</code>: The actor you’re dealing damage <em>to</em>.</li>
  <li><code class="language-plaintext highlighter-rouge">Event Instigator</code>: The <strong>controller</strong> that is <em>responsible</em> for dealing this damage. You can obtain the instigator controller using the <code class="language-plaintext highlighter-rouge">GetInstigatorController</code> node.</li>
  <li><code class="language-plaintext highlighter-rouge">Damage Causer</code>: The actor that <em>actually dealt</em> this damage (e.g. a projectile or grenade).</li>
  <li><code class="language-plaintext highlighter-rouge">Damage Type Class</code>: An object that can influence damage calculations. This deserves a tutorial on it’s own so we will just keep it empty for now.</li>
</ul>

<p>In addition to <code class="language-plaintext highlighter-rouge">ApplyDamage</code>, there are also separate, specialized functions for dealing point and radial damage. Point damage is for damage at a particular point, coming from a particular direction (like being hit with a bullet). Radial damage is for damage in a wider area, possibily affecting multiple actors (like a grenade blast). I will write a separate tutorial about these damage variants in the future.</p>

<p>The C++ equivalent for dealing damage is <code class="language-plaintext highlighter-rouge">AActor::TakeDamage</code>. While the blueprint equivalent has different functions for each damage variant (i.e. point, radius, etc.), the <code class="language-plaintext highlighter-rouge">TakeDamage</code> function combines all of these into one with a <code class="language-plaintext highlighter-rouge">FDamageEvent</code> struct to differentiate between the variants.</p>

<p>Dealing damage in C++ is pretty simple though, here is the equivalent for the above blueprint example:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">AYourActor</span><span class="o">::</span><span class="n">DealDamageTo</span><span class="p">(</span><span class="k">class</span> <span class="nc">AActor</span><span class="o">*</span> <span class="n">OtherActor</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Much like the blueprint example, we're not using DamageType yet.</span>
    <span class="n">OtherActor</span><span class="o">-&gt;</span><span class="n">TakeDamage</span><span class="p">(</span><span class="mf">4.2</span><span class="n">f</span><span class="p">,</span> <span class="n">FDamageEvent</span><span class="p">(),</span> <span class="n">GetInstigatorController</span><span class="p">(),</span> <span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>For dealing point and radial damage, you will need to supply a <code class="language-plaintext highlighter-rouge">FPointDamageEvent</code> or <code class="language-plaintext highlighter-rouge">FRadialDamageEvent</code> with the proper arguments, instead of the <code class="language-plaintext highlighter-rouge">FDamageEvent</code>. For applying radial damage, I recommend using the <code class="language-plaintext highlighter-rouge">UGameplayStatics::ApplyRadialDamage</code> helper function instead.</p>

<h2 id="responding-to-damage">Responding to damage</h2>
<p>While any actor can receive damage, by default they will do nothing. Responding to damage in an actor is as simple as overriding the <code class="language-plaintext highlighter-rouge">AnyDamage</code> function in blueprint. For C++ things are a bit more tricky, we’ll get to that after the blueprint stuff.</p>

<p>In addition to the <em>any</em> damage function, there are also separate functions for receiving <em>point</em> and <em>radial</em> damage. Keep in mind that when you receive point or radial damage, <code class="language-plaintext highlighter-rouge">AnyDamage</code> will still get called!</p>

<p>The following is an example of responding to damage blueprint, simply override the <code class="language-plaintext highlighter-rouge">AnyDamage</code> function:</p>

<p><img src="/assets/images/damage-1/receive-damage.png" alt="The AnyDamage node" /></p>

<p>Most of the function arguments here are the same as the values you provided to the <code class="language-plaintext highlighter-rouge">ApplyDamage</code> function. The only exception is <code class="language-plaintext highlighter-rouge">Damage Type</code>, which is now an object reference rather than a class reference, more info on this in a future tutorial.</p>

<p>In addition to <code class="language-plaintext highlighter-rouge">AnyDamage</code>, there is also the <code class="language-plaintext highlighter-rouge">OnTakeAnyDamage</code> event dispatcher. This event is particularly useful if you have a component that takes care of dealing with damage, rather than the actor itself:</p>

<p><img src="/assets/images/damage-1/receive-damage-event.png" alt="An example of using the OnTakeAnyDamage event in an actor component" /></p>

<p>Unfortunately, the C++ function <code class="language-plaintext highlighter-rouge">ReceiveAnyDamage</code> in <code class="language-plaintext highlighter-rouge">AActor</code> was not made virtual by Epic, so it cannot be overridden. The next best way is to override the <code class="language-plaintext highlighter-rouge">TakeDamage</code> function instead (<code class="language-plaintext highlighter-rouge">InternalTakeRadialDamage</code> and <code class="language-plaintext highlighter-rouge">InternalTakePointDamage</code> exist for radial and point damage respectively):</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">float</span> <span class="n">AYourActor</span><span class="o">::</span><span class="n">TakeDamage</span><span class="p">(</span><span class="k">const</span> <span class="kt">float</span> <span class="n">DamageAmount</span><span class="p">,</span> <span class="n">FDamageEvent</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">DamageEvent</span><span class="p">,</span> <span class="n">AController</span><span class="o">*</span> <span class="n">EventInstigator</span><span class="p">,</span> <span class="n">AActor</span><span class="o">*</span> <span class="n">DamageCauser</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// If you need the DamageType object like in blueprint, this is how you do it:</span>
    <span class="n">UDamageType</span> <span class="k">const</span><span class="o">*</span> <span class="k">const</span> <span class="n">DamageTypeCDO</span> <span class="o">=</span> <span class="n">DamageEvent</span><span class="p">.</span><span class="n">DamageTypeClass</span> <span class="o">?</span> <span class="n">DamageEvent</span><span class="p">.</span><span class="n">DamageTypeClass</span><span class="o">-&gt;</span><span class="n">GetDefaultObject</span><span class="o">&lt;</span><span class="n">UDamageType</span><span class="o">&gt;</span><span class="p">()</span> <span class="o">:</span> <span class="n">GetDefault</span><span class="o">&lt;</span><span class="n">UDamageType</span><span class="o">&gt;</span><span class="p">();</span>

    <span class="c1">// Make sure to call Super so blueprint &amp; event dispatchers still fire.</span>
    <span class="k">return</span> <span class="n">Super</span><span class="o">::</span><span class="n">TakeDamage</span><span class="p">(</span><span class="n">DamageAmount</span><span class="p">,</span> <span class="n">DamageEvent</span><span class="p">,</span> <span class="n">EventInstigator</span><span class="p">,</span> <span class="n">DamageCauser</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Fortunately, the <code class="language-plaintext highlighter-rouge">OnTakeAnyDamage</code> delegate can simply be bound to in C++, just like with blueprint:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">UYourActorComponent</span><span class="o">::</span><span class="n">BeginPlay</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">Super</span><span class="o">::</span><span class="n">BeginPlay</span><span class="p">();</span>

    <span class="c1">// Subscribe to the owner receiving damage event.</span>
    <span class="n">GetOwner</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">OnTakeAnyDamage</span><span class="p">.</span><span class="n">AddDynamic</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">UYourActorComponent</span><span class="o">::</span><span class="n">OnTakeRadialDamage</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">UYourActorComponent</span><span class="o">::</span><span class="n">OnTakeRadialDamage</span><span class="p">(</span><span class="n">AActor</span><span class="o">*</span> <span class="n">DamagedActor</span><span class="p">,</span> <span class="kt">float</span> <span class="n">Damage</span><span class="p">,</span> <span class="k">const</span> <span class="n">UDamageType</span><span class="o">*</span> <span class="n">DamageType</span><span class="p">,</span> <span class="n">AController</span><span class="o">*</span> <span class="n">InstigatedBy</span><span class="p">,</span> <span class="n">AActor</span><span class="o">*</span> <span class="n">DamageCauser</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Your damage handling code here..</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>
<p>This tutorial has covered the basics of damage: It explained the role of instigators, how damage should be dealt and how it should be received, both in blueprint and C++.</p>

<p><strong>Next tutorial:</strong> Point and radial damage (coming soon™)</p>

<p>If you have any questions, let me know in the comments below! <br />
Jasper</p>]]></content><author><name>Jasper de Laat</name></author><category term="Unreal-Engine" /><category term="Unreal Engine" /><category term="Game Framework" /><category term="C++" /><category term="Blueprint" /><category term="Damage" /><summary type="html"><![CDATA[An introduction to instigators, dealing and receiving damage in Unreal Engine.]]></summary></entry><entry><title type="html">Installing Helix Core on Ubuntu</title><link href="https://jasperdelaat.com/devops/helix-core-ubuntu-install-guide/" rel="alternate" type="text/html" title="Installing Helix Core on Ubuntu" /><published>2021-07-29T00:00:00+02:00</published><updated>2021-07-29T00:00:00+02:00</updated><id>https://jasperdelaat.com/devops/helix-core-ubuntu-install-guide</id><content type="html" xml:base="https://jasperdelaat.com/devops/helix-core-ubuntu-install-guide/"><![CDATA[<p>In this article, I will guide you through the installation of Helix Core (aka <em>Perforce</em>) on <strong>Ubuntu</strong>. I will show you the process of setting up both a client (P4, P4V etc.) and a server (P4D, P4DCTL etc.), as they will have some common setup steps.</p>

<blockquote>
  <p>I found some of the Helix Core Linux documentation was obscure and getting outdated.
This article aims is to guide you through the installation using up-to-date commands and practises, as of writing in 2021.</p>
</blockquote>

<p>This guide assumes knowledge on the following:</p>
<ul>
  <li><strong>Ubuntu</strong>: you know what <code class="language-plaintext highlighter-rouge">apt</code> is, etc.</li>
  <li><strong>CLI</strong>: you can enter and modify terminal commands, etc.</li>
</ul>

<p>This guide is structured as follows: The first section below needs to be performed for both setting up a client or a server. After this common setup there are separate sections for a client setup and a server setup.</p>

<p>Without further ado, let’s dive right in!</p>

<h2 id="setting-up-the-perforce-repository-client--server">Setting up the Perforce repository (Client &amp; Server)</h2>
<p>In this section, we’re going to set up the Perforce package repository for <code class="language-plaintext highlighter-rouge">apt</code> so that we can download the Ubuntu packages of Helix Core.
This section is based on the <a href="https://www.perforce.com/manuals/v21.1/p4sag/Content/P4SAG/install.linux.packages.install.html">official documentation</a>, but with some parts rewritten because <a href="https://www.linuxuprising.com/2021/01/apt-key-is-deprecated-how-to-add.html">apt-key is mostly deprecated</a> starting Ubuntu 20.10 (and Debian 11).</p>

<p>First set up the Perforce repository key and the repository itself:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell">wget <span class="nt">-qO</span> - https://package.perforce.com/perforce.pubkey | <span class="nb">sudo </span>gpg <span class="nt">--dearmor</span> <span class="nt">-o</span> /usr/share/keyrings/perforce-archive-keyring.gpg
<span class="nb">echo</span> <span class="s2">"deb [signed-by=/usr/share/keyrings/perforce-archive-keyring.gpg] http://package.perforce.com/apt/ubuntu focal release"</span> | <span class="nb">sudo tee</span> /etc/apt/sources.list.d/perforce.list
<span class="nb">sudo </span>apt update</code></pre></figure>

<p>Replace <code class="language-plaintext highlighter-rouge">focal</code> with <code class="language-plaintext highlighter-rouge">precise</code>, <code class="language-plaintext highlighter-rouge">trusty</code>, <code class="language-plaintext highlighter-rouge">xenial</code>, or <code class="language-plaintext highlighter-rouge">bionic</code> if you’re using an older version of Ubuntu. 
In my case, I was using Pop!_OS 21.04 which is based on the newer Ubuntu <code class="language-plaintext highlighter-rouge">hirsute</code>, but <code class="language-plaintext highlighter-rouge">focal</code> is the newest available and it worked fine for me.</p>

<p>You should now be able to install software using <code class="language-plaintext highlighter-rouge">apt</code> from the Perforce repository, you can run this command to check it’s working:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell">apt search helix</code></pre></figure>

<p>If all went well, you should see multiple programs starting with <code class="language-plaintext highlighter-rouge">helix-</code> in the output:
<img src="/assets/images/helix-core-ubuntu-install-guide/apt-search-helix.png" alt="Apt search output showing multiple programs starting with &quot;helix-&quot;" />
The next steps depend on whether you’re setting up your computer as a client or a server.</p>

<h2 id="client-setup">Client setup</h2>
<p>Unlike with Windows, when you install P4V from Perforce’s website, the P4 command-line tool is not installed with it. This is a shame because some things like <code class="language-plaintext highlighter-rouge">p4 typemap</code> are not exposed in P4V or P4Admin. Instead, P4 needs to be installed via the package repository we set up in the previous step.</p>

<p>To install P4, simply enter the following:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nb">sudo </span>apt <span class="nb">install </span>helix-cli</code></pre></figure>

<p>After installation, the <code class="language-plaintext highlighter-rouge">p4</code> tool should be readily available for use:
<img src="/assets/images/helix-core-ubuntu-install-guide/p4.png" alt="Execution of &quot;p4&quot; after installing" />
(obviously you’ll have to configure it, just like on Windows)</p>

<p>The installation of the other Helix Core tools (P4V, P4Admin etc.) is fairly similar to Windows:</p>
<ol>
  <li><a href="https://www.perforce.com/products/helix-core-apps/helix-visual-client-p4v">Download them</a></li>
  <li><a href="https://community.perforce.com/s/article/1137">‘Install them’</a></li>
</ol>

<p>I personally ran into a problem starting <code class="language-plaintext highlighter-rouge">p4v</code> after installation, the Qt framework couldn’t load a specific plugin which lead to the application exiting with an error.
If you find yourself in a similar situation, you can try the following to get a more verbose error message:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nb">export </span><span class="nv">QT_DEBUG_PLUGINS</span><span class="o">=</span>1
p4v</code></pre></figure>

<p>In my case, the <code class="language-plaintext highlighter-rouge">libxcb</code> library was missing the <code class="language-plaintext highlighter-rouge">xinerama</code> dependency, which was easily fixed:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nb">sudo </span>apt <span class="nb">install </span>libxcb-xinerama0</code></pre></figure>

<p>You should now have all the Helix Core tools installed on your computer!</p>

<h2 id="server-setup">Server setup</h2>
<p>Installing the server is relatively straightforward after setting up the package repository:</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nb">sudo </span>apt <span class="nb">install </span>helix-p4d</code></pre></figure>

<p>The next step is configuring your server after installation. 
<a href="https://www.perforce.com/manuals/p4sag/Content/P4SAG/install.linux.packages.configure.html">The documentation for this</a> is actually pretty up-to-date, so I suggest you pick it up from there!</p>]]></content><author><name>Jasper de Laat</name></author><category term="DevOps" /><category term="Source Control" /><category term="Linux" /><summary type="html"><![CDATA[Tips and caveats of installing Helix Core/Perforce on Linux.]]></summary></entry></feed>