Categories
Basic Tutorials

Basic Coding 3: Functions

Preface

Functions are reusable blocks of code, and they exist in most programming languages. Programmers find functions useful for organising their code and saving time, as they don’t have to copy and paste the same lines of code over and over again. Instead, they can wrap the code in a function.

It is good practice to ensure that a function is given a useful name which describes what the it does, and to try to keep functions short-and-sweet. A function should ideally only perform one action, which makes it easier to debug and can often help to make the function more reusable.

Introduction

When a line of code tells Crayta to run a function, we say that we are “calling” that function. You have already written code that exists within a function (Init() OnInteract(), and code which calls other functions (Print()).

This tutorial aims to clarify some of the terminology around functions, and their use in Crayta. You will look at:

  • The use of functions
  • Functions return a value
  • Calling a function and using the returned value
  • Writing a function

Create A Game

Create a new empty map and enter the Advanced level editor.

Add A Door

Use the Library to select a Vault Door Prop, and add it to the game world.

Add a Vault Door Prop to the Game World.

Add A Door Script

Click on the VaultDoor Entity, and add a Script by clicking Entity -> Add -> Script -> New Script. Call the Script DoorScript.

Add a new Script to the door called DoorScript.

Open the Script Editor for the DoorScript.

The Problem

Within the DoorScript, we will be calling a function which plays an animation that is already attributed to the VaultDoor. Using the documentation, you can see that playing an animation on a Prop Entity is possible using the function:

Prop:PlayAnimation(string animationName)

As we did before, let’s break down our problem into a flowchart:

This time round, we want to play an animation on the Door Entity.

Animations are played by telling the Entity itself to play them, not just the Script we are working in. This means we need to get hold of the Entity before we can play any animations.

Get The Entity

Every Script which runs on an Entity has the ability to access the Entity itself, and it needs to do this to access information about it, or run functions in other Scripts

Tech Tips: Functions Return Values

You may already know that a function is a reusable block of code, but did you know that a function can also return a value? Just like a variable, a function can be thought of as a way of accessing data, and storing data for later. However, unlike variables, a function can contain runnable code, that can manipulate the data before it shares it.

For example, take a look at the following code:

function MyClass:MonthsInAYear()
    return 12
end

In this function, MonthsInAYear(), we are “returning” the number 12. This means if I call it, it will be replaced with that number. For example:

local months = MonthsInAYear() -- the number 12 is stored in the variable months

In this code, the variable months will store whatever is “returned” from calling the function MonthsInAYear().

Some functions return “void”, which means that the value they return is essentially nothing (think void as in space, where there is nothing).

Now that we know that functions can return a value, and that we can store this using a variable, we will put this into practice.

Create an OnInteract function in your DoorScript, which should look like this:

function DoorScript:OnInteract()

end

Within your DoorScript OnInteract() function, add the following line of code:

local entity = self:GetEntity()

This line of code runs the function GetEntity(), which is a function built-in to a Script in Crayta, and then stores the result of that in the variable “entity”. In our case the entity now holds our Vault Door.

We can now use the variable “entity” to access data about the Entity, or run functions on the Entity. For example (don’t actually do this), in order to get the position of the Entity, we could do:

Print(entity.position.x) -- this will print the position of the Entity to the console

Play The “Open Door” Animation

We know from the documentation that any Prop Entity has the function PlayAnimation, which takes a string as a value in the brackets:

Prop:PlayAnimation(string animationName)

The VaultDoor has two animations, “Open” and “Close”, so we can put either of these strings in the brackets of the PlayAnimation function to play those animations. If the animation has already played and the Prop is at the end of the animation in question, then nothing will happen.

To run the PlayAnimation function add the following code underneath the local entity variable declaration:

entity:PlayAnimation("Open")

The code in your DoorScript should look like this:

local DoorScript = {}
DoorScript.Properties = {}

function DoorScript:Init()
end

function DoorScript:OnInteract()
    local entity = self:GetEntity()
    entity:PlayAnimation("Open")
end

return DoorScript

Return to the Level Editor, and test your game. Try interacting with the Vault Door and you should see that it swings open.

You can now open the door by interacting with it during a game Preview.

Return to the Level Editor when you are happy that your code works.

Writing A Function

Opening the door when you interact with it is all well and good, but what if you want to open the door on other events? Or play a sound as well? This is when it might be useful to write a function to do this.

Tech Tips: Anatomy Of A Function

You have already written functions in Lua, and you know that they look like this:

function DoorScript:OnInteract()

end

Let’s break down the function declaration in a bit more depth

function – this is a keyword in Lua which states that we are defining a function

DoorScript – this is the name of the Script that this function belongs to

: – we use a colon to define that what follows is a “member” of this Script

OnInteract – this is the name of the function itself

() – the brackets can hold values that we can pass from the code calling the function to the function itself. If there is nothing in here, we still need to include the brackets, but we can leave them empty.

end – this is a Lua keyword that defines the end of this function

Write your own function in the DoorScript Script like so:

function DoorScript:OpenDoor()
    local entity = self:GetEntity()
    entity:PlayAnimation("Open")
end

Remove the code from within the OnInteract function, and replace it with the following to call the function:

self:OpenDoor()

Your DoorScript should now look like this:

local DoorScript = {}
DoorScript.Properties = {}

function DoorScript:Init()
end

-- function to open the door
function DoorScript:OpenDoor()
    local entity = self:GetEntity()
    entity:PlayAnimation("Open")
end

function DoorScript:OnInteract()
    self:OpenDoor()
end

return DoorScript

Test your game. The behaviour will be the same, but now we are calling the PlayAnimation function from our own function.

Opening The Door From Elsewhere

What if we wanted to open the door when we pressed a button, or pulled a secret lever? This is when functions are really powerful. We can call the OpenDoor() function from somewhere else.

Use the Library to add another Prop Entity to the game world. I have added a wall using some Voxels and placed a Key-Card Reader Entity on the wall next to the Vault Door Entity.

Add a Key-Card Reader near the Door Entity.

Open the Entity Editor for the Key-Card Reader.

Click on the “+” next to OnInteract, and use the menu system to select:

  • Entity: bankVaultDoor
  • Script: DoorScript
  • Event: OpenDoor()
Click on the + next to OnInteract in the Entity Editor for the Properties. Navigate to the onInteract Property. Then add the bankVaultDoor Entity.

Select your OpenDoor() function for the Event dropdown option.

Test Your Game

Preview your game. Try interacting with the Key-Card Reader (or the Prop Entity you chose) and ensure that the door opens. Success!

When you Interact with the Key-Card Reader, you should find that the door swings open.

Recap

In this tutorial, you have looked at how to call functions, how to write functions, and why functions are useful additions to the coders toolbox. You also saw how you can use a mixture of Crayta Entities, Community Scripts and your own code to make completely custom functionality.

Adding Polish

There are several more functions that may be of interest to you, depending on what you want your game to do. Just like the way you used the OnInteract() function, you might also want to try:

  • OnCollision() – called when something collides with this object
  • OnDamage() – called when something damages this object
  • OnTriggerEnter() / OnTriggerExit() – these are called on Scripts attached to a Trigger Volume Entity, when a player enters or exits the Trigger Volume
  • OnTick() – called every frame

To take this game further, and cement your understanding of functions, try the following:

  • Remove the code from the OnInteract() function on the DoorScript, so that the only way to open the door is by interacting with the Key-Card Reader
  • Using a variable on the DoorScript, make the game more challenging by needing to interact with the Key-Card Reader multiple times, before the door opens

Next steps

Functions and variables are the cornerstones of scripting, and a lot can be achieved with just those two. However, there is more that you can achieve once you start using conditionals, which make use of the data stored in variables in order to change the activity in the game and to create timers. Time to move onto Code Tutorial 4: Conditionals.