Categories
Advanced Tutorials

The relationship between Player and Default camera

Preface

In most 3D game engines the concept of a camera is quite common. Cameras are the devices that capture and display the world to the player.

Crayta provides this mechanism: a default camera with a number of customization options to easily achieve your desired gameplay camera and the option to spawn any number of secondary cameras to be further used.

In this tutorial we will explore the relationship between the default camera and the player, and also how to create and use additional in-game cameras.

If you are coming from a Unity background you will be familiar with camera game objects.

What’s different in Crayta is that the default camera is directly attached to the Player entity. The default camera comes with ready to use controls for a first and third person camera setting.

In Unity you could do something similar either with implementing your own solution in code or using a starter kit.

Default Camera

In Crayta the default camera is basically the Character entity automatically spawned in the game world from the Player template, so it won’t be exposed separately in the Entities World Tree.

Crayta provides a default first or third person camera with a number of settings to customize for each type.

Camera Primitive

Additional cameras can be spawned in the game world to be used later during game play for cutscenes, level previews, as a background when showing game results etc.

Camera entities spawned in the world remain inactive until activated from a script.

How to select a camera?

When starting any Crayta game your spawned User entity in the game world automatically sets the selected camera to the default. And that would be your Character entity since in Crayta:

The default camera is the character entity.

At any point in a Crayta script you can change the selected camera to any other camera entity using the following code:

userEntity:SetCamera(cameraEntity)

You can also specify an optional second parameter as the transitionTime in seconds. That will automatically animate the view from the current camera to the newly selected one:

userEntity:SetCamera(cameraEntity, 3.0)

At any moment you can fallback to the default camera by calling the same method with no parameters:

userEntity:SetCamera()

And lastly you can query the active camera using a similar method:

userEntity:GetCamera()

If the default camera is selected, the Character entity will be returned. Otherwise a camera entity will be referenced.

It’s a simple and powerful mechanism that allows you to present dynamic views of your game world to the player.

Categories
Advanced Tutorials

Creating Voxel Meshes using Volume Select

Preface

Crayta provides a powerful voxel building system allowing you to create big and varied game worlds. You can quickly create your game level surfaces to start testing your gameplay and later go back and add cosmetic details easily.

In this tutorial we will explore how Volume Select, a Voxel tool available, works to edit and extract parts of a Voxel Mesh. Which you can later reuse in other parts of your Crayta world.

What is Volume Select?

When creating a new Crayta project you will find a single Voxel Mesh, in the form of a ground floor, already placed in the world for you. If you start drawing voxels on this surface, the voxels created will be automatically added to that original Voxel Mesh.

This stone door that we created is nice but what if our game requires moving it to a different location? Volume Select allows us to select a number of voxels from a Voxel Mesh to execute a number of methods on them:

Clicking Volume Select on the Voxel Tools toolbar allows us to create a selection volume in the 3D view to include our voxels. You can add a selection volume and further edit it using the gizmo to precisely select the required voxels.

Then you can execute one of the following methods:

  • Extract, creates a new Voxel Mesh from the selection containing the selected voxels. This will also have the voxels selected removed from the current Voxel Mesh.
  • Move, allows you to move the current voxels in the world, inside the current Voxel Mesh.
  • Duplicate, allows you to create a copy of the current voxels, inside the current Voxel Mesh.
  • Clear, will delete the selected voxels from the Voxel Mesh.

Let’s take a look at how each method works.

Moving Voxels

Using Volume Select to select a number of voxels and pressing Move will render the move gizmo at the center of the selected volume.

Using the gizmo you can move the voxels around and when finished pressing Apply on the toolbar will complete the action.

Duplicating Voxels

Duplicating Voxels is very similar to moving Voxels, with the only difference when finished moving the voxels around a new copy will be created.

Clearing Voxels

Clearing Voxels is even simpler: selecting Voxels with the Volume Select tool and pressing Clear will automatically remove those voxels from the Voxel Mesh.

Extracting Voxels

Extracting Voxels is a powerful tool that allows us to easily reuse voxels to enhance our game level.

When selecting Voxels using Volume Select and pressing Extract the output will be a new Voxel Mesh and Entity added to your project.

The new Voxel Mesh created will automatically be named based on the name of the original Voxel Mesh. A good practise is to remember to name the new extract to something sensible, helps a lot when starting having a lot of Voxel Meshes in the same level.

You can now easily reuse this new Voxel Mesh to make copies of the stone door in your level.

At any point you can merge back this new Voxels to a parent Voxel Mesh entity.

To do that move the Voxel Mesh entities, to be merged, as children to the parent Voxel Mesh entity. Right click on each entity and select Merge To Parent.

Each merged entity will be removed from the Entities Tree and the Voxels merged to the parent Voxel Mesh.

This is a powerful system to easily create levels and interesting worlds for your game.

Categories
Advanced Tutorials

Script variable scope

Preface

