Create an Entity – Arma Reforger

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Some wiki formatting)
No edit summary
Line 1: Line 1:
{{TOC|side}}
{{TOC|side}}
A {{Link|Arma Reforger:World Editor|World Editor}} entity is a scripted entity that can be placed from the World Editor's '''Create''' tab.
A {{Link|Arma Reforger:World Editor|World Editor}} entity is a scripted entity that can be placed from the World Editor's [[Arma Reforger:World Editor#Create|'''Create''' tab]].


In this example, we will create an Entity that once placed in the world, will print the player's position with a certain frequency.
In this example, we will create an Entity that once placed in the world, will print the player's position with a certain frequency.
Line 307: Line 307:
}
}
</enforce>
</enforce>
</spoiler>
</spoiler><div id="bikisp659bce8cccdcd" class="biki-spoiler"><div>
<div class="enforcescripthighlighter-block armar"><div class="enforcescripthighlighter-scroller"><span class="p">[</span><span class="nc">EntityEditorProps</span><span class="p">(</span>category<span class="p">:</span> <span class="s">"Tutorial Entities"</span><span class="p">,</span> description<span class="p">:</span> <span class="s">"Prints player's position regularly"</span><span class="p">,</span> color<span class="p">:</span> <span class="s">"0 255 0 0"</span><span class="p">)]</span>
<span class="k">class</span> <span class="nc">TAG_PrintPlayerPositionEntityClass</span> <span class="p">:</span> <span class="nc">[./enfusion://ScriptEditor/scripts/GameLib/entities/gameLibEntities.c%3B17 GenericEntityClass]</span>
<span class="p">{</span>
<span class="p">}</span>
 
<span class="k">class</span> <span class="nc">TAG_PrintPlayerPositionEntity</span> <span class="p">:</span> <span class="nc">[./enfusion://ScriptEditor/scripts/GameLib/generated/Entities/GenericEntity.c%3B15 GenericEntity]</span>
<span class="p">{</span>
<span class="p">[</span><span class="nc">Attribute</span><span class="p">(</span>defvalue<span class="p">:</span> <span class="s">"1"</span><span class="p">,</span> desc<span class="p">:</span> <span class="s">"Print player position"</span><span class="p">)]</span>
<span class="k">protected</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/bool.c%3B12 bool]</span> <span class="mv">m_bPrintPlayerPosition</span><span class="p">;</span>
 
<span class="p">[</span><span class="nc">Attribute</span><span class="p">(</span>defvalue<span class="p">:</span> <span class="s">"1"</span><span class="p">,</span> desc<span class="p">:</span> <span class="s">"Print a message when player is null"</span><span class="p">)]</span>
<span class="k">protected</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/bool.c%3B12 bool]</span> <span class="mv">m_bPrintWhenPlayerIsNull</span><span class="p">;</span>
 
<span class="p">[</span><span class="nc">Attribute</span><span class="p">(</span>defvalue<span class="p">:</span> <span class="s">"1"</span><span class="p">,</span> uiwidget<span class="p">:</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/attributes.c%3B37 UIWidgets]</span><span class="p">.</span>Slider<span class="p">,</span> desc<span class="p">:</span> <span class="s">"Print cycle period (in seconds)"</span><span class="p">,</span> params<span class="p">:</span> <span class="s">"1 30 1"</span><span class="p">)]</span>
<span class="k">protected</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/int.c%3B12 int]</span> <span class="mv">m_iCycleDuration</span><span class="p">;</span>
 
<span class="k">protected</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float]</span> <span class="mv">m_fWaitingTime</span> <span class="o">=</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float]</span><span class="p">.</span><span class="c">MAX</span><span class="p">;</span> <span class="c1">// trigger Print on start</span>
 
<span class="k">protected</span> <span class="k">static</span> <span class="nc">TAG_PrintPlayerPositionEntity</span> <span class="mv">s_Instance</span><span class="p">;</span>
 
<span class="c1">//------------------------------------------------------------------------------------------------</span>
<span class="k">protected</span> <span class="nt">void</span> <span class="om">PrintPlayerPosition</span><span class="p">()</span>
<span class="p">{</span>
<span class="nc">[./enfusion://ScriptEditor/scripts/Game/generated/Player/PlayerController.c%3B16 PlayerController]</span> playerController <span class="o">=</span> <span class="om">GetGame</span><span class="p">().</span><span class="om">GetPlayerController</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span>playerController<span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
 
<span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity]</span> player <span class="o">=</span> playerController<span class="p">.</span><span class="om">GetControlledEntity</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span>player<span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="mv">m_bPrintWhenPlayerIsNull</span><span class="p">)</span>
<span class="om">Print</span><span class="p">(</span><span class="s">"Player entity position: no player"</span><span class="p">,</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel]</span><span class="p">.</span><span class="c">NORMAL</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
 
<span class="om">Print</span><span class="p">(</span><span class="s">"Player entity position: "</span> <span class="o">+</span> player<span class="p">.</span><span class="om">GetOrigin</span><span class="p">(),</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel]</span><span class="p">.</span><span class="c">NORMAL</span><span class="p">);</span>
<span class="p">}</span>
 
<span class="c1">//------------------------------------------------------------------------------------------------</span>
<span class="k">override</span> <span class="nt">void</span> <span class="om">EOnFrame</span><span class="p">(</span><span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity]</span> owner<span class="p">,</span> <span class="nt">[./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float]</span> timeSlice<span class="p">)</span>
<span class="p">{</span>
<span class="mv">m_fWaitingTime</span> <span class="o">+=</span> timeSlice<span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="mv">m_fWaitingTime</span> <span class="o"><</span> <span class="mv">m_iCycleDuration</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
 
<span class="mv">m_fWaitingTime</span> <span class="o">=</span> 0<span class="p">;</span>
<span class="om">PrintPlayerPosition</span><span class="p">();</span>
<span class="p">}</span>
 
<span class="c1">//------------------------------------------------------------------------------------------------</span>
<span class="nt">void</span> <span class="nc">TAG_PrintPlayerPositionEntity</span><span class="p">(</span><span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Containers/IEntitySource.c%3B12 IEntitySource]</span> src<span class="p">,</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity]</span> parent<span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="mv">s_Instance</span><span class="p">)</span>
<span class="p">{</span>
<span class="om">Print</span><span class="p">(</span><span class="s">"Only one instance of TAG_PrintPlayerPositionEntity is allowed in the world!"</span><span class="p">,</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel]</span><span class="p">.</span><span class="c">WARNING</span><span class="p">);</span>
<span class="k">delete</span> <span class="k">this</span><span class="p">;</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
 
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="mv">m_bPrintPlayerPosition</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">delete</span> <span class="k">this</span><span class="p">;</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
 
<span class="mv">s_Instance</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
 
<span class="om">SetFlags</span><span class="p">(</span><span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityFlags.c%3B13 EntityFlags]</span><span class="p">.</span><span class="c">ACTIVE</span> | <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityFlags.c%3B13 EntityFlags]</span><span class="p">.</span><span class="c">NO_LINK</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
<span class="om">SetEventMask</span><span class="p">(</span> <span class="nc">[./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityEvent.c%3B13 EntityEvent]</span><span class="p">.</span><span class="c">FRAME</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></div></div>
 
[[Arma Reforger:Create an Entity#bikisp659bce8cccdcd|↑ Back to spoiler's top]]</div></div><span></span>




{{GameCategory|armaR|Modding|Tutorials|Scripting}}
{{GameCategory|armaR|Modding|Tutorials|Scripting}}

Revision as of 11:30, 8 January 2024

A World Editor entity is a scripted entity that can be placed from the World Editor's Create tab.

In this example, we will create an Entity that once placed in the world, will print the player's position with a certain frequency.


Declaration

Entity

Create a new file and name it as your entity - here, we will go with TAG_PrintPlayerPositionEntity so the file should be TAG_PrintPlayerPositionEntity.c.

By convention all Entities classnames must end with the Entity suffix.
An entity script file must be created in the Game module (scripts/Game), otherwise it will not be listed in the Entities list!

class TAG_PrintPlayerPositionEntity : GenericEntity { }

Entity Class

An Entity requires an Entity Class declaration. This allows it to be visible in World Editor. The name must be exactly the Entity name suffixed by Class, here TAG_PrintPlayerPositionClass. An Entity Class is usually placed just above the Entity definition as such:

[EntityEditorProps(category: "Tutorial Entities", description: "Prints player's position regularly")] class TAG_PrintPlayerPositionEntityClass : GenericEntityClass { } class TAG_PrintPlayerPositionEntity : GenericEntity { }

The class is decorated using EntityEditorProps; the category is where the Entity will be found in World Editor's Create tab - see below.

EntityEditorProps

category
the "Create" tab's category in which the Entity can be found
description
unused (for now)
color
the bounding box's unselected line colour - useful only when visible is set to true
visible
have the bounding box always visible - drawn in color
configRoot
unused
icon
unused: direct path to a png file, e.g WBData/EntityEditorProps/entityEditor.png
style
can be "none", "box", "sphere", "cylinder", "capsule", "pyramid", "diamond"
sizeMin
bounding box's lower dimensions
sizeMax
bounding box's higher dimensions
color2
the bounding box's surface colour
dynamicBox
enables the entity visualiser using custom dimensions (provided by _WB_GetBoundBox)


Filling

The Entity is now visible in World Editor, the next step is to make it do something.

Add Code

Let's use the IEntity's constructor to call code.

class TAG_PrintPlayerPositionEntity : GenericEntity { protected float m_fWaitingTime = float.MAX; // trigger Print on start protected int m_iCycleDuration = 10; // in seconds //------------------------------------------------------------------------------------------------ protected void PrintPlayerPosition() { PlayerController playerController = GetGame().GetPlayerController(); if (!playerController) return; IEntity player = playerController.GetControlledEntity(); if (!player) { Print("Player entity position: no player", LogLevel.NORMAL); return; } Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL); } //------------------------------------------------------------------------------------------------ override void EOnFrame(IEntity owner, float timeSlice) { m_fWaitingTime += timeSlice; if (m_fWaitingTime < m_iCycleDuration) return; m_fWaitingTime = 0; PrintPlayerPosition(); } //------------------------------------------------------------------------------------------------ void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent) { SetFlags(EntityFlags.ACTIVE | EntityFlags.NO_LINK, false); SetEventMask(EntityEvent.FRAME); } }

Make It Unique

Let's assume we do not want the Print to be displayed multiple times in the case someone placed multiple Entities in the world.

A singleton is an entity that can only be instanciated once. See Singleton pattern.

For that we will use the static keyword to keep a single reference:

class TAG_PrintPlayerPositionEntity : GenericEntity { // other properties protected static TAG_PrintPlayerPositionEntity s_Instance; // other methods //------------------------------------------------------------------------------------------------ void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent) { if (s_Instance) { Print("Only one instance of TAG_PrintPlayerPositionEntity is allowed in the world!", LogLevel.WARNING); delete this; return; } s_Instance = this; // rest of the init code } }

Add Properties

Now, we can declare properties with the Attribute in order to be able to adjust some settings from the World Editor interface. The following code only contains the added attributes:

class TAG_PrintPlayerPositionEntity : GenericEntity { [Attribute(defvalue: "1", desc: "Print player position")] protected bool m_bPrintPlayerPosition; [Attribute(defvalue: "1", desc: "Print a message when player is null")] protected bool m_bPrintWhenPlayerIsNull; [Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")] protected int m_iCycleDuration; }

The following code contains code with the implemented attributes:

class TAG_PrintPlayerPositionEntity : GenericEntity { [Attribute(defvalue: "1", desc: "Print player position")] protected bool m_bPrintPlayerPosition; [Attribute(defvalue: "1", desc: "Print a message when player is null")] protected bool m_bPrintWhenPlayerIsNull; [Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")] protected int m_iCycleDuration; // other properties //------------------------------------------------------------------------------------------------ protected void PrintPlayerPosition() { PlayerController playerController = GetGame().GetPlayerController(); if (!playerController) return; IEntity player = playerController.GetControlledEntity(); if (!player) { if (m_bPrintWhenPlayerIsNull) Print("Player entity position: no player", LogLevel.NORMAL); return; } Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL); } // other methods //------------------------------------------------------------------------------------------------ void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent) { if (!m_bPrintPlayerPosition) { delete this; return; } // rest of the init code } }

Now all there is to do is to place one TAG_PrintPlayerPositionEntity entity in the world and see the player's position printed in logs!

In order for the entity to appear in World Editor, scripts must be compiled and reloaded via ⇧ Shift + F7.


Final Code

The final file content can be found here:

[EntityEditorProps(category: "Tutorial Entities", description: "Prints player's position regularly", color: "0 255 0 0")] class TAG_PrintPlayerPositionEntityClass : GenericEntityClass { } class TAG_PrintPlayerPositionEntity : GenericEntity { [Attribute(defvalue: "1", desc: "Print player position")] protected bool m_bPrintPlayerPosition; [Attribute(defvalue: "1", desc: "Print a message when player is null")] protected bool m_bPrintWhenPlayerIsNull; [Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")] protected int m_iCycleDuration; protected float m_fWaitingTime = float.MAX; // trigger Print on start protected static TAG_PrintPlayerPositionEntity s_Instance; //------------------------------------------------------------------------------------------------ protected void PrintPlayerPosition() { PlayerController playerController = GetGame().GetPlayerController(); if (!playerController) return; IEntity player = playerController.GetControlledEntity(); if (!player) { if (m_bPrintWhenPlayerIsNull) Print("Player entity position: no player", LogLevel.NORMAL); return; } Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL); } //------------------------------------------------------------------------------------------------ override void EOnFrame(IEntity owner, float timeSlice) { m_fWaitingTime += timeSlice; if (m_fWaitingTime < m_iCycleDuration) return; m_fWaitingTime = 0; PrintPlayerPosition(); } //------------------------------------------------------------------------------------------------ void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent) { if (s_Instance) { Print("Only one instance of TAG_PrintPlayerPositionEntity is allowed in the world!", LogLevel.WARNING); delete this; return; } if (!m_bPrintPlayerPosition) { delete this; return; } s_Instance = this; SetFlags(EntityFlags.ACTIVE | EntityFlags.NO_LINK, false); SetEventMask( EntityEvent.FRAME); } }

↑ Back to spoiler's top
[EntityEditorProps(category: "Tutorial Entities", description: "Prints player's position regularly", color: "0 255 0 0")]

class TAG_PrintPlayerPositionEntityClass : [./enfusion://ScriptEditor/scripts/GameLib/entities/gameLibEntities.c%3B17 GenericEntityClass] { }

class TAG_PrintPlayerPositionEntity : [./enfusion://ScriptEditor/scripts/GameLib/generated/Entities/GenericEntity.c%3B15 GenericEntity] { [Attribute(defvalue: "1", desc: "Print player position")] protected [./enfusion://ScriptEditor/scripts/Core/generated/Types/bool.c%3B12 bool] m_bPrintPlayerPosition;

[Attribute(defvalue: "1", desc: "Print a message when player is null")] protected [./enfusion://ScriptEditor/scripts/Core/generated/Types/bool.c%3B12 bool] m_bPrintWhenPlayerIsNull;

[Attribute(defvalue: "1", uiwidget: [./enfusion://ScriptEditor/scripts/Core/attributes.c%3B37 UIWidgets].Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")] protected [./enfusion://ScriptEditor/scripts/Core/generated/Types/int.c%3B12 int] m_iCycleDuration;

protected [./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float] m_fWaitingTime = [./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float].MAX; // trigger Print on start

protected static TAG_PrintPlayerPositionEntity s_Instance;

//------------------------------------------------------------------------------------------------ protected void PrintPlayerPosition() { [./enfusion://ScriptEditor/scripts/Game/generated/Player/PlayerController.c%3B16 PlayerController] playerController = GetGame().GetPlayerController(); if (!playerController) return;

[./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity] player = playerController.GetControlledEntity(); if (!player) { if (m_bPrintWhenPlayerIsNull) Print("Player entity position: no player", [./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel].NORMAL); return; }

Print("Player entity position: " + player.GetOrigin(), [./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel].NORMAL); }

//------------------------------------------------------------------------------------------------ override void EOnFrame([./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity] owner, [./enfusion://ScriptEditor/scripts/Core/generated/Types/float.c%3B12 float] timeSlice) { m_fWaitingTime += timeSlice; if (m_fWaitingTime < m_iCycleDuration) return;

m_fWaitingTime = 0; PrintPlayerPosition(); }

//------------------------------------------------------------------------------------------------ void TAG_PrintPlayerPositionEntity([./enfusion://ScriptEditor/scripts/Core/generated/Containers/IEntitySource.c%3B12 IEntitySource] src, [./enfusion://ScriptEditor/scripts/Core/generated/Entities/IEntity.c%3B12 IEntity] parent) { if (s_Instance) { Print("Only one instance of TAG_PrintPlayerPositionEntity is allowed in the world!", [./enfusion://ScriptEditor/scripts/Core/generated/Debug/LogLevel.c%3B13 LogLevel].WARNING); delete this; return; }

if (!m_bPrintPlayerPosition) { delete this; return; }

s_Instance = this;

SetFlags([./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityFlags.c%3B13 EntityFlags].ACTIVE | [./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityFlags.c%3B13 EntityFlags].NO_LINK, false); SetEventMask( [./enfusion://ScriptEditor/scripts/Core/generated/Entities/EntityEvent.c%3B13 EntityEvent].FRAME); }

}
↑ Back to spoiler's top