Create an Entity – Arma Reforger

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Fix category)
(Change from CallQueue().CallLater to EOnFrame)
Line 49: Line 49:
class TAG_PrintPlayerPositionEntity : GenericEntity
class TAG_PrintPlayerPositionEntity : GenericEntity
{
{
protected float m_fWaitingTime = float.MAX; // trigger Print on start
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
protected void PrintPlayerPosition()
protected void PrintPlayerPosition()
Line 64: Line 66:


Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL);
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();
}
}


Line 69: Line 82:
void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent)
void TAG_PrintPlayerPositionEntity(IEntitySource src, IEntity parent)
{
{
GetGame().GetCallqueue().CallLater(PrintPlayerPosition, 0); // initial call - waits for game initialisation
SetFlags(EntityFlags.ACTIVE | EntityFlags.NO_LINK, false);
GetGame().GetCallqueue().CallLater(PrintPlayerPosition, 1000, true);
SetEventMask(EntityEvent.FRAME);
}
}
};
};
Line 85: Line 98:
class TAG_PrintPlayerPositionEntity : GenericEntity
class TAG_PrintPlayerPositionEntity : GenericEntity
{
{
// other properties
protected static TAG_PrintPlayerPositionEntity s_Instance;
protected static TAG_PrintPlayerPositionEntity s_Instance;


//------------------------------------------------------------------------------------------------
// other methods
protected void PrintPlayerPosition()
{
// print code
}


//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
Line 120: Line 131:
protected bool m_bPrintPlayerPosition;
protected bool m_bPrintPlayerPosition;


[Attribute(defvalue: "1", desc: "Print player position when player is null")]
[Attribute(defvalue: "1", desc: "Print a message when player is null")]
protected bool m_bPrintPlayerPositionWhenPlayerNull;
protected bool m_bPrintWhenPlayerIsNull;


[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")]
[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")]
Line 128: Line 139:
</enforce>
</enforce>


The following code contains the whole class with the attributes implemented:
The following code contains code with the implemented attributes:


<enforce>
<enforce>
Line 136: Line 147:
protected bool m_bPrintPlayerPosition;
protected bool m_bPrintPlayerPosition;


[Attribute(defvalue: "1", desc: "Print player position when player is null")]
[Attribute(defvalue: "1", desc: "Print a message when player is null")]
protected bool m_bPrintPlayerPositionWhenPlayerNull;
protected bool m_bPrintWhenPlayerIsNull;


[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 0.1")]
[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")]
protected int m_iCycleDuration;
protected int m_iCycleDuration;


protected static TAG_PrintPlayerPositionEntity s_Instance;
// other properties


//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
Line 154: Line 165:
if (!player)
if (!player)
{
{
if (m_bPrintPlayerPositionWhenPlayerNull)
if (m_bPrintWhenPlayerIsNull)
Print("Player entity position: no player", LogLevel.NORMAL);
Print("Player entity position: no player", LogLevel.NORMAL);
return;
return;
Line 161: Line 172:
Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL);
Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL);
}
}
// other methods


//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
Line 193: Line 206:
protected bool m_bPrintPlayerPosition;
protected bool m_bPrintPlayerPosition;


[Attribute(defvalue: "1", desc: "Print player position when player is null")]
[Attribute(defvalue: "1", desc: "Print a message when player is null")]
protected bool m_bPrintPlayerPositionWhenPlayerNull;
protected bool m_bPrintWhenPlayerIsNull;


[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")]
[Attribute(defvalue: "1", uiwidget: UIWidgets.Slider, desc: "Print cycle period (in seconds)", params: "1 30 1")]
protected int m_iCycleDuration;
protected int m_iCycleDuration;
protected float m_fWaitingTime = float.MAX; // trigger Print on start


protected static TAG_PrintPlayerPositionEntity s_Instance;
protected static TAG_PrintPlayerPositionEntity s_Instance;
Line 211: Line 226:
if (!player)
if (!player)
{
{
if (m_bPrintPlayerPositionWhenPlayerNull)
if (m_bPrintWhenPlayerIsNull)
Print("Player entity position: no player", LogLevel.NORMAL);
Print("Player entity position: no player", LogLevel.NORMAL);
return;
return;
Line 217: Line 232:


Print("Player entity position: " + player.GetOrigin(), LogLevel.NORMAL);
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();
}
}


Line 237: Line 263:
s_Instance = this;
s_Instance = this;


GetGame().GetCallqueue().CallLater(PrintPlayerPosition, 0); // initial call - waits for game initalisation
SetFlags(EntityFlags.ACTIVE | EntityFlags.NO_LINK, false);
GetGame().GetCallqueue().CallLater(PrintPlayerPosition, m_iCycleDuration * 1000, true);
SetEventMask( EntityEvent.FRAME);
}
}
};
};

Revision as of 19:03, 14 November 2022

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.

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.


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 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!

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