When building a game in Crayta you will often need to store information about the state of your game; game score, current level, number of enemies, etc are all examples of information you would store using variables. You may use these variables while coding your Lua scripts to build working blocks of code, much like you would in any other programming language.

While it is very easy to declare variables that hold supported Lua data, their scope will be different depending on how and where we declare said variable.

In this tutorial we explore the different scopes available for Lua variables in Crayta.

Variable scope is a subject of study and practice in any programming language. Something that the developer has to understand and use accordingly.

In Unity with C#, the scope of a variable or property is set using special keywords, public and private. These define if other script classes have access to variables or not.

In C# you can’t define global variables, since everything has to belong in classes.

Local Variables

In Lua there is a keyword used to declare variables with a local scope, named local. Local variables have their scope limited to the block where they are declared. A block is the body of a control structure, the body of a function, a for loop etc.

Here is an example to illustrate this:

function CollectableScript:Init()
  local name = self:GetEntity():GetName()

  if name == 'cottageChair' then
     -- works, variable name is available since it was declared in a parent scope
     local nameLowerCase = name:lower()

     -- works, variable nameLowerCase is available since it was declared in this scope
     Print(nameLowerCase)
  end

  -- doesn’t work, variable nameLowerCase not available in this scope
  Print(nameLowerCase)
end

Global Variables

Global variables in Lua do not need declarations. You simply assign a value to a global variable to create it. This variable is available in any scope of this script.

For example let’s test this code:

local CollectableScript = {}

function CollectableScript:Init()
    
  local name = self:GetEntity():GetName()

  if name == 'cottageChair' then
      myGlobalVar = 'aGlobalValue'
  end
End

function CollectableScript:OnInteract()
    Print(myGlobalVar)
end

If we assign this script to a number of entities, with one of them named cottageChair, then each time we interact with any of these entities we will get aGlobalValue printed in the console.

A global variable has the same value across all instances of the script.

Global variables have a greater performance impact compared to local variables, so as a preference local variables should be preferred. In addition global variables produce poor code architecture, breaking abstractions and object oriented paradigms, making maintaining a codebase difficult.

Self Variables

Crayta uses an object oriented approach in writing reusable code. Each Lua script contains the definition of a class-style type that can be reused (instantiated) by any number of entities that have a script component of this type attached.

The methods declared in this script will run on a different context each time. That of the entity the script is attached to.

For this reason it is quite useful to be able to declare variables that can be used by any method of the same script, but not between script instances.

Crayta makes available in any script a special variable named self. We can use the dot notation to declare variables that are available on a specific script instance this way.

Let’s rewrite the previous example to accomplish a different task using self.

local CollectableScript = {}

function CollectableScript:Init()
    
  local name = self:GetEntity():GetName()
  self.nameLowerCase = name:lower()

end

function CollectableScript:OnInteract()
    
    Print(self.nameLowerCase)
end

Now if we attach our script to a number of entities, whenever we interact with one of them we will get their name printed in lowercase to the console.

Using self.nameLowerCase we make sure that we declare a new variable unique to each script instance executing.

Accessing from other scripts

Local and global variables are accessible only within the same script. On the other hand variables defined using self can be easily accessed by other scripts. Variables in Lua can hold not only data values but also references to functions.

This is powerful and allows you to easily extend your code to read data and methods found in other scripts.

Here is an example of how we can access the nameLowerCase variable from another script:

local AnotherScript= {}

AnotherScript.Properties = {
      { name = "collectable", type = "entity"}
}

function AnotherScript:MyMethod()
    
    Print( collectable.collectableScript.nameLowerCase )
end

We can access the script instance of a script with its name, on any entity that has it attached. Any variables or methods declared on self are available now using the same notation.

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);
}
Categories
Advanced Tutorials

Packages, migrating level components from one game to another

Preface

Unless you are developing a very small and basic game, you will quite often reach a point of complexity in your game’s setup that requires a shift in the way you build it. The ability to split your game in smaller pieces or components, that can be developed and tested separately can help a lot with reducing that complexity. Crayta provides a powerful feature that allows you to do this, called packages.

In this tutorial we will explore how we can use packages to migrate components from our game, like voxels and templates, to another game.

In Unity there is a similar tool that implements this concept of packaging parts of your game to be used in another scene or game altogether, called Packages as well.

You are able to create Packages that contain models, textures, prefabs etc, export them and import them in another project.

Unity provides an Asset Store where users can publicly share packages.

Packages

In Crayta, at any point, you are able to create new packages that contain any number of valid assets. Assets that can be included in the package are:

  • Voxel Meshes
  • Scripts
  • Widgets
  • Templates
  • Worlds
  • Other packages (can be referenced as dependencies)

Core Crayta assets like Meshes or Sounds can’t be added in a package directly, although they can be part of a Template or World asset which can be added.

All new packages created are made available to all of your Crayta projects via the Library. When you are creating a new package you can make it public which in turn will make the package available not only to your projects but to all user created projects.

Packages Library

In Advanced Mode under the Library tab you can see a list of all the packages available to your project. Those include packages that have been installed from the Crayta library and those created in this project.

