Particle Effects

Particle Effects

Showing off the built-in particle effects and all the magic it can do!

What better way to take advantage of Brainpads colorful display than to play around with some particles? Below is a program that lets you continuously add effects and overall makes a nice showcase on a project that may not use the display like a robot car!

This code only works in JavaScript and requires a base understanding to use.
interface ParticleDemonstration {
    start(): particles.ParticleSource[];
}

// show controls
let ctlMessage = image.create(scene.screenWidth(), 10);
ctlMessage.printCenter("Effects: 'A' (+), 'B' (-)", 0, 0);
let msgSprite = sprites.create(ctlMessage);
let msgInterval = 0;

const myDemonstrations: ParticleDemonstration[] = [];
let count = 1;

controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
    count = Math.min(count + 1, 6);
});

controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
    count = Math.max(count - 1, 1);
});

namespace demonstrations {
    export class Fire implements ParticleDemonstration {
        start() {
            const sources: particles.ParticleSource[] = [];
            const factory = new particles.FireFactory(8);
            const src = new particles.FireSource(makeSimpleAnchor(), 100, factory);
            src.setAcceleration(0, -40);

            sources.push(src);
            return sources;
        }
    }

    export class Spinner implements ParticleDemonstration {
        start() {
            class RingFactory extends particles.RadialFactory {
                createParticle(anchor: particles.ParticleAnchor) {
                    const p = super.createParticle(anchor);
                    p.lifespan = this.galois.randomRange(200, 350);
                    return p;
                }
            }

            const sources: particles.ParticleSource[] = [];
            const colors = [0x9, 0xA, 0xB, 0xC];
            const factory = new RingFactory(20, 30, 10, colors);
            const src = new particles.ParticleSource(makeSimpleAnchor(), 400, factory);

            sources.push(src);
            return sources;
        }
    }

    export class BubbleConfetti implements ParticleDemonstration {
        start() {
            const sources: particles.ParticleSource[] = [];
            const min = 1000;
            const anchor = makeSimpleAnchor();
            anchor.width = screen.width;

            const bubbleFactory = new particles.BubbleFactory(anchor, min, min * 2.5);
            sources.push(new particles.BubbleSource(anchor, 30, bubbleFactory.stateCount - 1, bubbleFactory));

            const confettiFactory = new particles.ConfettiFactory(anchor.width, 16);
            confettiFactory.setSpeed(50);

            sources.push(new particles.ParticleSource(anchor, 50, confettiFactory));
            return sources;
        }
    }

    export class RadialGroup implements ParticleDemonstration {
        start() {
            const sources: particles.ParticleSource[] = [];
            const anchor = makeSimpleAnchor();

            const radius = Math.percentChance(50) ? 0 : 20;
            const increaseRate = Math.percentChance(50);

            control.runInParallel(() => {
                for (let i = 0; i < 3; ++i) {
                    const colors = Math.percentChance(10) ?
                        [0xC, 0xD, 0xE]
                        :
                        Math.percentChance(50) ?
                            [0x6, 0x7, 0x8, 0x9, 0xA]
                            :
                            undefined;
                    let factory: particles.ParticleFactory = new particles.RadialFactory(radius, 90, 5, colors);
                    const src = new particles.ParticleSource(anchor, increaseRate ? 50 + (i * 50) : 100, factory);
                    sources.push(src);
                    pause(350);
                }
            });

            return sources;
        }
    }

    export class Stars implements ParticleDemonstration {
        start() {
            class StarFactory extends particles.ParticleFactory {
                protected galois: Math.FastRandom;
                protected possibleColors: number[];
                images: Image[];

                constructor(possibleColors?: number[]) {
                    super();
                    this.galois = new Math.FastRandom();
                    this.images = [
                        img`
                            1
                        `, img`
                            1 . 1
                            . 1 .
                            1 . 1
                        `, img`
                            . 1 .
                            1 1 1
                            . 1 .
                        `
                    ];

                    if (possibleColors && possibleColors.length)
                        this.possibleColors = possibleColors;
                    else
                        this.possibleColors = [1];
                }

                createParticle(anchor: particles.ParticleAnchor) {
                    const p = super.createParticle(anchor);

                    p._x = Fx8(this.galois.randomRange(0, screen.width));
                    p._y = Fx8(0);
                    p.vy = Fx8(this.galois.randomRange(40, 60));

                    // set lifespan based off velocity and screen height (plus a little to make sure it doesn't disappear early)
                    p.lifespan = Fx.toInt(Fx.mul(Fx.div(Fx8(screen.height + 20), p.vy), Fx8(1000)));

                    const length = this.possibleColors.length - 1;
                    p.color = this.possibleColors[this.possibleColors.length - 1];
                    for (let i = 0; i < length; ++i) {
                        if (this.galois.percentChance(50)) {
                            p.color = this.possibleColors[i];
                            break;
                        }
                    }

                    // images besides the first one are only used on occasion
                    p.data = this.galois.percentChance(15) ? this.galois.randomRange(1, this.images.length - 1) : 0;

                    return p;
                }

                drawParticle(p: particles.Particle, x: Fx8, y: Fx8) {
                    // on occasion, twinkle from white to yellow
                    const twinkleFlag = 0x8000;
                    const rest = 0x7FFF;
                    if (twinkleFlag && p.data) {
                        if (this.galois.percentChance(10)) {
                            p.color = 1;
                            p.data &= rest;
                        }
                    } else if (p.color === 1 && this.galois.percentChance(1)) {
                        p.color = 5;
                        p.data |= twinkleFlag;
                    }

                    const selected = this.images[rest & p.data].clone();
                    selected.replace(0x1, p.color);
                    screen.drawImage(selected, Fx.toInt(x), Fx.toInt(y));
                }
            }

            const sources: particles.ParticleSource[] = [];
            const colors = [1];
            for (let i = 0; i < 4; i++)
                colors.push(Math.randomRange(2, 0xE));

            const factory = new StarFactory(colors);
            const src = new particles.ParticleSource(makeSimpleAnchor(), 25, factory)
            sources.push(src);
            return sources;
        }
    }
}

function makeSimpleAnchor(): particles.ParticleAnchor {
    return {
        x: screen.width >> 1,
        y: screen.height >> 1
    };
}

// Radial group as a lot of different possible configurations, so make it twice as likely as others
for (let i = 0; i < 2; i++) {
    myDemonstrations.push(new demonstrations.RadialGroup());
}
myDemonstrations.push(new demonstrations.Stars());
myDemonstrations.push(new demonstrations.BubbleConfetti());
myDemonstrations.push(new demonstrations.Spinner());
myDemonstrations.push(new demonstrations.Fire());

forever(() => {
    particles.disableAll()

    for (let i = 0; i < count; ++i) {
        Math.pickRandom(myDemonstrations)
            .start();
    }

    msgSprite.top = scene.screenHeight();
    msgSprite.top += msgInterval % 5 == 0 ? -10 : 0;
    msgInterval += 1;
    pause(3000);
});

Here is a project to with the code already loaded.

Start Exploring Particles!

 

Sprites and Collision

Learn about Sprites and Collisions

Chicken Run

Help the chicken find her eggs. Inspired by frogger game

Helicopter Ride

Use your helicopter to fly your team back to the base

Newsletter

Get Social
Latest Press
October 11, 2019
September 26, 2019
August 23, 2019
August 7, 2019
August 5, 2019