excaliburjs / Excalibur

🎮 Your friendly TypeScript 2D game engine for the web 🗡️
https://excaliburjs.com
BSD 2-Clause "Simplified" License
1.82k stars 188 forks source link

Think about redoing sprite effects API #420

Closed kamranayub closed 3 years ago

kamranayub commented 9 years ago

I think effects will need the same treatment as Actions and be separated into their own API chain. Furthermore, it is all too common for Excalibur to call clearEffects and addEffect, which can remove any other custom effects on a Sprite.

Proposing something like this:

interface ISpriteEffect {
    set(value: any): void;
    clear(): void;
    update(x: any);
    isSet: boolean;
}

interface ISpriteEffectOf<T> extends ISpriteEffect {
    set(value: T): void;
}

interface SpriteEffects {
    colorize: Effect;
    opacity: Effect;
    fill: Effect;
    [key: string]: ISpriteEffect;
}

class Effect implements ISpriteEffectOf<string> {
    public set(value: string) { this.isSet = true; }
    public clear(): void { this.isSet = false; }
    public update(x: any) { }
    public isSet: boolean = true;
}

class Sprite {
    public fx: SpriteEffects;

    constructor() {

        // load available fx
        this.fx = engine.fx.load();
    }

    public clearFx() {
        for (var key in this.fx) {
            if (this.fx.hasOwnProperty(key)) {
                this.fx[key].clear();
            }
        }
    }
}

var engine = {

    fx: {
        available: {
            colorize: Effect,
            opacity: Effect,
            fill: Effect
        },
        register(key: string, effect: any) {
            engine.fx.available[key] = effect;
        },
        load: function (): SpriteEffects {
            var fx = {};

            for (var key in engine.fx.available) {
                if (engine.fx.available.hasOwnProperty(key)) {
                    fx[key] = Object.create(engine.fx.available[key].prototype);
                }
            }

            return <SpriteEffects>fx;
        }
    }

}

// register custom at startup
engine.fx.register("custom", Effect);

var sprite = new Sprite();

// built-in
sprite.fx.colorize.set("white");
sprite.fx.colorize.clear();

// custom
sprite.fx["custom"].set("foo");

// clear all
sprite.clearFx();

This supports built-in effects with full intellisense and then registering custom effects at a global level. All effects are available to every sprite/whatever, but you can clear them out or set them without adding/removing.

Not sure yet about ordering of effects using this method. Maybe ISpriteEffect has an order and you can customize it when needed.

eonarheim commented 9 years ago

@kamranayub :+1:

If we get rid of the Effect array and make effects permanent we wouldn't need to worry about order.. not sure this is okay. But that would sacrifice the ability to undo an effect... unless we did some sort of command pattern and implement an applyEffect and an removeEffect. Or we can keep the effect array and play some tricks in the set() function.

SpriteEffects right now are fairly heavy items, so anything we can do to make them better is awesome.

github-actions[bot] commented 3 years ago

This issue hasn't had any recent activity lately and is being marked as stale automatically.

eonarheim commented 3 years ago

Closed by #1730