YACE64 Logo

The Commodore 64 Emulator with the extra dimension

Home Introduction Features Screenshots Download Links Help About
Commodore 64
www.icons8.com

Tutorials

Tutorial 25 - Particle Effects


Hint: turn sound on!

Instructions

Particles are a little bit complicated and require many settings to achieve a nice result. Best practice is to take one of the examples and change it with slightly changes to the parameters. Design the effect in a separate script, so changing and loading the script is faster to emitienly see the result of changes.

A particle effect is defined through the numbers of particles, its form, speed, direction, colors and so on. Each parameter can be added with some randomnes to make the effect more interesting.

So the direction, the speed, the color and the form will vary in runtime. Also an effect can run "forever" or is just a single-shot, like an explosion.

Defining the direction is maybe the most complicated part - to make this a little bit easier there are to function SetSpherical and SphericalRange, that can be used to get the direction vector by spherical coordinates.

In the example below two paricle effects are defined. The "bubbles" are running forever and the "explosion" can be triggered by pressing the 'S' keys.
The "bubbled" can be moved left and right with the 'A' and 'D' keys. The 'W' and 'X' changes the length of the direction vector and so changes the speed of the emitted particles. Due to the defined gravity the bubbles will be "pulled" down.

The particle form can be set with up to four of sixteen predefined forms (see enum Particle).

Creation of the particle effects is done in the OnLoad() methode with the CreateParticleEffect() function and manipulation through the C64 keyboard with the OnKeyboard() callback function. Particles are a system wide resource, so they have to be cleared by the script with the Delete() function (usually done in OnUnload()).

The second part in this example is using audio files to extend the SID sound and setting the 3D position of the sound emitter.
Loading the sounds and setting its initial position is also done in the OnLoad() callback. Within the OnKeyboard() callback, the "bubble" sound is moved according the position of the "bubble" particle effect.

ParticleEffect bubbles;
ParticleEffect explosion;

Vector particleEmitterPosition;
Vector acc1;
Vector dir1;
Vector gravity1;
Vector dirRange1;
float speed = 0.09;

float audioEmitterX = 0.0;

int OnChar(int mode, CharInfo& charInfo, BlockManipulation& charManipulationBack, BlockManipulation& charManipulationFore)
{
    if (charInfo.row > 8)
        return Draw::DrawNothing;

    return Draw::DrawCombined;
}

void OnLoad(bool reloaded)
{
    string scriptPath = APP.GetScriptPath();

    APP.ClearDepthMaps();
    APP.ClearModels();
    APP.ViewMode = ViewMode::Ext3D;

    // Load some audio files and enable 3D audio
    APP.LoadAudio(AudioEmitter::Aux1, 0, scriptPath + "Sound\\explosion12.raw");
    APP.LoadAudio(AudioEmitter::Aux2, 0, scriptPath + "Sound\\66786__mattj99__bubbling01.raw");
    APP.Audio3D = true;

    // Set initial audio positions
    APP.PlayAudio(AudioEmitter::Aux2, 0, true);
    APP.SetAudioEmitter(AudioEmitter::Aux1, 0.0, 0.0, 0.1);
    APP.SetAudioEmitter(AudioEmitter::Aux2, audioEmitterX, 0.0, 0.1);

    // Set initial position, acceleration, direction/speed and gravity for the bubble particles
    particleEmitterPosition = Vector(-0.15, 0.0, -0.05);
    acc1 = Vector(1.0, 1.0, 1.0);
    dirRange1 = dir1.SphericalRange(0.09, 0.0, -90.0, 0.19, 30.0, 5.0);
    gravity1.SetSpherical(0.03, 0.0, 90.0);

    // Create the bubble effect
    bubbles = APP.CreateParticleEffect(100, 2000.0, 10000.0, true);

    bubbles.SetEmitterPosition(particleEmitterPosition, Vector(0.05, 0.0, 0.1));
    bubbles.SetParticleDirection(dir1, dirRange1, gravity1, acc1);
    bubbles.SetParticleColor(Vector(0.5, 0.5, 0.5, 0.8), Vector(0.5, 0.5, 0.5, 0.2), Vector(-0.05, -0.1, 0.1, 0.0));
    bubbles.SetParticleSize(0.01, 0.005, -0.0015);
    bubbles.SetIntensity(1.0);
    bubbles.SetTextures({ Particle::CircleFilled, Particle::Star4, Particle::Star5Filled, Star6Filled });
    bubbles.Enable = true;


    // Create the explosion effect
    explosion = APP.CreateParticleEffect(150, 1000.0, 2200.0, false);

    explosion.SetEmitterPosition(Vector(-0.5, 0.0, +0.05), Vector(0.02, 0.02, 0.02));
    explosion.SetParticleDirection(Vector(0.0, 0.0, 0.0), Vector(0.18, 0.18, 0.18), Vector(0.0, 0.0, 0.0, 0.0), Vector(0.995, 0.995, 0.995));
    explosion.SetParticleSize(0.003, 0.0015, -0.0015);
    explosion.SetParticleColor(Vector(0.5, 0.5, 0.5, 1.0), Vector(0.1, 0.05, 0.05, 0.0), Vector(-0.06, -0.08, -0.08, 0.0));
    explosion.SetIntensity(1.0);
    explosion.SetTextures({ Particle::Frag1, Particle::Frag2, Particle::RectFilled, Frag4 });
    explosion.Enable = true;
}

void OnUnload()
{
    bubbles.Delete();
    explosion.Delete();
    APP.StopAudio(AudioEmitter::Aux2);
}

void OnKeyboard(bool pressed, Keys cbmKeyboard)
{
    if (pressed)
    {
        if (cbmKeyboard == Keys::A)
        {
            // Move bubble particle emitter and audio position to left
            particleEmitterPosition -= Vector(0.05, 0.0, 0.0);
            bubbles.SetEmitterPosition(particleEmitterPosition, Vector(0.05, 0.0, 0.1));

            audioEmitterX -= 0.5f;
            APP.SetAudioEmitter(AudioEmitter::Aux2, audioEmitterX, 0.0, 0.1);
        }
        else if (cbmKeyboard == Keys::D)
        {
            // Move bubble particle emitter and audio position to right
            particleEmitterPosition += Vector(0.05, 0.0, 0.0);
            bubbles.SetEmitterPosition(particleEmitterPosition, Vector(0.05, 0.0, 0.1));

            audioEmitterX += 0.5f;
            APP.SetAudioEmitter(AudioEmitter::Aux2, audioEmitterX, 0.0, 0.1);
        }
        else if (cbmKeyboard == Keys::W)
        {
            speed += 0.05;

            dirRange1 = dir1.SphericalRange(speed, 0.0, -90.0, 0.19, 30.0, 5.0);
            bubbles.SetParticleDirection(dir1, dirRange1, gravity1, acc1);

        }
        else if (cbmKeyboard == Keys::X)
        {
            speed -= 0.05;

            dirRange1 = dir1.SphericalRange(speed, 0.0, -90.0, 0.19, 30.0, 5.0);

            bubbles.SetParticleDirection(dir1, dirRange1, gravity1, acc1);
        }
        else if (cbmKeyboard == Keys::S)
        {
            // Play explosion sound and start the explosion particle effect
            APP.PlayAudio(AudioEmitter::Aux1, 0, false);
            explosion.Restart();
        }
    }
}