Tutorial 3: Scripts and Behaviours

Last tutorial we covered rendering meshes. In this tutorial we will be seeing how to make 2 GameObjects interact with each other.

Behaviours

A Behaviour is a Component that you can create yourself. To create a Behaviour, subclass from it:

>>> class MyBehaviour(Behaviour):
...     pass

In this case the Behaviour does nothing. To make it do something, use the Update function:

>>> class Rotator(Behaviour):
...     def Update(self, dt):
...         self.transform.localEulerAngles += Vector3(0, 90, 0) * dt

What this does is it rotates the GameObject that the Behaviour is on by 90 degrees each second around the y-axis. The Update function takes 1 argument, dt, which is how many seconds have passed since the last frame.

Behaviours vs Components

Look at the code for the Component class:

class Component:
    def __init__(self):
        self.gameObject = None
        self.transform = None

    def GetComponent(self, component):
        return self.gameObject.GetComponent(component)

    def AddComponent(self, component):
        return self.gameObject.AddComponent(component)

A Component has 2 attributes: gameObject and transform. This is set whenever the Component is added to a GameObject. A Behaviour is subclassed from a Component and so has the same attributes. Each frame, the Scene will call the Update function on all Behaviours, passing the time since the last frame in seconds.

When you want to do something at the start of the Scene, use the Start function. That will be called right at the start of the scene, when scene.Run() is called.

>>> class MyBehaviour(Behaviour):
...     def Start(self):
...         self.a = 0
...     def Update(self, dt):
...         print(self.a)
...         self.a += dt

The example above will print in seconds how long it had been since the start of the Scene. Note that the order in which all Behaviours’ Start functions will be the orders of the GameObjects.

With this, you can create all sorts of Components, and because Behaviour is subclassed from Component, you can add a Behaviour to a GameObject with AddComponent.

Examples

This creates a spinning cube:

>>> class Rotator(Behaviour):
...     def Update(self, dt):
...         self.transform.localEulerAngles += Vector3(0, 90, 135) * dt
...
>>> scene = SceneManager.AddScene("Scene")
>>> cube = GameObject("Cube")
>>> renderer = cube.AddComponent(MeshRenderer)
>>> renderer.mesh = Mesh.cube(2)
>>> renderer.mat = Material(Color(255, 0, 0))
>>> cube.AddComponent(Rotator)
>>> scene.Add(cube)
>>> scene.Run()

This is a debugging Behaviour, which prints out the change in position, rotation and scale each 10 frames:

class Debugger(Behaviour):
    lastPos = Vector3.zero()
    lastRot = Quaternion.identity()
    lastScl = Vector3.one()
    a = 0
    def Update(self, dt):
        self.a += 1
        if self.a == 10:
            print(self.transform.position - self.lastPos)
            print(self.transform.rotation.conjugate * self.lastRot)
            print(self.transform.scale / self.lastScl)
            self.a = 0

Note that the printed output for non-moving things would be as so:

Vector3(0, 0, 0)
Quaternion(1, 0, 0, 0)
Vector3(1, 1, 1)
Vector3(0, 0, 0)
Quaternion(1, 0, 0, 0)
Vector3(1, 1, 1)
Vector3(0, 0, 0)
Quaternion(1, 0, 0, 0)
Vector3(1, 1, 1)
...

This means no rotation, position or scale change. It will break when you set the scale to Vector3(0, 0, 0).

In the next tutorial we’ll be looking at physics.