From here you can explore the contents of each package, review it, add it to your favourites and also update a package to its latest, if available, version.

Creating a Package

Clicking Create New Package will open the relevant window to start creating a new package.

There are several fields available here to provide a name, description, optional tags etc. for the package with the most important field being the Assets drag and drop zone. There you can drag and drop any valid asset from the Library window to be included in the new package.

You can add as many assets as you like this way in the package, and they will all be listed in the Assets list.

You can also drag and drop other packages to the Package dependencies field to be included here and Crayta will automatically add them as a dependency. This means when you are importing this package to another project, Crayta will make sure to download and install any other package required as a dependency.

Hitting Create will finish the creation process and make this package available in Crayta’s Library.

Importing a Package

The Crayta Community tab will list your newly created package allowing you to download and install it to any other project.

By doing so the contents of the package will be made available in the project’s Library. A special icon indicates that this asset is part of an installed package.

You can now use this asset much like any other asset included in your project.

That way packages become a powerful tool to share components between games.

You can use this feature to split the development of your game in components that can be easily developed and tested separately and when ready incorporated back to the original game.

You can also have templates used in one game migrated and reused in another game. 

Crayta users can make their packages public and share them with other users building games.

Updating a Package

At any point you can edit any of your packages to push changes to existing assets or add new ones.

To edit a package you start by locating it in the Packages library window and clicking edit.

This will bring up a window similar to the package creation window, in which you may use a similar method to edit the package.

When finished, clicking Update will update the published the package with any changes you have made. Any projects using this package will show an active Download button which users may then click on to download the newest version of this package.

By clicking this button the latest version of the package will get downloaded and the included assets will be updated.

Categories
Advanced Tutorials

Voxel meshes and templates, when to use each

Preface

Crayta provides several tools to help you build large and interesting worlds for your games.

One of the most powerful features provided is the ability to use voxels in various sizes and materials for terrain, structures, objects, etc. At the same time Crayta allows you to organize parts of your scene as reusable components called templates. Templates can be easily duplicated multiple times, and any changes made to the original will automatically propagate to all instances.

In this tutorial we will explore how to use voxel meshes and templates and when to use each.

In Unity doing world building involves using polygon assets called meshes/models that get placed in the scene to assemble a world. Quite often a terrain surface is used in addition, painted using a number of brushes to help you create realistic worlds. 

There isn’t any notion of voxel building in Unity so usually a large number of assets have to be prepared in advance for all parts of the scene to be put together in the Unity editor. The only thing that might resemble Crayta voxel building is the ProBuilder Unity extension that can do part of the scene polygon modelling inside the Unity editor.

Crayta templates on the other hand are very much like Unity prefabs.

Voxel Mesh

Voxel building in Crayta involves adding and editing voxel meshes. Voxel meshes are groups of voxels that contain from a handful (e.g. a simple rock) to millions of voxels (e.g. a complex structure).

When creating a new project a voxel mesh is automatically added, containing a simple terrain surface to start building on.

The voxel mesh is saved to a voxel mesh asset, that can be found in the Library under the Voxel Meshes category. You can create multiple voxel meshes from a single voxel mesh asset simply by dragging and dropping it in your world:

Editing any of these terrain surfaces using the voxel tools will result in changes rendering in all terrain surfaces. This initially can be confusing, the reason is simply because all the terrain surfaces reference the same voxel mesh asset. So any change to that voxel mesh asset is being saved to that asset and in turn updates all voxel meshes referencing that asset.

You can change that behaviour for any voxel mesh by clicking the Create a unique copy of this asset button in the voxel mesh entity properties. That will create a new voxel mesh asset from this voxel mesh and assign it to it. From there and on any change on this voxel mesh will update the new voxel mesh asset created.

From the Library -> Voxel Meshes window you can also create new voxel mesh assets to be used to spawn voxel meshes in the world.

Template

Templates in Crayta is a powerful system that allows you to create reusable groups of entities that can be easily spawned anywhere in your world. At the same time retaining a link to the original template allowing you to make changes at any point to your template and have the changes propagate automatically to all the template instances.

A template can contain any kind of entities and components. You can use it for several things:

  • Collectables
  • Repeating structures
  • User template
  • Player templates
  • Effects etc.

You can easily create a new template by using an entity that already exists in your world. Select it and then click Template -> Create New Template…

This will create a new Template with this entity at the root of the template. From there you can easily add children entities, components etc.

You may spawn instances of a template by using the Library → Templates window and drag/drop your selected templates into the world. Spawned entities will show the full hierarchy of the template in the World Tree editor window and will contain a toolbar with the following template actions:

  • Edit template, will open this template for editing.
  • Copy to template, any changes made to this instance with this button will be saved back to the template and propagate to all template instances.
  • Break template link, this will severe the connection to the template and make this entity a normal World entity. You can do further changes to the entity without having the template override anything.

Voxel Meshes and Templates

