Tutorial: Behavior

This tutorial tells you how to use Behaviors in Quorum

What is a Behavior?

A Behavior is a critical GUI component that allows items in the user interface to conduct actions or even respond to user interaction. Most of the classes that use Behaviors are user interface controls, such as Buttons and TextBoxes, which will be covered in the following tutorials. Together, these classes provide a way to efficiently route user input throughout the system.

This is what the Behavior class in Quorum looks like:

package Libraries.Interface.Behaviors
use Libraries.Interface.Events.BehaviorEvent

class Behavior
    action Run(BehaviorEvent event)
    end

    action Update(number seconds)
    end

    action Dispose
    end

    action IsFinished returns boolean
        return false
    end
end

On the surface, you will see that the Behavior class does not do anything itself. This is because it is heavily subclassed for specific actions. For more information on inheritance and overriding actions, see the tutorial on Inheritance.

Lets run through the four actions in a Behavior:

  1. Run - Run is called when an action is taken with the Behavior. For example, if a Button is clicked in the user interface, then Run would be called.
  2. Update - A Behavior can also be set to Update on every frame of a running program. However, not all Behaviors do this. For example, when a Behavior is set to a Button via SetBehavior, Update is never called, while the Run action is called when the Button is pressed. In contrast, if the AddBehavior action is called on an item, Update will be called every frame. We will go over the specifics of each GUI element in their respective tutorials, so don't worry about this difference for now.
  3. Dispose - This action does nothing by default, but it can be overridden for cleanup actions when the Behavior is finished. Note that, like the Update action, Dispose is only called if the Behavior is added through AddBehavior, not if it is set as a default Behavior using SetBehavior.
  4. IsFinished - This action returns a boolean, which states if the Behavior has completed its work.

For this tutorial, we will first create a simple Behavior that outputs and says text. To start, create a new Game Application project.

Note: We will use the Drawable and Speech classes in this tutorial. For more information on using Drawables, check out the tutorial on Drawing in 2D, and for more information on Speech, see the documentation on the Speech class.

Outputting with a Behavior

To create our own Behavior, we will create a new Quorum Class, which we will name "OutputBehavior.quorum." This class will use the libraries for Behavior, BehaviorEvent, and Speech. The class itself will override the Behavior's Run action to output and say the desired text. This gives the following OutputBehavior class:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Sound.Speech

class OutputBehavior is Behavior
    action Run(BehaviorEvent event)
        Speech speech
        speech:Say("Hello world!", false)
        output "Hello world!"
    end
end

We now have our completed OutputBehavior class, but nothing will happen yet because it has to be added to an object for the Behavior to run. To do so, we will make a Drawable and use it so our Behavior can run. Return to the main class and in the CreateGame action we will make a Drawable and add our Behavior to it.

The complete main class will be as follows:

use Libraries.Game.Game
use Libraries.Game.Graphics.Drawable

class Main is Game
    action Main
        StartGame()
    end

    action CreateGame
        Drawable box
        OutputBehavior behavior
        box:AddBehavior(behavior)
    end
end

If we run the program now, nothing will be in the game window, but "Hello World!" will output to the console and you will hear the program say "Hello World."

This was a simple Behavior that only needed to override the Run action, but most Behaviors will perform more complex actions and may need to override all 4 of a Behavior's actions. For a deeper look into Behaviors, in the next section of this tutorial we will rotate a drawable for 5 seconds and change its color using Behaviors.

Rotation with a Behavior

Creating a New Behavior

To begin, we will create a new Quorum class, which we will name "RotationBehavior.quorum." In addition to the Behavior and BehaviorEvent libraries needed to make a Behavior, we will be using the Color, Drawable, and Speech libraries.

The RotationBehavior class will inherit the Behavior class, and we will override the actions for Run, Update, Dispose, and IsFinished. Additionally, we need to create a Drawable class variable to store our rectangle for use in all actions, and we must also create a timer so that we can make our Behavior last for five seconds, giving the following template:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Drawable
use Libraries.Sound.Speech

class RotationBehavior is Behavior
    Drawable rectangle = undefined
    number timer = 0

    action Run(BehaviorEvent event)
    end

    action Update(number seconds)
    end

    action Dispose
    end

    action IsFinished returns boolean
    end
end

