Skip to content

Entities

Radik Khamatdinov edited this page Feb 24, 2026 · 23 revisions

You'll need to create your own entities for your game. If you want to use entities from Half-Life 2, you should implement the entity logic on your own. All entities should be in @tool mode, extend from VMFEntityNode, and be placed in the folder assigned in the config (entities_folder).

  1. Create a script for an entity.
  2. Create a 3D scene with the same name and assign the script.
  3. Try to import your map with the entity.

Note

Inputs of entities are just methods with a single parameter that is passed from outputs. The input method MUST have one parameter. If you don't need a parameter, just write _void = null.

func SomeInput(_void = null): 
  # Do something

Important

Outputs should be called by the trigger_output method (e.g., from a signal).

Repo with some implemented entities: https://github.com/H2xDev/GodotVMF-Entities

In case you don't want to extend your entity from VMFEntityNode, just define a static function called setup. In this case, it's not necessary to make the script in @tool mode. Also, you won't be able to use flags and other features from VMFEntityNode.

class_name SomeEntity extends Node3D

var entity: Dictionary = {};

static func setup(entity: VMFEntity, instance: SomeEntity):
	instance.entity = entity.data; # This is required
	instance.transform = VMFEntityNode.get_entity_transform(entity);
	instance.basis *= Basis(Vector3.UP, -PI / 2);

Example

## func_button.gd
@tool
extends VMFEntityNode

signal interact();
signal OnUseLocked();
signal OnPressed();


const FLAG_ONCE = 2;
const FLAG_STARTS_LOCKED = 2048;

var is_locked = false;
var is_used = false;

var sound = null;
var locked_sound = null;

## Use this instead of _ready
func _entity_ready():
	is_locked = has_flag(FLAG_STARTS_LOCKED);

	# Once we trigger this signal, we trigger the entity's outputs.
	interact.connect(_on_interact);

	if "sound" in entity:
		sound = load("res://Assets/Sounds/" + entity.sound);

	if "locked_sound" in entity:
		locked_sound = load("res://Assets/Sounds/" + entity.locked_sound);

# This method will be called during import
func _entity_setup(e: VMFEntity):
	# Getting entity's brush geometry and assigning it
	var mesh = get_mesh();
	$MeshInstance3D.set_mesh(mesh);

	# Generating collision for the assigned mesh.
	$MeshInstance3D/StaticBody3D/CollisionShape3D.shape = mesh.create_convex_shape();

func _on_interact():
	if is_locked:
		if locked_sound: SoundManager.PlaySound(global_position, locked_sound, 0.05);
		trigger_output(OnUseLocked)
		return;

	if has_flag(FLAG_ONCE) and is_used:
		return;

	if sound: SoundManager.PlaySound(global_position, sound, 0.05);
	trigger_output(OnPressed)
	is_used = true


func Lock(_param = null):
	is_locked = true;

func Unlock(_param = null):
	is_locked = false;

Entity aliases

In case you don't want to place some entities inside the entities folder, you can use aliases:

// vmf.config.json
{
  "import": {
    "entity_aliases": {
      "npc_ghost": "res://objects/npc_ghost/npc_ghost.tscn"
    }
  }
}

VMFEntityNode

The base of all entities. Contains I/O logic and some useful methods for entities.

Standard Inputs

All entities extending from this node will always have these inputs, so you don't need to define them.

Input Description
Toggle Toggles enabled field of the entity
Enable Enables the entity
Disable Disables and blocks outputs for the entity
Kill Removes the node from the tree

API Reference

_entity_ready

Signature Description
_entity_ready() Called when all outputs and reparents are ready. Use this method instead of _ready.

Example:

func _entity_ready():
    # Initialize your entity logic here
    if has_flag(1):
        queue_free()

_entity_setup

Signature Description
_entity_setup(e: VMFEntity) Called during import to setup entities (assigning brushes, generating collisions).

Example:

func _entity_setup(e: VMFEntity):
    var mesh = get_mesh()
    $MeshInstance3D.mesh = mesh
    $CollisionShape3D.shape = mesh.create_convex_shape()

has_flag

Signature Description
has_flag(flag: int) -> bool Checks the spawnflags field of the entity.

Example:

const FLAG_LOCKED = 2048
func _entity_ready():
    isLocked = has_flag(FLAG_LOCKED)

trigger_output

Signature Description
trigger_output(outputName: String | Signal) Triggers outputs defined in the entity.

Example:

if isLocked:
    trigger_output("OnUseLocked")
else:
    trigger_output("OnPressed")

get_mesh

Signature Description
get_mesh(cleanup=true, lods=true) -> ArrayMesh Returns entity's solids as ArrayMesh.
cleanup: remove unnecessary faces.
lods: generate LODs.

Example:

$mesh.mesh = get_mesh()

get_entity_shape

Signature Description
get_entity_shape() -> Shape Returns optimized collision shape (trimesh or convex). Uses CSGMesh.

Example:

$col.shape = get_entity_shape()

get_entity_convex_shape

Signature Description
get_entity_convex_shape() -> Shape Returns a convex shape for the entity's brushes.

Example:

$CollisionShape3D.shape = get_entity_convex_shape()

get_entity_trimesh_shape

Signature Description
get_entity_trimesh_shape() -> Shape Returns optimized trimesh shape for the entity's brushes.

Example:

$CollisionShape3D.shape = get_entity_trimesh_shape()

get_entity_basis

Signature Description
static get_entity_basis(entity: Dictionary) -> Basis Returns rotation state for specified entity.

Example:

var rotation_basis = VMFEntityNode.get_entity_basis(entity_data)

get_movement_vector

Signature Description
static get_movement_vector(vec: Vector3) -> Vector3 Returns directional vector from property. Useful for entities like func_door or func_button.

Example:

var dir: Vector3:
    get: return get_movement_vector(entity.get("movedir", Vector3.LEFT))

convert_vector

Signature Description
static convert_vector(v: Vector3) -> Vector3 Converts Vector3 position from Z-up to Y-up.

Example:

var godot_pos = VMFEntityNode.convert_vector(source_pos)

convert_direction

Signature Description
static convert_direction(v: Vector3) -> Vector3 Converts Vector3 rotation from Z-up to Y-up.

Example:

var godot_rot = VMFEntityNode.convert_direction(source_rot)

define_alias

Signature Description
static define_alias(name: String, value: VMFEntityNode) Defines global alias to node for using in I/O.

Example:

func _entity_ready():
    VMFEntityNode.define_alias('!player', self)

remove_alias

Signature Description
static remove_alias(name: String) Removes global alias.

Example:

func _exit_tree():
    VMFEntityNode.remove_alias('!player')

get_target

Signature Description
get_target(targetName: String) -> VMFEntityNode Returns first node by target name assigned in entity.

Example:

var target_node = get_target(entity.target)
if target_node:
    target_node.trigger_input("Use")

get_all_targets

Signature Description
get_all_targets(targetName: String) -> Array[VMFEntityNode] Returns all nodes by target name assigned in entities.

Example:

var targets = get_all_targets(entity.target)
for t in targets:
    t.trigger_input("Use")

get_separated_collisions

Signature Description
get_separated_collisions() -> Array[CollisionShape3D] Returns a list of collisions for each brush.

Example:

for col in get_separated_collisions():
    $StaticBody3D.add_child(col)

get_entity_transform

Signature Description
static get_entity_transform(entity: Dictionary) -> Transform3D Returns Transform3D of entity.

Example:

transform = VMFEntityNode.get_entity_transform(entity_data)

Prop entities

To make prop entities creation a bit easier you can just inherit your entity from prop_studio instead VMFEntityNode.

Properties

  • model_instance: MeshInstance3D - The mesh instance with the target model
  • model: String - The path to the model

Clone this wiki locally