Voxel meshes should be used when doing world building and you require parts of your world to be reused. Parts that don’t require any special functionality like scripting or lighting etc.

When those parts require additional components to be added and spawned on each instance a template should be used. Voxel meshes can be added to template entities much like any other component (script, sound, effect etc).

The only thing requiring special attention regarding voxel meshes in templates is the use of the Break template link button. This will break the link to the template, allowing the entity to be edited further without affecting the template. This holds true for all changes except editing voxel meshes attached to this entity or to its children.

This happens because, as we stated above, voxel meshes always reference voxel mesh assets. Breaking the link to a template will keep a reference to the same voxel mesh asset used by the template. So editing the voxel mesh on an entity that has broken the template link will have the, potentially undesirable, effect of editing the voxel mesh asset referenced by the voxel meshes in the template instances.

To stop this behavior, the solution is simple using the Create a unique copy of this asset button on those voxel meshes to create new voxel mesh assets that aren’t referenced by this template.

Categories
Advanced Tutorials

The relationship between Player and User

Preface

One of the most common concepts found in video games is that of a user controlled avatar. The player takes control of an avatar, which can be anything depending on the theme of the game (a human, a vehicle, an exotic spaceship) to navigate and interact with the game world.

In this tutorial we will explore how this concept is applied in Crayta and how to set it up in your game.

When getting on board Crayta one of the first things you are asked to do is to setup your Avatar using a range of controls to customize the body, hair, clothing etc.

Crayta games revolve around players that control human avatars. Crayta provides a camera system, player collisions, interaction etc, making it very easy to create first or third person games.

In Unity there isn’t a similar thing out of the box, the closest thing you could do is use the default first or third person controller script to start building a similar functionality.

User

A User is a type of entity which references the account of a person connected to the game. When you connect to a Crayta game a User entity will be spawned from the available User template and assigned to you.

All Crayta games are required to have a User template available. Only a single one is needed, since there isn’t any way to choose or set the active User template. Crayta will automatically detect and use it.

A default User template is provided in all new projects created which can be used to attach scripts and widgets.

Player

The User entity doesn’t have any physical representation in the game World, so you can’t see or interact with other connected Users.

When a new user is connected to the game and a User entity is spawned. Crayta will also attempt to spawn a Character entity from a Player template, unless a OnUserLogin method  has been added to a script. If that is the case then Crayta will not spawn a Player template and it is up to your game logic to handle this.

All player templates are required to have a root Character entity (other entity types may become available in the future).

Spawning a character entity will cause the game to render the user’s avatar and add a default camera.

A default Player template is added in all new projects created.

In contrast with the User template, a Player template exposes a list of properties allowing you to customize a number of settings like the jump height or running speed of the Player.

User/Player relationship

Each user connected to the game has at any instant a User entity spawned and referenced to his account and also a Player (Character) entity spawned and active in the game World.

Both entities are spawned from the User and Player templates available in the game. A game can have a single User template but can have multiple Player templates.

The User entity provides you with a method to change the active Player template that is used by each player:

This is quite powerful since it allows you to easily change the behavior of your game depending on the game state. For example you can have one Player template for the lobby area with an Orbit camera and players not being able to jump, a first person Player template for the main game action time and another one for players spectating and not actively playing.

Here is an example of how to change the Player template from a script attached to a User entity:

local MyUserScript = {}

MyUserScript.Properties = {
    { name = "playerTemplate", type = "template"}
}

function MyUserScript:ChangePlayerTemplate()

    self:GetEntity():SpawnPlayer(self.properties.playerTemplate)

end

And here is an example of getting a reference to the active Player (Character) from a script attached to a User entity:

function MyUserScript:GetActivePlayer()

   return self:GetEntity():GetPlayer()

end

And a more advanced case: getting a reference to the Player entity of all connected users from any script running on the server:

GetWorld():ForEachUser(
   function(userEntity)
       local username = userEntity:GetUsername()
       local player = userEntity:GetPlayer()
       -- do something with the player 
       -- e.g. access script methods or player properties
   end
)

You can easily add more Player (Character) templates to your game using the Primitives window.

Categories
Advanced Tutorials

Introduction to Widgets, building a game UI

Preface

Almost every game requires, in one form or the other, some sort of user interface (UI). For that reason most of the game engines or game creation systems go to great lengths in providing a robust UI solution to the developer.

In Crayta you can use a well established tech stack to build the UI for your game: HTML/CSS and Javascript. If you are coming from a web dev background you will feel right at home. If not, in this tutorial we will attempt to provide simple steps to get you started.

If you are coming from Unity to Crayta and you have been using the Unity User Interface (Unity UI), initially you might find it difficult to adapt to the Crayta UI.

At the moment, there isn’t a visual editor to allow you to place elements visually, adjust the position, the properties etc. All Crayta UI elements are HTML elements that are styled using CSS and logic is added using Javascript.

You can find a plethora of resources online to help you get started with HTML, CSS and Javascript.

If you’ve used the new UIElements in Unity you will feel much more comfortable.