In the Run action, we must first obtain the Drawable we want to rotate. Since the RotationBehavior will later be added to the Drawable itself in the main class, we can use the BehaviorEvent's GetItem action to get the object associated with the Behavior. However, this action returns an Item, not a Drawable, so we must cast it. This gives us the following line:

rectangle = cast(Drawable, event:GetItem())

Next, for the program to say "Rotate," we will need to use the Speech class's Say action, giving us the following lines:

Speech speech
speech:Say("Rotate")

This gives the following complete Run action:

action Run(BehaviorEvent event)
    rectangle = cast(Drawable, event:GetItem())
    Speech speech
    speech:Say("Rotate")
end

Moving on to the Update action, we want our rectangle to rotate, and we want to keep track of the time elapsed. Therefore, we need to increment the timer and call the Drawable's Rotate action. Since the Update action will be used for five seconds, a rotation of 72 degrees per second will result in a full 360 degrees rotation, giving us the following Update action:

action Update(number seconds)
    timer = timer + seconds
    if rectangle not= undefined
        rectangle:Rotate(72 * seconds)
    end
end

Note that the conditional if-statement checks if the "rectangle" variable is defined. If we did not include this, then the program could potentially crash by attempting to rotate an object that does not exist.

In the Dispose action, we want our rectangle to change color to indicate that the Behavior is finished. As such, we need to create a Color variable and call the Drawable's SetColor action. Lastly, for the program to say "Rotation complete," we will once again need to use the Speech class's Say action. This gives the following Dispose action:

action Dispose
    if rectangle not= undefined
        Color color
        rectangle:SetColor(color:Green())
        Speech speech
        speech:Say("Rotation complete")
    end
end

With this, once the Behavior is finished, the rectangle will change from Red to Green, and the program will say "Rotation complete."

In the IsFinished action, we need to set the action to return true once five seconds have passed. Thus, we simply add the line "return timer >= 5" to get the following action:

action IsFinished returns boolean
    return timer >= 5
end

Altogether, the resulting RotationBehavior class looks like this:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Drawable
use Libraries.Sound.Speech

class RotationBehavior is Behavior

    Drawable rectangle
    number timer = 0

    action Run(BehaviorEvent event)
        rectangle = cast(Drawable, event:GetItem())
        Speech speech
        speech:Say("Rotate", false)
    end

    action Update(number seconds)
        timer = timer + seconds

        if rectangle not= undefined
            rectangle:Rotate(72 * seconds)
        end
    end

    action Dispose
        if rectangle not= undefined
            Color color
            rectangle:SetColor(color:Green())
            Speech speech
            speech:Say("Rotation complete", false)
        end
    end

    action IsFinished returns boolean
        return timer >= 5
    end
end

Setting up Main

In the main, we will be using a Drawable and and will be altering its Color, so we must include the Drawable and Color libraries.

First, we will create a Drawable object and a Color object. For the purposes of this tutorial, we want the Drawable to use its Behavior as soon as the game begins, so we'll add it to the game in the CreateGame action.

Next, let's load a rectangle shape using the Drawable's LoadFilledRectangle action. We are going to make it red for this tutorial. Then, we'll give it a position with the SetPosition action. Finally, we'll add it to the game using "Add(box)."

Lastly, we must return to the main class and give a RotationBehavior to our Drawable. At the end of the CreateGame action, this can be done creating a RotationBehavior variable and calling the Drawable's AddBehavior action, giving us the following lines:

RotationBehavior rotate
box:AddBehavior(rotate)

The resulting final version of the Main class is as follows:

use Libraries.Game.Game
use Libraries.Game.Graphics.Drawable
use Libraries.Game.Graphics.Color

class Main is Game

    action Main
        StartGame()
    end

    action CreateGame
        Drawable box
        Color color
        box:LoadFilledRectangle(300, 200, color:Red())
        box:SetPosition(250, 250)
        Add(box)

        RotationBehavior rotate
        box:AddBehavior(rotate)
    end

    action Update(number seconds)
    end
end

Now, when the program is run, the rectangle will start as red, the program will say "Rotate," the rectangle will make one full rotation over five seconds, and then turn green while the program says "Rotation complete." The following images show a sample of the beginning, middle, and end of the Behavior's execution.

This is an image of initial position of the Drawable.This is an image of a position of the Drawable mid-Behavior.This is an image of end position of the Drawable.

Next Tutorial

In the next tutorial, we will discuss Buttons, which describes how to use Buttons.