Categories
Advanced Tutorials

Event Functions in Crayta Scripts

Preface

Scripts in Crayta use an event-driven approach by calling certain functions that can be declared in any script. These functions, which can be called entry points, are activated by Crayta as a response to events that occur in the game, quite often with associated arguments.

All these methods are specified in the Crayta Lua API. Some of them you will already have seen like the Init (called on the server to initialize a script) or the OnInteract (called on the server when a player interacts with an entity on all scripts of the entity.)

In this tutorial you will be introduced to the most common and important event functions.

If you are coming to Crayta from a Unity background, entry points will look familiar.

What might be new is the context of execution, where the script is running:  Server, Client or Local. So, many event functions will have variants depending on where they are executing e.g. Init() vs ClientInit() vs LocalInit().

In the beginning this can be slightly confusing but in the long run it will become a powerful way of programming multiplayer games. 

By sharing the same codebase between client/server and easily communicating between the server/client. In another tutorial the relationship between server and client and how the two communicate will be fully explained.

Initialization

It is a common use case to be able to call initialization code before updates occur in gameplay. The Init function provided by Crayta is used to do that and is called as soon as the script is initialised.

There are three variants of this method depending on where it is called:

  • Init, called on the server, on the first frame that the server is running.
  • ClientInit, called on each connected client when that client initializes.
  • LocalInit, this is similar to ClientInit except it only works for scripts attached to either the User or Player template and is only called on the local client.
function ScriptComponent:Init() ... end
function ScriptComponent:ClientInit() ... end
function ScriptComponent:LocalInit() ... end

Here are some examples to help you understand where to use each:

  1. In a dungeon crawler you would like to position random crates with hidden power ups across the dungeon. Running the code in the Init method will ensure that the server is responsible for spawning crates in random places and have those entities propagate automatically to all connected clients.
  2. You would like to start animating a cosmetic object (not important to gameplay) as soon as a player connects. ClientInit will execute as soon as that client is ready and the animation will start playing for the player to watch. If animating entities important to gameplay e.g. a door opening/closing that blocks a gameplay area, that should be done on the Server.
  3. You would like to render in the UI how much time the player has been playing. As soon as he is connected you can save the current time in the LocalInit and pass it to a Widget to be used in the interface logic to measure time.

Regular Updates

Much like most game engines Crayta provides a way to run code that is executed per frame. That is key to program changes to the position, rotation or behavior of objects before each frame is rendered. The OnTick function is the main place to put that kind of code. 

When OnTick runs it also provides the delta time in seconds which is the time elapsed since the last frame was rendered.

function ScriptComponent:OnTick(number deltaTimeSeconds) ... end
function ScriptComponent:ClientOnTick(number timeDeltaSeconds) ... end
function ScriptComponent:LocalOnTick(number timeDeltaSeconds) ... end

Much like the Init function, OnTick comes with the same three variants (regular/Server, Client and Local).

Here is an example on how to use OnTick to rotate an entity each frame:

local RotateScript = {}

RotateScript.Properties = {
    { name = "speed", type = "number", default = 200}
}

function RotateScript:Init()
    self.yaw = 0
end

function RotateScript:OnTick(dt)

    self.yaw = self.yaw + self.properties.speed * dt

    local rotation = Rotation.New(0, self.yaw, 0)
    self:GetEntity():SetRotation(rotation)
end

return RotateScript

Input

Crayta has in place a default player controller (configurable on the Player template) that handles all player and camera movement in the world (walking, running, jumping etc).

Further input handling is provided by a set of event methods that take care of abstracting the source of input (keyboard/mouse or controller).

Interact

The OnInteract method is executed on entities the player interacts with (player targeting the entity and pressing keyboard E or the left face button on the controller with the default mappings).

When OnInteract runs it provides the Player that interacted with that entity as an argument as well as the hitResult on the entity.

function ScriptComponent:OnInteract(Entity player, HitResult hitResult) ... end

There are also two other methods available, OnInteractPressed and OnInteractReleased, that run on scripts attached to either the User or the Player when the interact key is pressed or released accordingly. These two methods will be executed even when there isn’t any object available to interact with.

All OnInteract methods run on the server only.

Actions

Similar to the OnInteractPressed and OnInteractReleased methods, Crayta provides additional methods to listen to user input (keyboard/mouse or controller). 

All methods run on the server only, and most of them on scripts attached to the User or Player entity.

function ScriptComponent:OnButtonPressed(btnName) ... end
function ScriptComponent:OnButtonReleased(btnName) ... end

World

There are several event functions provided by Crayta to interface with the game world and respond to updates or changes that happen in it.

Here are some of the most commonly used events.

OnUserLogin/OnUserLogout

This is a method called on the server to inform you when a new user joins or leaves a World. When it runs the User that has joined or left the World is passed as argument.

function ScriptComponent:OnUserLogin(User user) ... end
function ScriptComponent:OnUserLogout(User user) ... end

OnTriggerEnter/OnTriggerExit

This is a method called on the server by a trigger component placed in the world when any entity enters or exits the trigger. When it runs the Entity that is responsible for triggering the event is passed as argument.

function ScriptComponent:OnTriggerEnter(Entity other) ... end
function ScriptComponent:OnTriggerExit(Entity other) ... end

OnCollision

This method is called on the server when a player collides with an entity. The method will be called on all scripts of that entity and also on the player’s scripts. 

In the first case the Player that collided with the entity will be passed as an argument, in the second case the Entity that the player has collided with will be passed.

function ScriptComponent:OnCollision(Entity collidingPlayerOrEntity) ... end

OnDamage

This method is called on the server on all scripts of the entity when damage is inflicted on that entity, provided the damageEnabled property is enabled.

The arguments passed when this method runs are the damage amount (number), the damage causer (Entity) and the hit result (HitResult).

function ScriptComponent:OnDamage(number damageAmount, Entity damageCauser, HitResult hitResult) ... end