Widgets

All interface related code is being stored in a special asset named Widget which can be attached to entities. You add widgets to your entities in the same way that you add scripts.

There are three types of widgets that can render an interface:

  1. Screen: the UI will be rendered as a HUD on screen.
  2. World: the UI will be rendered as a texture in the 3D world on a 3D plane.
  3. World – Camera Facing: the UI will be rendered as a texture in the 3D world, as a camera facing 3D plane.

The type of a widget can be set using the type property.

The Widget references an asset in its html property that contains the HTML code used for rendering it, plus inline CSS and inline Javascript.

What is HTML?

HTML is a markup language used to render web pages that has been used since the very first websites went public on the internet. Over time it has evolved to be able to handle 2D and 3D styles and also include complex logic using Javascript.

<!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>

<p>My first paragraph.</p>

</body>
</html>

What is CSS?

The tags (e.g. <p></p>) used to define the HTML markup structure have a basic styling of their own. To extend or change that styling with your own, a special language was created called CSS (Cascading Style Sheets).

This language provides you with a number of rules that extend the styling of any HTML element. Here is an example of inline (meaning in the same file) CSS:

<html>
  <head>
    <title>Playing with Inline Styles</title>
      <style>
         p{
            margin-left: 20px;
         }
      </style>
  </head>
  <body>
    <p style="color:blue;font-size:46px;">
      I'm a big, blue, <strong>strong</strong> paragraph
    </p>
  </body>
</html>

CSS can be added directly to any element using the style attribute or using a special HTML element <style>.

What is Javascript?

Javascript, a turing complete language, is used for adding logic and interactivity to web pages and even to write complex web applications.

Crayta includes the V8 Javascript engine which is the same Javascript compiler used by Chrome and other applications. This means that you are able to run and execute any kind of Javascript code in Crayta.

Crayta exposes a clean API that can be used to communicate data back and forth to your Lua scripts in your Javascript code.

    <body>
       <p style="color:blue;font-size:46px;">
           I'm a big, blue, <strong>strong</strong> paragraph
       </p>

        <script>
            engine.createJSModel('data',
            {
                bgColor: "rgb(20, 200, 100)",
                
                title: "Sign Title",
                titleSize: 20,
                titleColor: "rgb(255, 255, 255)",
                
                message: "Sign Message",
                messageSize: 10,
                messageColor: "rgb(20, 20, 20)",
            });
        </script>
    </body>

To write Javascript in HTML you can use the special HTML element <script>, in the <head> and/or <body> elements.

It’s common practice to write your Javascript code at the end of your <body> element, since this allows you to access any other HTML elements in the script.

Building a simple UI

A lot of the Crayta provided packages come with one or more widgets to draw a UI. You can use them to start learning how to build a UI of your own or as a starting point for your game UI.

But to better understand how widgets work in Crayta, we will explore how we can get started building a UI from scratch.

A simple game

Let’s take a moment and create a simple game and use it as the base for our interface.

  • You can create a new blank project or work on your existing one. 
  • Place a number of random Mesh entities around the world.
  • Create a new script called collectableScript and attach it to all the entities you’ve placed.
  • Add the following code to the script:
local CollectableScript = {}

function CollectableScript:OnCollision()
    self:GetEntity():Destroy()
end

return CollectableScript

If you go and play the game now, as soon as the Player collides with an object it will be removed from the world, like a collectible.

Now that’s not so much fun since the Player can’t see which items they’ve picked up. Our interface to the rescue!

Adding a widget

  • Select the UI Widgets category from your Library, and create a new asset named myInterfaceWidget

You can have all of your interface in a single widget, or split it up into smaller widgets that can act as parts or components of your interface. The latter approach is particularly beneficial If you have a complex interface or plan on reusing parts of it in other games in the long term.

For our tutorial project we will be using a single widget. Crayta will automatically fill the widget html file with boilerplate code that includes placeholders for CSS, HTML and basic Javascript methods required to communicate with your Lua scripts.

  • Attach this widget to your Player template.

Running the game will result in this:

Let’s prepare the widget to host our interface code.

  • Remove all existing CSS code from your <style> element.
        <style type="text/css">
            /* YOUR CSS CODE HERE */
        </style>
  • Remove all html code from your <body> element, and Javascript from the script element.
    <body>
        <!-- YOUR HTML CODE HERE -->

        <script>
            /* YOUR JAVASCRIPT CODE HERE */
        </script>
    </body>

