Categories
Advanced Tutorials

Accessing table methods in Lua

Preface

Object Oriented Programming (OOP), is one the most used programming techniques used in the modern era of programming. There are a lot of programming languages that support OOP, and Lua provides a number of ways to practice OOP in your code. Lua isn’t a true OOP language itself, but the way it’s implemented in Crayta exposes several OOP concepts for use (tables/scripts, properties etc.).

Crayta uses the OOP paradigm in its scripts, allowing you to easily take advantage of it in your code.

In this tutorial we will explain how to access table values (properties and methods of an object, in OOP lingo) and common pitfalls to look for.

In Unity the C# language fully supports OOP. The Unity script classes, properties and method will look familiar in comparison to how a Crayta script is structured and used.

Objects in Lua

You implement OOP in Lua with the help of tables and first class functions. By placing functions and related data into a table, an object is formed.

Tables in Lua have the features of an OOP object like state and identity that is independent of its values. Two objects (tables) with the same value are different objects, whereas an object can have different values at different times, but it is always the same object. Like objects and tables have a life cycle that is independent of who created them or where they were created.

Each Crayta script is implemented as a table that can reference a number of properties and methods.

Accessing table methods

Understanding Colon and Dot Operators

Many programmers learning Lua for the first time struggle with the difference between a function call that uses a colon (:) to call table method and a call that uses a dot/period (.). 

For example:

local length = string.len( "Hello World" )
enemyEntity:SetRotation(rotation)

Both methods will work and execute correctly, so when should you be using each one?

Deciding whether to use the colon or dot syntax, to access a method, can often be determined by whether you need a reference to the object within the function. This is irrelevant for standalone functions, but it’s quite important for functions which are defined as methods of objects.

The colon (:) is used for implementing methods that automatically pass self as the first parameter.

The following call:

enemyEntity:SetRotation(rotation)

Has the same result with calling this method:

enemyEntity.SetRotation(enemyEntity, rotation)

So basically the colon (:) is used as a short form of calling a method and having self appended as a parameter automatically by the compiler.

Deciding whether to use the colon or dot syntax can often be determined by whether you need a reference to the object within the function.

Example error

Here is an example of a Crayta error, when using dot instead of colon out of place. Normally to access the entity the current script is attached to, you can do it like this:

self:GetEntity()

If you use a dot instead of colon, you will get an error like the following:

self.GetEntity()

This happens because of the GetEntity() Crayta method is expecting a reference to the script instance. If you do the following, the method will work correctly:

self.GetEntity(self)

Of course using the colon instead of dot here will result in cleaner and more readable code.

Here is a full Crayta script demonstrating how colon and dot is used in place:

local CollectableScript = {}

function CollectableScript:Init()
    self.collected = false;
end

function CollectableScript:OnCollision(collidingPlayerOrEntity)
    
    if self.collected == true then return end

    self.collected = true
    local name = self:GetEntity():GetName()
    local nameLength = string.len(name)
    
    -- inform the Player/UI of the item collected
    if collidingPlayerOrEntity:IsA(Character) then
        collidingPlayerOrEntity:SendToLocal('Collected', name, nameLength)    
    end 
end

return CollectableScript

Accessing table properties

We should mention here, to avoid confusion, that table properties, like the ones a Crayta script exposes for editing, always use the dot (.) operator.

Health.Properties = {}

Health.Properties = {
   { name = "maxHealth", type = "number"}
}

function Health:Init(){
   Print(self.properties.maxHealth);
}