This documentation contains all the information you need to start with your first project or work with all the different subsystems of the engine, e.g., the Lua scripting interface, the editor, or all the various components.
This section describes some of the core concepts and the ideology of the engine on a very high level. It also features detailed guides to work with the various subsystems of the engine.
IOLITE's core ideology is to offer an easily understandable way to create fun and responsive voxel games.
TODO
The ECS (Entity Component System) forms the engine's core.
An entity is a general-purpose object assigned a context using one or multiple components. The components primarily house the data to accomplish the specific task, and the system, which comes with every component type, provides the logic. A system works on all instantiated components of a particular type. So, for whatever you're trying to accomplish, you will most likely create an entity and decorate it with one or multiple of the available components to perform specific tasks.
By default, every entity created in the editor has a node component attached to it. Nodes assign a position, orientation, and size in the world to an entity and are also in charge of building hierarchies of multiple entities. One node can have multiple child nodes, and each child node can have multiple child nodes on its own.
As a more complex example, if you create an entity and decorate it with a node, character controller, script, and a hierarchy of voxel shape components, this could become the basis for your player character.
Internally the ECS is designed with data-oriented principles, making it possible to work with large scenes and thousands of objects without hiccups. All the data of entities and components are always ensured to be laid out consecutively in memory, utilizing the CPU caches efficiently when, e.g., iterating over specific properties of components. These design principles also ensure that almost any engine part is or can easily be optimized with multithreading in the future.
Worlds are your creative containers. On its basis, a world stores its name and a single root entity. All entities attached to the root entity build the description for your scene. In addition to that, worlds can be saved to and loaded from disk. You can also use worlds to structure your project: Multiple worlds store the levels for your game, while another single world can house the scripts and logic for your menu screen.
Every project reads all its data from one or many so-called data sources. Data sources in the development environment are plain directories in the application's root directory (right next to the application). When deploying a build, you can opt-in to package the data of each of the data sources to an IOLITE package (IPKG) file.
Data is loaded from and stored in the following directories in a data source directory:
/my_data_source/worlds/ /my_data_source/managers/post_effects/ /my_data_source/managers/particle_effects/ /my_data_source/media/images/ /my_data_source/media/heightmaps/ /my_data_source/media/scripts/ /my_data_source/media/sounds/ /my_data_source/media/voxels/
If you're not using certain features, it's perfectly fine to skip the creation of the corresponding directories.
Data sources provide an incredibly flexible approach to modding applications created with IOLITE.
Let's say you want to replace a specific voxel asset in a game, like a tree in a different color or a particular script where you've added some little tweaks or new features. All you have to do is to create a new data source directory and place the modified assets in the correct path in the directory structure, matching the path used in the base data source. After that, you must tell the engine to load your data source first, shadowing the assets in the base data source. The following section about the app metadata file depicts how data sources are handled and loaded.
But data sources are not only handsome for modding purposes. They also offer a great way to tweak and test things without modifying the game's base assets.
The app metadata data file is a JSON file with the following content:
{ "application_name": "IOLITE", "organization_name": "Missing Deadlines", "version_string": "0.1.0", "data_sources": [ "example" ], "active_data_source": "example", "initial_world": "example", "initial_game_state": "Editing", }
The app metadata offers the option to adjust basic things like your application's name and organization. In addition, it is also in charge of defining the data sources that should be used to source files from and which single data source is currently active for editing purposes. Here's an overview of all the different parameters:
application_name
organization_name
version_string
data_sources
active_data_source
initial_world
initial_game_state
Editing
for the editor or Main
to start the application in game mode directly.This section contains a short technical overview of the rendering approach utilized in IOLITE. While these details are optional to work with the engine, having at least some technical information in the back of your head, especially when optimizing your game, can be tremendously helpful.
Two different systems handle the rendering process in IOLITE.
The first system is responsible for displaying the voxels on the screen and for providing the necessary data for the deferred (direct) lighting pass. The other system handles shadow rendering and diffuse/specular global illumination. While the first system utilizes a mixture of ray tracing and rasterization, the second one solely relies on real-time ray tracing using compute shaders.
A world in IOLITE is potentially composed of thousands of so-called voxel shapes. Voxel shapes are one-to-one mappings to the voxel creations loaded from VOX files authored, e.g., in Magica Voxel. Voxel shapes can be positioned, scaled, and rotated however you like. After placing a voxel shape in the scene, the voxelization pass analyzes the voxel data. It then quickly generates a heavily compressed compound of axis-aligned bounding boxes as an overall bounding volume in the background. Voxel shapes are used for displaying everything voxel-related, so even chunks spawned in the destruction systems are subsets of the initial voxel shapes they were created from.
During the rendering stage, the renderer then collects all visible voxel shapes, so the ones neither occluded nor out of the bounds of the camera's view, and renders them to the G-buffer used for the deferred lighting stage. The vertex shader for each voxel shape expands the compressed data to a renderable set of vertices. Subsequently, the fragment shader executes a ray tracing pass, starting from all pixel positions on the bounding volume. If a ray hits a solid voxel, all necessary data is written to the G-buffer. If voxel shapes only occupy a small area on the screen, the rendering of the more complex box geometry is skipped, and the shape's world bounds are rendered instead.
All in all, especially with the occlusion culling pass and conservative depth tests in the background, this approach achieves a close to constant overhead per pixel - making it almost entirely independent of the scene's complexity. Extra care has to be taken to alleviate overdraw, though. Accordingly, it's crucial to ensure that the bounds of shapes are as tight as humanly possible - potentially requiring you to split a complex shape into a compound of multiple smaller shapes to keep the amount of "air" inside the volumes to a minimum.
The real-time ray tracing subsystem works quite differently. Instead of rasterization, it works with various acceleration structures and a low-resolution rendering approach to allow the tracing of millions of rays per frame from any point in the scene in real-time.
In the first step, the GI pass generates a bounding volume hierarchy (BVH) from all the voxel shapes in the world on the fly. This data structure is utilized in the different global illumination passes to accelerate the ray tracing. The BVH allows us to skip large portions of the scene when searching for the actual hits of one specific ray. When the first bounding volume intersecting the ray is found, a ray-tracing pass similar to the approach depicted in the previous system is used.
TODO: The different GI quality levels and their differences, light sources, diffuse sampling, specular sampling, denoising
TODO
---Called once when the script component becomes active. [email protected] entity Ref The ref of the entity the script component is attached to. function OnActivate(entity) end --- Called every frame. [email protected] entity Ref The ref of the entity the script component is attached to. [email protected] delta_t number The time (in seconds) passed since the last call to this function. function Tick(entity, delta_t) end --- Called once when the script component becomes inactive. [email protected] entity Ref The ref of the entity the script component is attached to. function OnDeactivate(entity) end
TODO
The layout of heightmaps is heavily inspired by Teardown. Each of the three color channels of a height map is interpreted in a specific way:
The terrain generator is merely a helper to quickly generate a grid of voxel shapes (chunks) based on the provided data from the map.
Heightmaps are required to be R8G8B8A8_UNORM
textures. The following snippet can be used to create a heightmap DDS file from a PNG file in the correct format:
texconv.exe -y -m 1 -f R8G8B8A8_UNORM my_ui_texture.png
Heightmap terrains can either be created using the height map terrain component or programmatically using the LUA API, which is shown in the following example:
local entity = Terrain.generate_from_heightmap("my_heightmap", "my_template_chunk", 255) --The entity can then be used to, e.g., retrieve the node component and position the terrain in the world
TODO: What are template chunks?
TODO
TODO
TODO
UI textures are also plain DDS files sourced from the media/images
directory. The are some requirements, though:
Here's an example of how to correctly convert a UI texture using DirectXTex:
texconv.exe -y -m 1 -pmalpha -f BC7_UNORM_SRGB my_ui_texture.png
This section focuses on the editor, featuring in-depth descriptions of the essential features, making it easy for you to get started quickly.
TODO
TODO
TODO
To create a new entity in the editor, right-click on the entity in the world inspector you want to attach the new entity to. In the context menu, either select Attach New Entity
or Attach New Entity (With Component)
to create an entity decorated with the selected component from the start.
TODO
To import a scene from a VOX file, open up the File
menu in the editor and select Import Scene from VOX
. Finally, select the VOX file to import the scene from. You can find the imported scene hierarchy below a new entity called vox_scene
. Please note that only scenes from VOX files can be loaded which are already present in the media/voxels
directory.
This chapter in-depth describes all the different Component types available in IOLITE.
TODO
TODO
TODO
TODO
TODO
TODO
TODO
TODO
This section offers a quick overview of all the functions and types made available via the Lua scripting interface. Use this section to quickly localize something and to jump to the detailed description in the next sections.
To ease writing Lua code, you can also download the scripting interface as a LUA file. Autocompletion should work right out of the box with a lot of different IDEs, like, e.g., Visual Studio Code in combination with the widely spread Lua
extension. Just download and place the iolite_api.lua
file right next to your scripts.
The file itself is automatically generated and always reflects the latest state of API visible on this page here.
iolite_api.lua
The file itself looks like this:
---IOLITE Scripting API (https://iolite-engine.com)
[email protected] (c) 2023 Missing Deadlines (Benjamin Wrensch)
---Vector type with two components.
[email protected] Vec2
Vec2 = {
---The x component of this vector.
[email protected] number
x = nil,
---The y component of this vector.
[email protected] number
y = nil
}
---Initializes all components of the vector to the provided parameter.
[email protected] x Vec2|number
[email protected] Vec2 value
function Vec2(x)
end
---Initializes the x and y components to the provided values.
[email protected] x number
[email protected] y number
[email protected] Vec2 value
function Vec2(x, y)
end
---Vector type with three components.
[email protected] Vec3
Vec3 = {
---The x component of this vector.
[email protected] number
x = nil,
---The y component of this vector.
[email protected] number
y = nil,
---The z component of this vector.
[email protected] number
z = nil
}
---Initializes all components of the vector to the provided parameter.
[email protected] x Vec3|number
[email protected] Vec3 value
function Vec3(x)
end
---Initializes the x, y, and z components to the provided values.
[email protected] x number
[email protected] y number
[email protected] z number
[email protected] Vec3 value
function Vec3(x, y, z)
end
---Vector type with four components.
[email protected] Vec4
Vec4 = {
---The x component of this vector.
[email protected] number
x = nil,
---The y component of this vector.
[email protected] number
y = nil,
---The z component of this vector.
[email protected] number
z = nil,
---The w component of this vector.
[email protected] number
w = nil
}
---Initializes all components of the vector to the provided parameter.
[email protected] x Vec4|number
[email protected] Vec4 value
function Vec4(x)
end
---Initializes the x, y, z, and w components to the provided values.
[email protected] x number
[email protected] y number
[email protected] z number
[email protected] w number
[email protected] Vec4 value
function Vec4(x, y, z, w)
end
---A quaternion with four components.
[email protected] Quat
Quat = {
---The x component of this quaternion.
[email protected] number
w = nil,
---The y component of this quaternion.
[email protected] number
x = nil,
---The z component of this quaternion.
[email protected] number
y = nil,
---The w component of this quaternion.
[email protected] number
z = nil
}
---Initializes all components of the quaternion to the provided parameter.
[email protected] quat Quat
[email protected] Quat value
function Quat(quat)
end
---Initializes the w, x, y, and z components to the provided values.
[email protected] w number
[email protected] x number
[email protected] y number
[email protected] z number
[email protected] Quat value
function Quat(w, x, y, z)
end
---Handle used to reference particle emitters.
[email protected] EmitterHandle
EmitterHandle = {
}
---A reference to entities, components or resources. Refs are only returned by functions and can then be used to, e.g., interact with a created node.
[email protected] Ref
Ref = {
}
---A name can be initialized from a string and supports fast comparison with other names (using integer instead of string comparisons internally).
[email protected] Name
Name = {
}
---Initializes an invalid/empty name.
[email protected] Name value
function Name()
end
---Initializes a new name from a string.
[email protected] name string
[email protected] Name value
function Name(name)
end
---Initializes this name from another name.
[email protected] name Name
[email protected] Name value
function Name(name)
end
Math = {}
---Calculates the sine of the provided angle.
[email protected] x number Angle in radians.
[email protected] number value The sine of the angle.
function Math.sin(x)
end
---Calculates the arc sine of the provided value.
[email protected] x number Value in [-1, 1].
[email protected] number value The arc sine in radians.
function Math.asin(x)
end
---Calculates the cosine of the provided angle.
[email protected] x number Angle in radians.
[email protected] number value The cosine of the angle.
function Math.cos(x)
end
---Calculates the arc cosine of the provided value.
[email protected] x number Value in [-1, 1].
[email protected] number value The arc cosine in radians.
function Math.acos(x)
end
---Calculates the tangent of the provided angle.
[email protected] x number Angle in radians.
[email protected] number value The tangent of the angle.
function Math.tan(x)
end
---Calculates the arc tangent of the provided angle.
[email protected] x number Input value.
[email protected] number value The arc tangent in radians.
function Math.atan(x)
end
---Calculates the arc tangent of y/x in radians.
[email protected] y number Proportion of the y-coordinate.
[email protected] x number Proportion of the x-coordinate.
[email protected] number value The arc tangent of y/x in radians.
function Math.atan2(y, x)
end
---Converts the provided angle in radians to degrees.
[email protected] x number Angle in radians.
[email protected] number value Angle in degrees.
function Math.degrees(x)
end
---Converts the provided angle in degrees to radians.
[email protected] x number Angle in degrees.
[email protected] number value Angle in radians.
function Math.radians(x)
end
Math = {}
---Linearly interpolates between the provided input values.
[email protected] x number|Vec2|Vec3|Vec4 Start of the interpolation range.
[email protected] y number|Vec2|Vec3|Vec4 End of the interpolation range.
[email protected] a number Fraction used to interpolate between x and y.
[email protected] any value The interpolated result.
function Math.lerp(x, y, a)
end
---Spherically interpolates between the provided input values. Useful for interpolating between quaternion-based orientations at constant speed.
[email protected] x Quat First interpolant.
[email protected] y Quat Second interpolant.
[email protected] a number Fraction used to interpolate between x and y.
[email protected] Quat value The interpolated result.
function Math.slerp(x, y, a)
end
Math = {}
---Retrieves the component of the vector for the given index.
[email protected] vec Vec2|Vec3|Vec4 The vector to retrieve the component from.
[email protected] idx number The index of the component to retrieve.
[email protected] number value The value of the vector's component for the given index.
function Math.vec_get_component(vec, idx)
end
---Multiplies the provided vectors.
[email protected] left Vec2|Vec3|Vec4 The first vector.
[email protected] right Vec2|Vec3|Vec4] The second vector.
[email protected] any value The product of the operation.
function Math.vec_mul(left, right)
end
---Scales the provided vector by the given scalar value.
[email protected] s number The scalar value the vector is scaled by.
[email protected] vec Vec2|Vec3|Vec4 The vector to scale.
[email protected] any value The scaled vector.
function Math.vec_scale(s, vec)
end
---Divides the first vector by the second vector.
[email protected] left Vec2|Vec3|Vec4 The first vector.
[email protected] right Vec2|Vec3|Vec4 The second vector.
[email protected] any value The quotient of the operation.
function Math.vec_div(left, right)
end
---Adds the second vector to the first vector.
[email protected] left Vec2|Vec3|Vec4 The first vector.
[email protected] right Vec2|Vec3|Vec4 The second vector.
[email protected] any value The summand of the operation.
function Math.vec_add(left, right)
end
---Subtracts the second vector from the first vector.
[email protected] left Vec2|Vec3|Vec4 The first vector.
[email protected] right Vec2|Vec3|Vec4 The second vector.
[email protected] any value The difference of the operation.
function Math.vec_sub(left, right)
end
---Returns the length of the provided vector.
[email protected] vec Vec2|Vec3|Vec4 The vector used for calculating the length.
[email protected] any value The length of the provided vector.
function Math.vec_length(vec)
end
---Returns the squared length of the provided vector. More efficient when only comparing lengths.
[email protected] vec Vec2|Vec3|Vec4 The vector used for calculating the length.
[email protected] any value The squared length of the provided vector.
function Math.vec_length2(vec)
end
---Returns the distance between the two provided points in space.
[email protected] x Vec2|Vec3|Vec4 The first position in space.
[email protected] y Vec2|Vec3|Vec4 The second position in space.
[email protected] any value The distance between the two provided points.
function Math.vec_distance(x, y)
end
---Returns the squared distance between the two provided points in space. More efficient when only comparing distances.
[email protected] x Vec2|Vec3|Vec4 The first position in space.
[email protected] y Vec2|Vec3|Vec4 The second position in space.
[email protected] any value The squared distance between the two provided points.
function Math.vec_distance2(x, y)
end
---Normalizes the provided vector.
[email protected] vec Vec2|Vec3|Vec4 The vector to normalize.
[email protected] any value The normalized vector.
function Math.vec_normalize(vec)
end
---Calculates the cross product of the provided vector.
[email protected] left Vec3 The first vector.
[email protected] right Vec3 The second vector.
[email protected] Vec3 value The cross product of both vectors.
function Math.vec_cross(left, right)
end
---Calculates the dot product of the provided vector.
[email protected] left Vec2|Vec3|Vec4 The first vector.
[email protected] right Vec2|Vec3|Vec4 The second vector.
[email protected] number value The dot product of both vectors.
function Math.vec_dot(left, right)
end
Math = {}
---Multiplies the provided quaternions.
[email protected] left Quat The first quaternion.
[email protected] right Quat The second quaternion.
[email protected] Quat value The product of both quaternions.
function Math.quat_mul(left, right)
end
---Rotates the provided three-component vector using the given quaternion.
[email protected] quat Quat The quaternion used for the rotation.
[email protected] vec Vec3 The vector to rotate.
[email protected] Vec3 value The rotated three-component vector.
function Math.quat_rotate(quat, vec)
end
---Normalizes the provided quaternion.
[email protected] quat Quat The quaternion to normalize.
[email protected] Quat value The normalized quaternion.
function Math.quat_normalize(quat)
end
---Generates a look at quaternion using the provided direction and up vector.
[email protected] dir Vec3 The direction to look in.
[email protected] up Vec3 The up vector.
[email protected] Quat value The look at quaternion for the provided direction and up vector.
function Math.quat_look_at(dir, up)
end
---Generates a quaternion from the provided axis rotation.
[email protected] angle number The angle of the rotation in radians.
[email protected] axis Vec3 The axis to rotate around.
[email protected] Quat value The quaternion for the provided axis rotation.
function Math.quat_angle_axis(angle, axis)
end
---Derives the Euler angles from the provided quaternion.
[email protected] quat Quat The quaternion to derive the Euler angles from.
[email protected] Vec3 value The Euler angles [pitch, yaw, roll] derived from the quaternion.
function Math.quat_to_euler_angles(quat)
end
---Derives a quaternion from the provided Euler angles.
[email protected] euler Vec3 The Euler angles [pitch, yaw, roll] to derive the quaternion from.
[email protected] Quat value The quaternion derived from the Euler angles.
function Math.quat_from_euler_angles(euler)
end
Random = {}
---Generates a random unsigned integer.
[email protected] number value Random unsigned integer value.
function Random.rand_uint()
end
---Generates a random float in [0.0, 1.0].
[email protected] number value Random floating point value.
function Random.rand_float()
end
---Generates a random float in [min, max].
[email protected] min number The smallest random float to generate.
[email protected] max number The largest random float to generate.
[email protected] number value Random floating point value in [min, max].
function Random.rand_float_min_max(min, max)
end
Input = {}
---Gets the state of the given key.
[email protected] key number The key to retrieve the state from.
[email protected] player_id number The player id to retrieve the state from.
[email protected] number value The current state of the given key.
function Input.get_key_state(key, player_id)
end
---Gets the state of the given axis.
[email protected] axis number The axis to retrieve the state from.
[email protected] player_id number The player id to retrieve the state from.
[email protected] number value The current state of the given axis mapped to [-1, 1].
function Input.get_axis_state(axis, player_id)
end
---Gets the position of the mouse.
[email protected] Vec2 value The position of the mouse in pixels.
function Input.get_mouse_pos()
end
---Gets the position of the mouse mapped to viewport coordinates.
[email protected] Vec2 value The position of the mouse relative to the viewport (mapped to [0, 1]).
function Input.get_mouse_pos_viewport()
end
---Gets the delta position of the mouse (calculated as current_mouse_pos - previous_mouse_pos).
[email protected] Vec2 value The position delta in pixels.
function Input.get_mouse_pos_relative()
end
Particle = {}
---Spawns the particle emitter with a certain particle effect at the given position for the provided time.
[email protected] effect_name string The name of the particle effect to use.
[email protected] position Vec3 The position to spawn the emitter at (in world space).
[email protected] lifetime_in_seconds number How long the emitter should live (in seconds).
[email protected] adjust_spawnrate boolean Whether the spawnrate should be adjusted to the lifetime.
[email protected] EmitterHandle value The handle of the emitter.
function Particle.spawn_particle_emitter(effect_name, position, lifetime_in_seconds, adjust_spawnrate)
end
Log = {}
---Logs the given string as information.
[email protected] message string The message to log.
function Log.log_info(message)
end
---Logs the given string as a warning.
[email protected] message string The message to log.
function Log.log_warning(message)
end
---Logs the given string as an error.
[email protected] message string The message to log.
function Log.log_error(message)
end
Settings = {}
---Creates or sets the setting with the given name to the provided value.
[email protected] name string The name of the setting.
[email protected] value number|boolean The value to set.
function Settings.register_or_update_setting(name, value)
end
---Gets the setting with the given name (as a bool).
[email protected] name string The name of the setting to retrieve from.
[email protected] boolean value The value of the setting.
function Settings.find_setting_bool(name)
end
---Gets the setting with the given name (as a float).
[email protected] name string The name of the setting to retrieve from.
[email protected] boolean value The value of the setting.
function Settings.find_setting_float(name)
end
---Gets the setting with the given name (as an unsigned integer).
[email protected] name string The name of the setting to retrieve from.
[email protected] number value The value of the setting.
function Settings.find_setting_uint(name)
end
Ref = {}
---Returns true if the provided ref is valid.
[email protected] ref Ref The ref to check.
[email protected] boolean value True if the provided ref is valid.
function Ref.is_valid(ref)
end
---Gets the id of the provided ref.
[email protected] ref Ref The ref to retrieve from.
[email protected] number value The id of the provided ref.
function Ref.get_id(ref)
end
Entity = {}
---Returns whether the referenced entity is still alive - or not.
[email protected] entity Ref The ref of the entity.
[email protected] boolean value True if the entity referenced is alive.
function Entity.is_alive(entity)
end
---Retrieves the name of the given entity.
[email protected] entity Ref The ref of the entity.
[email protected] string value The name of the entity.
function Entity.get_name(entity)
end
---Returns the first entity found in the world with the given name.
[email protected] name string The name of the entity to retrieve.
[email protected] Ref value The entity with the given name. Returns an invalid ref if not found.
function Entity.find_first_entity_with_name(name)
end
---Returns an array with all entities matching the given name.
[email protected] name string The name of the entities to retrieve.
[email protected] table value List of entities with the given name.
function Entity.find_entities_with_name(name)
end
Name = {}
---Returns true if the given name is valid (not empty).
[email protected] name string The name to check.
[email protected] Ref value True if the given names are valid (and not empty).
function Name.is_valid(name)
end
---Returns whether the names are equal - or not.
[email protected] a Name The first name to compare.
[email protected] b Ref The second name to compare.
[email protected] boolean value True if both names are equal.
function Name.equal_to(a, b)
end
Physics = {}
---Performs a sphere sweep test from the given position into the provided direction. Great for doing intersection tests for fast moving objects, like, e.g., projectiles.
[email protected] p Vec3 The position to start the sweep at.
[email protected] r number The radius of the sphere to sweep with.
[email protected] dir Vec3 The direction to sweep in.
[email protected] dist number The distance to sweep.
[email protected] boolean hit Whether the sweep test hit something - or not.
[email protected] Vec3 pos The position of the hit.
[email protected] Vec3 normal The normal of the hit.
[email protected] Ref ref The ref referencing the component responsible for the hit.
function Physics.sweep_sphere(p, r, dir, dist)
end
---Performs a raycast from the given position into the provided direction.
[email protected] p Vec3 The starting position of the ray.
[email protected] dir Vec3 The direction of the ray.
[email protected] dist number The maximum distance the ray can travel.
[email protected] boolean hit Whether the raycast hit something - or not.
[email protected] Vec3 pos The position of the hit.
[email protected] Vec3 normal The normal of the hit.
[email protected] Ref ref The ref referencing the component responsible for the hit.
function Physics.raycast(p, dir, dist)
end
World = {}
---Returns the root node of the current world.
[email protected] Ref value The root node of the current world.
function World.get_root_node()
end
---Loads the world with the given name replacing the current world.
[email protected] name string The name of the world to load.
function World.load(name)
end
---Spawns the prefab with the given name.
[email protected] name string The name of the prefab to spawn.
[email protected] Ref value The root node of the loaded prefab.
function World.spawn_prefab(name)
end
---Applies radius damage at the given position for explosion type effects.
[email protected] pos Vec3 The world space position to apply the explosion at.
[email protected] r number The radius of the explosion.
[email protected] shade_crater boolean Whether the crater of the explosion should be shaded.
function World.radius_damage(pos, r, shade_crater)
end
Tag = {}
---Returns whether the referenced tag component is alive - or not.
[email protected] tag Ref The ref of the tag component.
[email protected] boolean value True if the tag component referenced is alive.
function Tag.is_alive(tag)
end
---Returns an array of all available entities with matching tags.
[email protected] tag string The tag to match.
[email protected] table value List of entities with matching tag components.
function Tag.find_entities_with_tag(tag)
end
Node = {}
---Returns whether the referenced node component is alive - or not.
[email protected] node Ref The ref of the node component.
[email protected] boolean value True if the node component referenced is alive.
function Node.is_alive(node)
end
---Returns the node component's entity.
[email protected] node Ref The node component to retrieve from.
[email protected] Ref value The entity this node component is attached to.
function Node.get_entity(node)
end
---Gets the node component of the provided entity.
[email protected] entity Ref The Ref of the entity.
[email protected] Ref value The ref of the node component of the provided entity. Returns an invalid ref if none is found.
function Node.get_node_for_entity(entity)
end
---Creates a new node component and entity and attaches it to the root node of the current world.
[email protected] name Ref The name of the node.
function Node.create(name)
end
---Creates a new node component and entity and attatches it to the provided node.
[email protected] parent_node Ref The node to attach the new node to.
[email protected] name Ref The name of the node.
function Node.create(parent_node, name)
end
---Destroys the given node and its whole hierarchy, including all components and entities attached to it and its children.
[email protected] node Ref The node to destroy.
function Node.destroy(node)
end
---Gets the local position of the given node component.
[email protected] node Ref The node component to retrieve from.
[email protected] Vec3 value The local position of the given node component.
function Node.get_position(node)
end
---Gets the world position of the given node component.
[email protected] node Ref The node component to retrieve from.
[email protected] Vec3 value The world position of the given node component.
function Node.get_world_position(node)
end
---Gets the orientation of the given node component.
[email protected] node Ref The node component to retrieve from.
[email protected] Quat value The orientation of the given node component.
function Node.get_orientation(node)
end
---Gets the world orientation of the given node component.
[email protected] node Ref The node component to retrieve from.
[email protected] Quat value The world orientation of the given node component.
function Node.get_world_orientation(node)
end
---Sets the local position of the given node component.
[email protected] node Ref The node component to modify.
[email protected] position Vec3 The local position to set.
function Node.set_position(node, position)
end
---Sets the world position of the given node component by reversing the world transform of the parent node. Can be used to move the node to a fixed world position, regardless of its hierarchy.
[email protected] node Ref The node component to modify.
[email protected] position Vec3 The world position to set.
function Node.set_world_position(node, position)
end
---Sets the local orientation of the given node component.
[email protected] node Ref The node component to modify.
[email protected] position Quat The local orientation to set.
function Node.set_orientation(node, position)
end
---Sets the world orientation of the given node component by reversing the world transform of the parent node. Can be used to set the node to a fixed world orientation, regardless of its hierarchy.
[email protected] node Ref The node component to modify.
[email protected] orientation Quat The world orientation to set.
function Node.set_world_orientation(node, orientation)
end
---Sets the local size of the given node component.
[email protected] node Ref The node component to modify.
[email protected] size Vec3 The local size to set.
function Node.set_size(node, size)
end
---Updates the world transforms of the given node and all its child nodes. Has to be called to make any changes to the node visible.
[email protected] node Ref The root node component to update.
function Node.update_transforms(node)
end
Trigonometry related functions and types.
sin(x) | Calculates the sine of the provided angle. |
asin(x) | Calculates the arc sine of the provided value. |
cos(x) | Calculates the cosine of the provided angle. |
acos(x) | Calculates the arc cosine of the provided value. |
tan(x) | Calculates the tangent of the provided angle. |
atan(x) | Calculates the arc tangent of the provided angle. |
atan2(y, x) | Calculates the arc tangent of y/x in radians. |
degrees(x) | Converts the provided angle in radians to degrees. |
radians(x) | Converts the provided angle in degrees to radians. |
Functions enabling interpolation between different data types.
lerp(x, y, a) | Linearly interpolates between the provided input values. |
slerp(x, y, a) | Spherically interpolates between the provided input values. Useful for interpolating between quaternion-based orientations at constant speed. |
Vector math related functions.
vec_get_component(vec, idx) | Retrieves the component of the vector for the given index. |
vec_mul(left, right) | Multiplies the provided vectors. |
vec_scale(s, vec) | Scales the provided vector by the given scalar value. |
vec_div(left, right) | Divides the first vector by the second vector. |
vec_add(left, right) | Adds the second vector to the first vector. |
vec_sub(left, right) | Subtracts the second vector from the first vector. |
vec_length(vec) | Returns the length of the provided vector. |
vec_length2(vec) | Returns the squared length of the provided vector. More efficient when only comparing lengths. |
vec_distance(x, y) | Returns the distance between the two provided points in space. |
vec_distance2(x, y) | Returns the squared distance between the two provided points in space. More efficient when only comparing distances. |
vec_normalize(vec) | Normalizes the provided vector. |
vec_cross(left, right) | Calculates the cross product of the provided vector. |
vec_dot(left, right) | Calculates the dot product of the provided vector. |
Vec2 | Vector type with two components. |
Vec3 | Vector type with three components. |
Vec4 | Vector type with four components. |
Quaternion math related functions and types.
quat_mul(left, right) | Multiplies the provided quaternions. |
quat_rotate(quat, vec) | Rotates the provided three-component vector using the given quaternion. |
quat_normalize(quat) | Normalizes the provided quaternion. |
quat_look_at(dir, up) | Generates a look at quaternion using the provided direction and up vector. |
quat_angle_axis(angle, axis) | Generates a quaternion from the provided axis rotation. |
quat_to_euler_angles(quat) | Derives the Euler angles from the provided quaternion. |
quat_from_euler_angles(euler) | Derives a quaternion from the provided Euler angles. |
Quat | A quaternion with four components. |
Functions to generate random numbers.
rand_uint() | Generates a random unsigned integer. |
rand_float() | Generates a random float in [0.0, 1.0]. |
rand_float_min_max(min, max) | Generates a random float in [min, max]. |
Functions to interact with the input system.
get_key_state(key, player_id) | Gets the state of the given key. |
get_axis_state(axis, player_id) | Gets the state of the given axis. |
get_mouse_pos() | Gets the position of the mouse. |
get_mouse_pos_viewport() | Gets the position of the mouse mapped to viewport coordinates. |
get_mouse_pos_relative() | Gets the delta position of the mouse (calculated as current_mouse_pos - previous_mouse_pos). |
Functions to interact with the particle system.
spawn_particle_emitter(effect_name, position, lifetime_in_seconds, adjust_spawnrate) | Spawns the particle emitter with a certain particle effect at the given position for the provided time. |
EmitterHandle | Handle used to reference particle emitters. |
Functions necessary to interact with the logging subsystem.
log_info(message) | Logs the given string as information. |
log_warning(message) | Logs the given string as a warning. |
log_error(message) | Logs the given string as an error. |
Functions provided to modify and retrieve settings.
register_or_update_setting(name, value) | Creates or sets the setting with the given name to the provided value. |
find_setting_bool(name) | Gets the setting with the given name (as a bool). |
find_setting_float(name) | Gets the setting with the given name (as a float). |
find_setting_uint(name) | Gets the setting with the given name (as an unsigned integer). |
Functions provided to work with refs. Refs are used to reference components, resources and entities.
Ref | A reference to entities, components or resources. Refs are only returned by functions and can then be used to, e.g., interact with a created node. |
Functions provided to interact with entities.
is_alive(entity) | Returns whether the referenced entity is still alive - or not. |
get_name(entity) | Retrieves the name of the given entity. |
find_first_entity_with_name(name) | Returns the first entity found in the world with the given name. |
find_entities_with_name(name) | Returns an array with all entities matching the given name. |
Functions and types provided to interact with names.
is_valid(name) | Returns true if the given name is valid (not empty). |
equal_to(a, b) | Returns whether the names are equal - or not. |
Name | A name can be initialized from a string and supports fast comparison with other names (using integer instead of string comparisons internally). |
Functions provided to interact with the physics system.
sweep_sphere(p, r, dir, dist) | Performs a sphere sweep test from the given position into the provided direction. Great for doing intersection tests for fast moving objects, like, e.g., projectiles. |
raycast(p, dir, dist) | Performs a raycast from the given position into the provided direction. |
Functions provided to interact with the current world.
get_root_node() | Returns the root node of the current world. |
load(name) | Loads the world with the given name replacing the current world. |
spawn_prefab(name) | Spawns the prefab with the given name. |
radius_damage(pos, r, shade_crater) | Applies radius damage at the given position for explosion type effects. |
Functions provided to interact with tag components.
is_alive(tag) | Returns whether the referenced tag component is alive - or not. |
find_entities_with_tag(tag) | Returns an array of all available entities with matching tags. |
Functions provided to interact with node components.
is_alive(node) | Returns whether the referenced node component is alive - or not. |
get_entity(node) | Returns the node component's entity. |
get_node_for_entity(entity) | Gets the node component of the provided entity. |
create(name) | Creates a new node component and entity and attaches it to the root node of the current world. |
create(parent_node, name) | Creates a new node component and entity and attatches it to the provided node. |
destroy(node) | Destroys the given node and its whole hierarchy, including all components and entities attached to it and its children. |
get_position(node) | Gets the local position of the given node component. |
get_world_position(node) | Gets the world position of the given node component. |
get_orientation(node) | Gets the orientation of the given node component. |
get_world_orientation(node) | Gets the world orientation of the given node component. |
set_position(node, position) | Sets the local position of the given node component. |
set_world_position(node, position) | Sets the world position of the given node component by reversing the world transform of the parent node. Can be used to move the node to a fixed world position, regardless of its hierarchy. |
set_orientation(node, position) | Sets the local orientation of the given node component. |
set_world_orientation(node, orientation) | Sets the world orientation of the given node component by reversing the world transform of the parent node. Can be used to set the node to a fixed world orientation, regardless of its hierarchy. |
set_size(node, size) | Sets the local size of the given node component. |
update_transforms(node) | Updates the world transforms of the given node and all its child nodes. Has to be called to make any changes to the node visible. |
This section lists the detailed description of all functions made available via the Lua scripting interface. To quickly find and jump to a function, please use the overview section above.
local value = Math.sin(x)
x [number]
value [number]
local value = Math.asin(x)
x [number]
value [number]
local value = Math.cos(x)
x [number]
value [number]
local value = Math.acos(x)
x [number]
value [number]
local value = Math.tan(x)
x [number]
value [number]
local value = Math.atan(x)
x [number]
value [number]
local value = Math.atan2(y, x)
y [number]
x [number]
value [number]
local value = Math.degrees(x)
x [number]
value [number]
local value = Math.radians(x)
x [number]
value [number]
local value = Math.lerp(x, y, a)
a [number]
local value = Math.slerp(x, y, a)
x [Quat]
y [Quat]
a [number]
value [Quat]
local value = Math.vec_get_component(vec, idx)
idx [number]
value [number]
local value = Math.vec_mul(left, right)
local x = Vec3(0.0, 21.0, 0.0)
local y = Vec3(0.0, 2.0, 0.0)
local z = Math.vec_mul(x, y)
--z equals [0.0, 42.0, 0.0]
local value = Math.vec_scale(s, vec)
s [number]
local value = Math.vec_div(left, right)
local x = Vec3(0.0, 84.0, 0.0)
local y = Vec3(0.0, 2.0, 0.0)
local z = Math.vec_div(x, y)
--z equals [0.0, 42.0, 0.0]
local value = Math.vec_add(left, right)
local x = Vec3(0.0, 41.0, 0.0)
local y = Vec3(0.0, 1.0, 0.0)
local z = Math.vec_add(x, y)
--z equals [0.0, 42.0, 0.0]
local value = Math.vec_sub(left, right)
local x = Vec3(0.0, 43.0, 0.0)
local y = Vec3(0.0, 1.0, 0.0)
local z = Math.vec_sub(x, y)
--z equals [0.0, 42.0, 0.0]
local value = Math.vec_length(vec)
local value = Math.vec_length2(vec)
local value = Math.vec_distance(x, y)
local value = Math.vec_distance2(x, y)
local value = Math.vec_normalize(vec)
local value = Math.vec_cross(left, right)
left [Vec3]
right [Vec3]
value [Vec3]
local value = Math.vec_dot(left, right)
value [number]
local value = Math.quat_mul(left, right)
left [Quat]
right [Quat]
value [Quat]
local value = Math.quat_rotate(quat, vec)
quat [Quat]
vec [Vec3]
value [Vec3]
local value = Math.quat_normalize(quat)
quat [Quat]
value [Quat]
local value = Math.quat_look_at(dir, up)
dir [Vec3]
up [Vec3]
value [Quat]
local value = Math.quat_angle_axis(angle, axis)
angle [number]
axis [Vec3]
value [Quat]
local value = Math.quat_to_euler_angles(quat)
quat [Quat]
value [Vec3]
local value = Math.quat_from_euler_angles(euler)
euler [Vec3]
value [Quat]
local value = Random.rand_uint()
value [number]
local value = Random.rand_float()
value [number]
local value = Random.rand_float_min_max(min, max)
min [number]
max [number]
value [number]
local value = Input.get_key_state(key, player_id)
key [number]
player_id [number]
value [number]
local value = Input.get_axis_state(axis, player_id)
axis [number]
player_id [number]
value [number]
local value = Input.get_mouse_pos()
value [Vec2]
local value = Input.get_mouse_pos_viewport()
value [Vec2]
local value = Input.get_mouse_pos_relative()
value [Vec2]
local value = Particle.spawn_particle_emitter(effect_name, position, lifetime_in_seconds, adjust_spawnrate)
effect_name [string]
position [Vec3]
lifetime_in_seconds [number]
adjust_spawnrate [boolean]
value [EmitterHandle]
Log.log_info(message)
message [string]
local v = Vec3(5.0, 1.0, 0.5)
Log.log_info(string.format("[%.2f, %.2f, %.2f]", v.x, v.y, v.z))
--Writes "[5.00, 1.00, 0.50]" to log as info
Log.log_warning(message)
message [string]
local v = Vec3(5.0, 1.0, 0.5)
Log.log_warning(string.format("[%.2f, %.2f, %.2f]", v.x, v.y, v.z))
--Writes "[5.00, 1.00, 0.50]" to log as warning
Log.log_error(message)
message [string]
local v = Vec3(5.0, 1.0, 0.5)
Log.log_error(string.format("[%.2f, %.2f, %.2f]", v.x, v.y, v.z))
--Writes "[5.00, 1.00, 0.50]" to log as error
Settings.register_or_update_setting(name, value)
name [string]
local value = Settings.find_setting_bool(name)
name [string]
value [boolean]
local value = Settings.find_setting_float(name)
name [string]
value [boolean]
local value = Settings.find_setting_uint(name)
name [string]
value [number]
local value = Ref.is_valid(ref)
ref [Ref]
value [boolean]
local value = Ref.get_id(ref)
ref [Ref]
value [number]
local value = Entity.is_alive(entity)
entity [Ref]
value [boolean]
local value = Entity.get_name(entity)
entity [Ref]
value [string]
local value = Entity.find_first_entity_with_name(name)
name [string]
value [Ref]
local value = Entity.find_entities_with_name(name)
name [string]
value [table]
local value = Name.is_valid(name)
name [string]
value [Ref]
local value = Name.equal_to(a, b)
a [Name]
b [Ref]
value [boolean]
local hit, pos, normal, ref = Physics.sweep_sphere(p, r, dir, dist)
p [Vec3]
r [number]
dir [Vec3]
dist [number]
hit [boolean]
pos [Vec3]
normal [Vec3]
ref [Ref]
---Simple projectile data structure as an example
local projectile = { prev_pos = Vec3(0.0, 0.0, 0.0), current_pos = Vec3(0.0, 1.0, 0.0) }
--Calculate vector pointing from the previous position to the current one
local to_new_pos = Math.vec_sub(projectile.current_pos, projectile.prev_pos)
--Find the traveled distance and direction
local sweep_dir = Math.vec_normalize(to_new_pos)
local sweep_dist = Math.vec_length(to_new_pos)
--Execute a sweep and do something if we've hit something
if Physics.sweep_sphere(projectile.prev_pos, 0.1, sweep_dir, sweep_dist) then
--Projectile hit detected
end
local hit, pos, normal, ref = Physics.raycast(p, dir, dist)
p [Vec3]
dir [Vec3]
dist [number]
hit [boolean]
pos [Vec3]
normal [Vec3]
ref [Ref]
local value = World.get_root_node()
value [Ref]
World.load(name)
name [string]
local value = World.spawn_prefab(name)
name [string]
value [Ref]
World.radius_damage(pos, r, shade_crater)
pos [Vec3]
r [number]
shade_crater [boolean]
local value = Tag.is_alive(tag)
tag [Ref]
value [boolean]
local value = Tag.find_entities_with_tag(tag)
tag [string]
value [table]
--Accumulated time
T = 0.0
--Lets all nodes tagged as "rotate" rotate slowly around the y-axis
function Tick(entity, delta_t)
--Collect all entities tagged as "rotate"
local entities = Tag.find_entities_with_tag("rotate")
--Accumulate delta time - 10 seconds for full 360 degrees
T = T + delta_t * 360.0 * 0.1
for k=1, #entities do
e = entities[k]
--Fetch the node component for the entity
n = Node.get_node_for_entity(e)
--Rotate all tagged nodes around the y-axis
Node.set_orientation(n, Quat(Vec3(0.0, Math.radians(T), 0.0)))
--Make changes to the transform "visible"
Node.update_transforms(n)
end
end
local value = Node.is_alive(node)
node [Ref]
value [boolean]
local value = Node.get_entity(node)
node [Ref]
value [Ref]
local value = Node.get_node_for_entity(entity)
entity [Ref]
value [Ref]
Node.create(name)
name [Ref]
Node.create(parent_node, name)
parent_node [Ref]
name [Ref]
local a = Node.create(World.get_root_node(), "new_parent")
local b = Node.create(a, "new_child")
Node.destroy(node)
node [Ref]
local value = Node.get_position(node)
node [Ref]
value [Vec3]
local value = Node.get_world_position(node)
node [Ref]
value [Vec3]
local value = Node.get_orientation(node)
node [Ref]
value [Quat]
local value = Node.get_world_orientation(node)
node [Ref]
value [Quat]
Node.set_position(node, position)
node [Ref]
position [Vec3]
Node.set_world_position(node, position)
node [Ref]
position [Vec3]
Node.set_orientation(node, position)
node [Ref]
position [Quat]
Node.set_world_orientation(node, orientation)
node [Ref]
orientation [Quat]
Node.set_size(node, size)
node [Ref]
size [Vec3]
Node.update_transforms(node)
node [Ref]
This section lists the detailed description of all types made available via the Lua scripting interface. Class-like structures are almost exlusively PODs (plain old data) and do not, besides the constructor, expose member functions. To quickly find and jump to a type, please use the overview section above.
--Example of Vec2's member variable layout as a Lua table
local value = {
x = nil,
y = nil
}
x [number]
y [number]
--Example of Vec3's member variable layout as a Lua table
local value = {
x = nil,
y = nil,
z = nil
}
x [number]
y [number]
z [number]
--Example of Vec4's member variable layout as a Lua table
local value = {
x = nil,
y = nil,
z = nil,
w = nil
}
x [number]
y [number]
z [number]
w [number]
--Example of Quat's member variable layout as a Lua table
local value = {
w = nil,
x = nil,
y = nil,
z = nil
}
Quat(quat [Quat])
w [number]
x [number]
y [number]
z [number]
Name()
Name(name [string])
Name(name [Name])