Let’s add a simple list that will serve as a container for all the collectables the Player gathers.

  • Add the following HTML code where you’ve removed the boilerplate one (at the top of the body section and under the <!– YOUR HTML CODE HERE –> comment).
        <div class="my-items-container">
            <h1>My items</h1>
            <div class="my-items-list">
                <div class="my-item">
                    <span>1</span>
                    <p>Item Collected</p>
                </div>
            </div>
        </div>
  • Add some CSS to make it look pretty inside the style element, under the /* YOUR CSS CODE HERE */ comment:
    .my-items-container {
        width: 30vh;
        margin: 10px;
        padding: 10px;
        border-radius: 7px;
        background-color: rgba(255,255,255,0.5);
    }
    
    .my-items-container h1{
        text-align: center;
        text-shadow: 0px 0px 5px white;
    }

    .my-items-list {
        color: #ccc;
        list-style-type: none;
    }
    
    .my-item{
        position: relative;
        font: bold italic 70px/1.5 sans-serif;
        margin-bottom: 20px;
    }
    
    .my-item p {
        font: 20px/1.5 sans-serif;
        padding-left: 60px;
        color: #555;
    }
    
    .my-item span {
        position: absolute;
        color: darkcyan;
    }

Running the game at this point:

Although it is a nice list, right now it is just a graphic. Let’s add some logic to the interface.

Adding logic

Our goal for this list is to list any collectable the player picks up. For that we need a Lua script on the Player template that keeps tracks of the items collected.

  • Add a script to the Player template called myCollectablesScript.
  • And add the following code to it:
local MyCollectablesScript = {}

function MyCollectablesScript:Collected(collectableName)
    
    self:GetEntity().myInterfaceWidget.js:CallFunction("collected", collectableName)
end

return MyCollectablesScript

This code is the starting point of establishing communication between our Lua scripts and the Widget.

MyCollectablesScript:Collected is a custom method that we will be calling each time the Player has picked up a collectable. Let’s implement that now.

  • Add the following code to the collectableScript.
local CollectableScript = {}

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

function CollectableScript:OnCollision(collidingPlayerOrEntity)
    
    if self.collected == true then return end
    self.collected = true
    
    -- destroy the collectable
    self:GetEntity():Destroy()
    
    -- inform the Player/UI of the item collected
    if collidingPlayerOrEntity:IsA(Character) then
        collidingPlayerOrEntity:SendToLocal('Collected', self:GetEntity():GetName())    
    end
    
end

return CollectableScript

Using SendToLocal on the Player entity is an easy way to communicate from the server to the local Player the item that this Player has collected.

  • Add the following Javascript code to the widget, replacing the current code.
      <script>
        /* YOUR JAVASCRIPT CODE HERE */

        engine.createJSModel('itemsModel',
        {
            items: []
        });

        engine.on("collected", function(collectableName) {
            itemsModel.items.push({
                index: itemsModel.items.length + 1,
                name: collectableName
            });
            engine.updateWholeModel(itemsModel);
            engine.synchronizeModels();
        });

    </script>

This Javascript code does two things:

  1. Creates a new model that contains an array property used to hold all of the collected items.
  2. Registers an event handler, that is a function that can be called from Lua code and can also accept arguments.

As soon as the Player picks up a collectable the widget will get notified, and the items array will get populated.

Dynamically updating the UI

Let’s explore how the interface can automatically get updated as the items are collected.

Crayta uses the Coherent Gameface UI library which allows you to add data bindings to any HTML element. This is powerful for the elements which can get updated/added/removed automatically reflecting your data.

  • Update the HTML code in the widget adding data attributes.
        <div class="my-items-container">
            <h1>My items</h1>
            <div class="my-items-list">
                <div data-bind-for="item:{{itemsModel.items}}"              class="my-item">
                    <span data-bind-value="{{item}}.index"></span>
                    <p data-bind-value="{{item}}.name"></p>
                </div>
            </div>
        </div>

There are a number of data-bind attributes available to use in your HTML code. Some common ones are:

  • data-bind-for: can be attached to an array and automatically clone this HTML element, together with its children, for each array item.
  • data-bind-if: can do conditionals to check and show/hide an HTML element based on that condition.
  • data-bind-value: automatically update the innerHTML value of any element with the value attached.

Now this HTML code will automatically reflect any changes to the itemsModel object.

Every item collected by the Player will now appear on the Interface.

Code

Here is the complete widget script:

<html>
    <head>
        <!-- Required includes -->
        <script type="text/javascript" src="coui://uiresources/js/crayta.js"></script>

        <style type="text/css">
            /* YOUR CSS CODE HERE */
            .my-items-container {
              width: 30vh;
              margin: 10px;
              padding: 10px;
              border-radius: 7px;
              background-color: rgba(255,255,255,0.5);
            }
            
            .my-items-container h1{
                text-align: center;
                text-shadow: 0px 0px 5px white;
            }

            .my-items-list {
              color: #ccc;
              list-style-type: none;
            }
            
            .my-item{
              position: relative;
              font: bold italic 70px/1.5 sans-serif;
              margin-bottom: 20px;
            }
            
            .my-item p {
              font: 20px/1.5 sans-serif;
              padding-left: 60px;
              color: #555;
            }
            
            .my-item span {
              position: absolute;
              color: darkcyan;
            }
        </style>
    </head>

    <body>
        <!-- YOUR HTML CODE HERE -->
        <div class="my-items-container">
            <h1>My items</h1>
            <div class="my-items-list">
                <div data-bind-for="item:{{itemsModel.items}}" class="my-item">
                    <span data-bind-value="{{item}}.index"></span>
                    <p data-bind-value="{{item}}.name"></p>
                </div>
            </div>
        </div>

        <script>
            /* YOUR JAVASCRIPT CODE HERE */

            engine.createJSModel('itemsModel',
            {
                items: []
            });

            engine.on("collected", function(collectableName) {
                itemsModel.items.push({
                    index: itemsModel.items.length + 1,
                    name: collectableName
                });
                engine.updateWholeModel(itemsModel);
                engine.synchronizeModels();
            });

        </script>
    </body>
