Entities - H2xDev/GodotVMF GitHub Wiki
You'll need to create your own entities for your game. If you want to use entities from Half-Life 2 then you should implement entities logic on your own.
All entities should be in @tool
mode, extended from ValveIONode
and placed in the folder that you assigned in the config (entities_folder
).
- Create script of an entity.
- Create a 3d scene with the same name and assign the script.
- Try to import your map with entity.
[!NOTE] Inputs of entities are just methods with a single parameter that passed from outputs.
The input method MUST have one parameter. In case you don't need a parameter just write_void = null
func SomeInput(_void = null): # Do something
[!IMPORTANT] Outputs should be called by method
trigger_output
(from signal for example)
In case you don't want to extend your entity from ValveIONode
, just define 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 ValveIONode
.
class_name SomeEntity extends Node3D
var entity: Dictionary = {};
static func setup(entity_structure: Dictionary, instance: SomeEntity):
instance.entity = entity_structure; # This is required
instance.transform = ValveIONode.get_entity_transform(entity_structure);
instance.basis *= Basis(Vector3.UP, -PI / 2);
Example
## func_button.gd
@tool
extends ValveIONode
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 _ready
func _entity_ready():
is_locked = has_flag(FLAG_STARTS_LOCKED);
# Once we trigger this signal we triggering 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 _apply_entity(entity_structure: Dictionary):
super._apply_entity(entity_structure);
# 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"
}
}
}
ValveIONode
The Base of all entities. Contains I/O logic and some useful methods for entities.
All entities extends from this node will always have these inputs so you don't need to define it.
- Toggle - toggles
enabled
field of the entity - Enable - enable the entity
- Disable - disables and blocks outputs for the entity
- Kill - removes the node from tree
Reference:
- _entity_ready
- _apply_entity
- has_flag
- trigger_output
- get_mesh
- get_entity_shape
- get_entity_convex_shape
- get_entity_trimesh_shape
- get_entity_basis
- get_movement_vector
- convert_vector
- convert_direction
- define_alias (static)
- get_target
- get_all_targets
- get_entity_transform (static)
- get_entity_basis (static)
- get_separated_collisions
- define_alias (static)
_entity_ready()
Means that all outputs and reparents are ready to use. Use this method instead of _ready
.
_apply_entity(entity_structure: Dictionary)
This method called by VMFNode during import entities and needs to make some setup for entities, such as assigning brushes, generation collisions and so on.
Don't forget to call super._apply_entity
before making any changes in the node.
Example
func _apply_entity(entity_structure: Dictionary):
super._apply_entity(entity_structure);
# Getting a mesh from the solid data of the entity and assigning
var mesh = get_mesh();
$MeshInstance3D.set_mesh(mesh);
# Generating a collision shape for the mesh
$MeshInstance3D/StaticBody3D/CollisionShape3D.shape = mesh.create_convex_shape();
has_flag(flag: int) -> bool
Checks the spawnflags
field of the entity.
Example
const FLAG_STARTS_LOCKED = 2048;
var isLocked = false;
func _entity_ready():
isLocked = has_flag(FLAG_STARTS_LOCKED);
trigger_output(outputName: string):
Triggers outputs that defined in the entity.
Example
interact.connect(func():
if isLocked:
trigger_output("OnUseLocked");
else:
trigger_output("OnPressed"));
get_mesh(cleanup = true, lods = true) -> ArrayMesh
Returns entity's solids as ArrayMesh. cleanup
means that the mesh will be cleaned from unnecessary faces. lods
means that the mesh will have generated LODs.
Example
func _apply_entity(entity_structure: Dictionary):
super._apply_entity(entity_structure);
$mesh_instance.mesh = get_mesh(); # Will return ready-to-use mesh with removed ignored faces and generated LODs
get_entity_shape() -> Shape:
Returns optimized collision shape for the entity's solids (trimesh or convex. Depends of brushes count inside of entity). Uses CSGMesh for shape generation
Example
## $body is a StaticBody3D
func _apply_entity(entity_structure: Dictionary):
super._apply_entity(entity_structure);
$body/mesh.mesh = get_mesh();
$body/collision_shape.shape = get_entity_shape();
get_entity_convex_shape() -> Shape
Returns a convex shape for the entity's brushes
get_entity_trimesh_shape() -> Shape
Returns optimized trimesh shape for the entity's brushes
get_entity_basis(entity: Dictionary) -> Basis [static]
Returns rotation state for specified entity.
get_movement_vector(vec: Vector3) -> Vector3 [static]
Returns directional vector from specified vector. If an entity has movement direction property (i.e. func_door, func_button) use this function to convert the direction.
Example
## func_door.gd
var movement_direction: Vector3:
get: return get_movement_vector(entity.get("movedir", Vector3.LEFT));
convert_vector(v: Vector3) -> Vector3 [static]
Converts Vector3 of position from Z-up to Y-up.
convert_direction(v: Vector3) -> Vector3 [static]
Converts Vector3 of rotation from Z-up to Y-up.
define_alias(name: string, value: ValveIONode) [static]
Defines global alias to node for using in I/O.
Example
# player.gd
func _entity_ready():
ValveIONode.define_alias('!player', self);
get_target(targetName: string) -> ValveIONode
Returns first node by target name assigned in entity.
get_all_targets(targetName: string) -> ValveIONode[]
Returns all nodes by target name assigned in entities.
get_separated_collisions() -> Array[CollisionShape3D]
Returns a list of collisions for each brush.
get_entity_transform(entity_structure: Dictionary) -> Transform3D [static]
Returns Transform3D of entity
get_entity_basis(entity_structure: Dictionary) -> Basis [static]
Returns Basis of entity
Prop entities
To make prop entities creation a bit easier you can just inherit your entity from prop_studio
instead ValveIONode
.
Properties
model_instance: MeshInstance3D
- The mesh instance with the target modelmodel: String
- The path to the model