Disk

Let’s get the disk to move. This can be done in various ways using VUEngine, like directly manipulating the disk in the PongState, or creating an instance of a Disk class that inherits from Actor instead of instantiating the base class, or even using plain Sprites and mainpulating their positions directly, but we are going to use a special kind of Component called Mutators, which are possible thanks to Virtual C’s mutation feature.

To make the disk move we have various options: directly manipulating its transformation or using physics simulations to give it some weight and inertia. Let’s do the latter.

# Adding physic simulations

Another type of Component that can be easily added through the actor editor is a Body. It allows to apply forces to an Actor or set its velocity and it will take care of the computation of the movement. Open the Disk.actor editor and add a Body component like you previously did with Sprites, and input the following values:

But to actually move a Body, it is necessary to either set its velocity or to apply a force to it. Which means that we need to have access to the disk instance somehow to manipulate it. Enter mutation classes.

# Mutation classes

With mutation classes, we can add functionality to classes by means of abstract classes that don’t allow instantiation, that is without having to go the full blown inheritance route. In the case of mutations of the Actor class, they spare us the need to define another Spec and worry about implementing a constructor and destructor. They are useful as long as we don’t need to persist any additional data to implement the logic of the class. They are not restricted to inherit from Actor, mutation classes can be created for any non abstract class in VUEngine. Let’s see how to use them.

# Mutators

The Mutator class is a kind of Component that performs the mutation on Actors without having to do it manually by means of directly calling SomeClass::mutateTo(someClassObject, MutationClass::getClass()).

To add a Mutator to the disk, open the Disk.actor editor and add a Mutator component to it. These components have a single configuration value through which we can specify the mutation class that the component will apply to the instance of the Actor, which is created with the auto-generated DiskActorSpec (see assets/Actor/Disk/Converted/DiskActorSpec.c).

When a Mutator is attached to an Actor, it will convert the instance object into an instance of the mutation class, specified in the Mutator’s configuration. Since we want this instance to behave like a Pong disk, we will specify Disk as the target mutation class of the Mutator:

The editor will update DiskActorSpec and render a DiskMutator1MutatorSpec in DiskComponentSpecs:

MutatorROMSpec DiskMutator1MutatorSpec =
{
    {
        // Allocator
        __TYPE(Mutator),

        // Component type
        kMutatorComponent
    },

    // Mutation target class
    class(Disk),

    // Enabled
    true
};

ComponentSpec* const DiskComponentSpecs[] =
{
    (ComponentSpec*)&DiskSprite1SpriteSpec,
    (ComponentSpec*)&DiskBodySpec,
    (ComponentSpec*)&DiskMutator1MutatorSpec,
    NULL
};

Now, we have to create the Disk class. Since it is a mutation target, it has to be a mutation class.

To create the Disk mutation class, add the folder source/Actors/Disk and, in it, a header and an implementation file: Disk.h and Disk.c.

In Disk.h let’s add the following to declare the new class:

#include <Actor.h>

[...]

mutation class Disk : Actor
{
}

Actors are not necessarily ready to be manipulated immediately after they are instantiated since whether or not they have, at that point in time, all their Components attached to them depends on whether the Stage is configured to defer their initialization over time or not. VUEngine supports deferred initialization in order to reduce hiccups during gameplay due to the load on the CPU when creating Actors with many Components attached to them.

The way in which the engine tells the game that an Actor has been completely configured and can be manipulated is through the call to the Container::ready virtual method. So let’s override the ready method:

#include <Actor.h>

[...]

mutation class Disk : Actor
{
    /// Make the animated actor ready to starts operating once it has been completely intialized.
    /// @param recursive: If true, the ready call is propagated to its children, grand children, etc.
    override void ready(bool recursive);
}

Finally, in the implementation of the method, set the velocity of the Disk instance as shown below, making the direction of the movement random each time the disk is ready:

#include <Body.h>

#include "Disk.h"

[...]

mutation class Disk;

[...]

void Disk::ready(bool recursive)
{
    Base::ready(this, recursive);

    if(isDeleted(this->body))
    {
        return;
    }

    int16 angle = Math::random(Math::randomSeed(), 64) - 32;

    Vector3D velocity =
    {
        __FIXED_MULT(Body::getMaximumSpeed(this->body), __FIX7_9_TO_FIXED(__COS(angle))),
        __FIXED_MULT(Body::getMaximumSpeed(this->body), __FIX7_9_TO_FIXED(__SIN(angle))),
        0
    };

    if(50 > Math::random(Math::randomSeed(), 100))
    {
        velocity.x = -velocity.x;
    }

    Disk::setVelocity(this, &velocity, false);
}

When building and running the game again, the disk will start to move by itself.

Now, let’s also breathe some life into the Paddles .