</html>

Useful links

Coherent Gameface reference docs:

Categories
Advanced Tutorials

Client/Server relationship and how they communicate

Preface

Crayta takes a unique approach to how you develop multiplayer games, something that usually requires solving difficult programming problems and acquiring special infrastructure for your server. Instead of having the server and the client running separately, trying to synchronize the game instances, in Crayta everything runs in the cloud, both the server and the client, and even the development environment itself.

By default all game logic that you write in Crayta runs in the server and the engine takes care of replicating all movement, entity updates, collisions and physics etc. to the connected clients. When explicit client logic is required, for example to update something on the HUD like a health bar, any script can easily include that and communicate updates to the code running on the server.

In this tutorial we will explore how to handle the Server/Client relationship in your code and how to communicate between the two.

You will not easily find something similar to Crayta in other game engines, where everything requires a rigorous architecture to handle the synchronization between the server and the client.

Crayta will take care of most of the hardest parts of making a multiplayer game, leaving you to concentrate on creating the gaming experience.

Where is my code executing?

Crayta makes it very easy to start building a world, adding objects and effects and from the very first moment have your friends connect and play together. When adding code to your game, to enable custom behavior and logic, at first it might be confusing where the code is executing and in what order.

Crayta doesn’t require you to write your server and client logic separately. In the same script you can have server code and client code, that can share and reuse methods.

So how do we decide where our code should execute? In Crayta there are a number of functions that are called entry points and can execute code in one of the following contexts:

  • Server
  • All clients
  • Local client only

Let’s take the Init method and its variations to see how it is used there to get a better understanding of how networking works in Crayta.

After the game world and all of its entities have been created on the server the Init method will be called in any script using it. It will execute the code in the server and all state updates happening to entities, as a result of the code running, will be replicated to all connected clients. This method is useful when executing gameplay sensitive code that aims to have the same result executed to all connected clients.

After all entities, that have been created, arrived to each connected client, separately, the ClientInit method will be called. This will execute the code to each connected client but not in a synchronous manner since the entities will arrive to each client at a different time. This is useful when code has to run to all connected clients, but it doesn’t have a crucial effect on the gameplay when not in sync. For example powerups spinning or particles effects animating. This method is valid and can be used in any entity, except the User and Player entities and their children.

On the Player or User, the LocalInit method can be used. It is called immediately after the ClientInit and it executes only to the local client. It can be used to update things like the HUD that are visible only to the local client.

How to handle communication?

Code executing to the server or the client only isn’t always useful, quite often you will have to send a message from the server to the clients or the other way around. Crayta provides an easy to use API to help you with that.

SendToAllClients

This method can be used in the server, in any script, to communicate with all connected clients:

entity:SendToAllClients(string eventName, ... args)

When called you have to pass the eventName, that is a string of the name of the function that will be executed. It will find and call this function on all scripts of this Entity on all connected clients.

Optionally you can pass any number of arguments that will be made available to the function when executed.

SendToLocal

This method can be used in the server to communicate with the local client only:

entity:SendToLocal(string eventName, ... args)

As with the previous method, the name of the function to be executed is passed as the first argument. This function will be called on all scripts of this Entity on the local client that owns the Player or User this script is attached to.

A number of arguments can be passed to be made available to the function when executed.
This method is useful to communicate changes required only by the local client, like HUD updates.

SendToServer

This method can be used in the client to communicate with the server:

entity:SendToServer(string eventName, ... args)

It will call eventName on all scripts attached to this Entity on the server, together with any arguments given.

IsLocal / IsClient

There are two helper methods that can be used in any script to check if the code executing is running on the server or in the client.

bool entity:IsClient()

This method will check if this Entity is on the client.

bool entity:IsLocal()

This method will check if this Entity is owned by the local client, that means it is the User or Player entity, or it is child to these entities.

Script Properties

Another way to easily communicate changes between the server and client is the property bag. All properties defined in a script automatically replicate to the clients and can therefore be used to transmit state and data without the need to use the Send methods.

The advantage of doing that is that new players will automatically get the latest state of a script, rather than having to catch up on their OnUserLogin and send it manually.

Categories
Advanced Tutorials

Coroutines in Crayta. Using Schedules and OnTick

Preface

In game development it is a common requirement to be able to schedule the execution of your code. Normally when you call a function the code will run from start to end and return in a single frame. There are cases where something has to happen over a sequence of frames or after a scheduled delay. Example cases:

  • Pause the code execution for a specified amount of time.
  • Change to the next level 3 seconds after the user has reached the finish line.
  • Calculate something complex over a number of frames that would normally make the game hang.

In this tutorial we will learn how to use Schedules and the special OnTick method to execute our code at an appropriate time.

In Unity a similar concept exists called Coroutines, allowing you to schedule the execution of your code.

The Coroutine class in Unity is similar to the Crayta Schedule method. They can both pause and resume their operation, where they left off, on the following or on a coming frame. A Unity Coroutine runs in the same thread, in a similar manner in Crayta the Schedule method will execute in sequence with the main thread.

How to use Schedules?

Here is a simple example on how to use a Schedule in Crayta:

function MyScript:OnInteract()
   self:Schedule( function()
        Wait(1.0)
        Print("Interact was pressed a second ago...")

        Wait(1.0)
        Print("Interact was pressed two seconds ago...")

        Wait(1.0)            
        Print("Interact was pressed three seconds ago...")
   end)
end

This method will print a couple of messages in the console but instead of printing them at the same time, it will print them with a second difference one from the other.

Schedule is a method available in the ScriptComponent class, meaning that it is available to be used in any Crayta script.

Wait

In the example above we used the Wait() method which is available to be used inside the callback function that is executed by the Schedule. As the name implies this method forces the code execution to pause and resume at a later point.

There are two ways to use this method:

  1. Wait( duration ) where duration is the time in seconds to pause in minimum before resuming the execution.
  2. Wait() pause the execution for a single frame and then resume in the next frame.

Both methods return the exact time in seconds taken from the pause instant till the method resumed. That is useful to implement non-linear smooth animations.

The code below will animate an entity moving periodically up and down when placed in an :OnTick(dt) function:

local angle = 0
while true do
    local dt = Wait()
    angle = angle + dt
    local position = Vector.New(0, 0, 100 * math.sin(angle))
    self:GetEntity():SetPosition(position)
end

IsInSchedule

There is also another method available to be used inside Schedule, IsInSchedule(). As the name suggests this will return true or false, depending if the code executing is running in a schedule or not. This is quite useful if you are calling methods in a schedule that you also call, with a different behavior, in other parts of your script.

Cancel

If required you can easily cancel any schedule by calling the Cancel() method in the parent script. When you call the Schedule() method a handler is returned which can be stored in a variable or script property for later use.

That handle can be used at any point by passing it in the Cancel( handler ) method to stop immediately the execution of that schedule.

function MyScript:Init()
   self.mySchedule = self:Schedule( function()
       -- animating the current entity
   end)
end

function MyScript:OnInteract()
   -- this will stop the animation as soon as the player interacts with it
   self:Cancel(self.mySchedule)
end

How to use OnTick?

OnTick is a method available in all scripts, that is updated automatically by Crayta on each frame. The deltaTime is in seconds, which is the time elapsed since the last frame was rendered, and is made available as an argument to be used by the executing code (e.g. to make smooth animations).

Here is an example using OnTick to infinitely rotate an entity around its Z axis, which is useful for items such as powerups:

function PowerupProp:ClientInit(dt)
    Self.rotation = Rotation.New(0,0,0)
end

function PowerupProp:ClientOnTick(dt)

    self.rotation.yaw = self.rotation.yaw + dt * self.properties.rotationSpeed

    self:GetEntity():SetRotation(self.rotation)
end

You will notice that instead of using OnTick(), we used a variation of it called ClientOnTick(). Much like the Init function the OnTick comes with the same three variants depending on the context it is used in:

  • OnTick (executed in the server)
  • ClientOnTick (executed in all clients)
  • LocalOnTick (executed in the local client)

Usually for objects that require cosmetic animations, when the movement of the entity doesn’t affect the gameplay, it is better to do it on each client separately, using ClientOnTick().

For animating something specific to a certain player, that is not required to be in sync or even visible to other players, LocalOnTick() can be used, but only on scripts attached to a User or Player template. That makes it useful for doing stuff in a Player’s HUD, but can’t be used to rotate a collectable.

When something should be synchronized across all connected players, OnTick() should be used.

Schedules vs OnTick

Both methods do something similar, execute code across several frames. So when to use each?

Schedules are more versatile. You have control over how often the code will execute, you can get the deltaTime elapsed and even stop the execution at any point. Also Schedules can be started at any point in your script code, so all contexts are supported in Schedules, too (Server, Client, Local).

Schedules ultimately can be configured to have the same behaviour as the OnTick method (using a while loop and a Wait).

OnTick is automatically called by Crayta, providing the deltaTime elapsed and it should be used when something should be executed per frame. For code that pauses or works occasionally Schedules can be a better alternative from a performance point of view.

Schedules are better used when you require exact control of when your code is executed. Also when you have to do something complex that would normally cause the the game to hang for a while. Putting that code in a Schedule and spreading calculations across a number of frame, can keep the frame rate constant.