Heim  >  Artikel  >  Web-Frontend  >  Implementieren Sie ein einfaches Codebeispiel für eine Partikel-Engine mit HTML5-Canvas

Implementieren Sie ein einfaches Codebeispiel für eine Partikel-Engine mit HTML5-Canvas

黄舟
黄舟Original
2017-03-22 15:26:372193Durchsuche

Vorwort

Nun, es eine „Partikelmaschine“ zu nennen, ist immer noch eine große Aussage und ein bisschen ein Titel, und es ist immer noch ein bisschen weit von einer echten Partikelmaschine entfernt. Werfen wir ohne weiteres einen Blick auf die Demo

In diesem Artikel erfahren Sie, wie Sie einen einfachen LeinwandPartikelmacher (im Folgenden als Engine bezeichnet) erstellen ).

Weltansicht

Diese einfache Engine erfordert drei Elemente: World, Launcher und Grain. Zusammenfassend ist dies: Der Emitter existiert in der Welt und der Emitter erzeugt Partikel. Die Welt und der Emitter beeinflussen den

Zustand der Partikel. Es ergibt sich folgende Rechnung: Versetzen Sie sich in die Lage des Augenblicks.

Welt

Die sogenannte „Welt“ ist die

Umgebung, die global auf die in dieser „Welt“ existierenden Partikel einwirkt. Wenn sich ein Teilchen dafür entscheidet, in dieser „Welt“ zu existieren, dann wird dieses Teilchen von dieser „Welt“ beeinflusst.

Launcher

Eine Einheit, die zum Ausstoßen von Partikeln verwendet wird. Sie können verschiedene

Eigenschaften der von ihnen erzeugten Partikel steuern. Als Elternteil von Partikeln kann der Emitter die Geburtsattribute von Partikeln steuern: Geburtsposition, Geburtsgröße, Lebensdauer, ob er von „Welt“ beeinflusst wird, ob er von „Launcher“ selbst beeinflusst wird usw.

Außerdem muss der Emittent selbst die von ihm produzierten toten Partikel beseitigen.

Teilchen (Korn)

Die kleinste Grundeinheit ist jedes turbulente

Individuum. Jedes Individuum hat seine eigene Position, Größe, Lebensdauer und ob es unter dem gleichen Namen usw. leidet, sodass seine Form in jedem Moment genau auf der Leinwand dargestellt werden kann.

Hauptlogik des Partikelzeichnens

Implementieren Sie ein einfaches Codebeispiel für eine Partikel-Engine mit HTML5-Canvas

Das Obige ist die Hauptlogik des Partikelzeichnens.

Schauen wir uns zunächst an, was die Welt braucht.

Erschaffe eine Welt

Ich weiß nicht, warum ich natürlich dachte, dass die Welt

Schwerkraftbeschleunigung haben sollte. Allerdings kann die Erdbeschleunigung allein nicht viele Tricks zeigen, daher habe ich hier zwei weitere Einflussfaktoren hinzugefügt: Wärme und Wind. Die Richtung der Erdbeschleunigung und der Wärme ist vertikal und die Richtung des Windeinflusses ist horizontal. Mit diesen drei Dingen können wir die Teilchen sehr kokett bewegen.

Die Aufrechterhaltung einiger Zustände (z. B. das Überleben von Partikeln) erfordert Zeitmarkierungen. Fügen wir also der Welt Zeit hinzu, um den Effekt der Zeitunterbrechung und des umgekehrten Flusses später zu erleichtern.

define(function(require, exports, module) {
    var Util = require('./Util');
    var Launcher = require('./Launcher');

    /**
     * 世界构造函数
     * @param config
     *          backgroundImage     背景图片
     *          canvas              canvas引用
     *          context             canvas的context
     *
     *          time                世界时间
     *
     *          gravity             重力加速度
     *
     *          heat                热力
     *          heatEnable          热力开关
     *          minHeat             随机最小热力
     *          maxHeat             随机最大热力
     *
     *          wind                风力
     *          windEnable          风力开关
     *          minWind             随机最小风力
     *          maxWind             随机最大风力
     *
     *          timeProgress        时间进步单位,用于控制时间速度
     *          launchers           属于这个世界的发射器队列
     * @constructor
     */
    function World(config){
        //太长了,略去细节
    }
    World.prototype.updateStatus = function(){};
    World.prototype.timeTick = function(){};
    World.prototype.createLauncher = function(config){};
    World.prototype.drawBackground = function(){};
    module.exports = World;
});
Wie wir alle wissen, bedeutet das Zeichnen von Animationen, dass man sie ständig neu zeichnen muss, daher müssen wir eine Methode für externe Schleifenaufrufe verfügbar machen:

/**
 * 循环触发函数
 * 在满足条件的时候触发
 * 比如RequestAnimationFrame回调,或者setTimeout回调之后循环触发的
 * 用于维持World的生命
 */
 
World.prototype.timeTick = function(){

    //更新世界各种状态
    this.updateStatus();

    this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
    this.drawBackground();

    //触发所有发射器的循环调用函数
    for(var i = 0;i<this.launchers.length;i++){
        this.launchers[i].updateLauncherStatus();
        this.launchers[i].createGrain(1);
        this.launchers[i].paintGrain();
    }
};
Diese timeTick-Methode befindet sich in der äußere Schleife Führen Sie beim Aufrufen jedes Mal Folgendes aus:

  1. Weltstatus aktualisieren

  2. Leinwand leeren und Hintergrund neu zeichnen

  3. Befragen Sie alle Emittenten auf der ganzen Welt und aktualisieren Sie ihren Status, erstellen Sie neue Partikel und zeichnen Sie Partikel

Was genau sind also die Status der Welt, die aktualisiert werden müssen? ?

Natürlich ist es einfach, sich jedes Mal ein wenig Zeit zu nehmen. Zweitens halten wir den Zustand von Wind und Hitze instabil, damit sich die Partikel so kokett wie möglich bewegen – jeder Windstoß und jeder Hitzestoß ist etwas, dessen Sie sich nicht bewusst sind~

World.prototype.updateStatus = function(){
    this.time+=this.timeProgress;
    this.wind = Util.randomFloat(this.minWind,this.maxWind);
    this.heat = Util.randomFloat(this.minHeat,this.maxHeat);
};
Erschaffung der Welt Nachdem es herausgekommen ist, müssen wir die Welt noch in die Lage versetzen, Partikelemitter herzustellen, sonst wie können wir Partikel herstellen~

World.prototype.createLauncher = function(config){
    var _launcher = new Launcher(config);
    this.launchers.push(_launcher);
};
Okay, als Gott haben wir die Welt fast erschaffen, und Der nächste Schritt ist, dass alle Arten von Kreaturen erfunden wurden.

Zwicken Sie das erste Lebewesen heraus: Emitter

Emitter ist das erste Lebewesen der Welt, das auf den Emitter angewiesen ist, um alle Arten seltsamer Teilchen zu reproduzieren. Welche Eigenschaften muss ein Sender haben?

Zuerst müssen Sie herausfinden, zu welcher Welt es gehört (da es sich bei dieser Welt möglicherweise um mehr als eine Welt handelt).

Zweitens ist es der Zustand des Senders selbst: Position, Wind und Hitze innerhalb seines eigenen Systems. Man kann sagen, dass der Sender eine kleine Welt in einer Welt ist.

Beschreiben wir abschließend seine „Gene“. Die Gene des Emittenten wirken sich auf seine Nachkommen (Partikel) aus. Je mehr „Gene“ wir den Sendern geben, desto mehr biologische Merkmale werden ihre Nachkommen haben. Einzelheiten finden Sie unten im Gewissenscode

Kommentar ~

define(function (require, exports, module) {
    var Util = require(&#39;./Util&#39;);
    var Grain = require(&#39;./Grain&#39;);

    /**
     * 发射器构造函数
     * @param config
     *          id              身份标识用于后续可视化编辑器的维护
     *          world           这个launcher的宿主
     *
     *          grainImage      粒子图片
     *          grainList       粒子队列
     *          grainLife       产生的粒子的生命
     *          grainLifeRange  粒子生命波动范围
     *          maxAliveCount   最大存活粒子数量
     *
     *          x               发射器位置x
     *          y               发射器位置y
     *          rangeX          发射器位置x波动范围
     *          rangeY          发射器位置y波动范围
     *
     *          sizeX           粒子横向大小
     *          sizeY           粒子纵向大小
     *          sizeRange       粒子大小波动范围
     *
     *          mass            粒子质量(暂时没什么用)
     *          massRange       粒子质量波动范围
     *
     *          heat            发射器自身体系的热气
     *          heatEnable      发射器自身体系的热气生效开关
     *          minHeat         随机热气最小值
     *          maxHeat         随机热气最小值
     *
     *          wind            发射器自身体系的风力
     *          windEnable      发射器自身体系的风力生效开关
     *          minWind         随机风力最小值
     *          maxWind         随机风力最小值
     *
     *          grainInfluencedByWorldWind      粒子受到世界风力影响开关
     *          grainInfluencedByWorldHeat      粒子受到世界热气影响开关
     *          grainInfluencedByWorldGravity   粒子受到世界重力影响开关
     *
     *          grainInfluencedByLauncherWind   粒子受到发射器风力影响开关
     *          grainInfluencedByLauncherHeat   粒子受到发射器热气影响开关
     *
     * @constructor
     */

    function Launcher(config) {
        //太长了,略去细节
    }

    Launcher.prototype.updateLauncherStatus = function () {};
    Launcher.prototype.swipeDeadGrain = function (grain_id) {};
    Launcher.prototype.createGrain = function (count) {};
    Launcher.prototype.paintGrain = function () {};

    module.exports = Launcher;

});
Der Sender ist für die Geburt eines Kindes verantwortlich, wie man gebärt:

 Launcher.prototype.createGrain = function (count) {
        if (count + this.grainList.length <= this.maxAliveCount) {
            //新建了count个加上旧的还没达到最大数额限制
        } else if (this.grainList.length >= this.maxAliveCount &&
            count + this.grainList.length > this.maxAliveCount) {
            //光是旧的粒子数量还没能达到最大限制
            //新建了count个加上旧的超过了最大数额限制
            count = this.maxAliveCount - this.grainList.length;
        } else {
            count = 0;
        }
        for (var i = 0; i < count; i++) {
            var _rd = Util.randomFloat(0, Math.PI * 2);
            var _grain = new Grain({/*粒子配置*/});
            this.grainList.push(_grain);
        }
    };
Danach Ich gebäre das Kind, das Kind, das ich nach meinem Tod noch aufräumen muss... (Es ist so traurig, ich schiebe die Schuld auf mangelndes Gedächtnis)

Launcher.prototype.swipeDeadGrain = function (grain_id) {
    for (var i = 0; i < this.grainList.length; i++) {
        if (grain_id == this.grainList[i].id) {
            this.grainList = this.grainList.remove(i);//remove是自己定义的一个Array方法
            this.createGrain(1);
            break;
        }
    }
};
Nach der Geburt muss ich das Kind immer noch zulassen raus zum Spielen:

Launcher.prototype.paintGrain = function () {
    for (var i = 0; i < this.grainList.length; i++) {
        this.grainList[i].paint();
    }
};
Mein eigenes Vergiss nicht, die kleine innere Welt zu bewahren~ (ähnlich der großen Welt draußen)

Launcher.prototype.updateLauncherStatus = function () {
    if (this.grainInfluencedByLauncherWind) {
        this.wind = Util.randomFloat(this.minWind, this.maxWind);
    }
    if(this.grainInfluencedByLauncherHeat){
        this.heat = Util.randomFloat(this.minHeat, this.maxHeat);
    }
};
Okay, bis jetzt haben wir das hat die Erschaffung des ersten Geschöpfs der Welt abgeschlossen, und als nächstes kommen ihre Nachkommen (Huhu, Gott ist so müde)

Kinder und Enkelkinder, endlos

Kommt raus, ihr Kleinen, ihr seid die Protagonisten der Welt!

作为世界的主角,粒子们拥有各种自身的状态:位置、速度、大小、寿命长度、出生时间当然必不可少

define(function (require, exports, module) {
    var Util = require(&#39;./Util&#39;);

    /**
     * 粒子构造函数
     * @param config
     *          id              唯一标识
     *          world           世界宿主
     *          launcher        发射器宿主
     *
     *          x               位置x
     *          y               位置y
     *          vx              水平速度
     *          vy              垂直速度
     *
     *          sizeX           横向大小
     *          sizeY           纵向大小
     *
     *          mass            质量
     *          life            生命长度
     *          birthTime       出生时间
     *
     *          color_r
     *          color_g
     *          color_b
     *          alpha           透明度
     *          initAlpha       初始化时的透明度
     *
     *          influencedByWorldWind
     *          influencedByWorldHeat
     *          influencedByWorldGravity
     *          influencedByLauncherWind
     *          influencedByLauncherHeat
     *
     * @constructor
     */
    function Grain(config) {
        //太长了,略去细节
    }

    Grain.prototype.isDead = function () {};
    Grain.prototype.calculate = function () {};
    Grain.prototype.paint = function () {};
    module.exports = Grain;
});

粒子们需要知道自己的下一刻是怎样子的,这样才能把自己在世界展现出来。对于运动状态,当然都是初中物理的知识了:-)

Grain.prototype.calculate = function () {
    //计算位置
    if (this.influencedByWorldGravity) {
        this.vy += this.world.gravity+Util.randomFloat(0,0.3*this.world.gravity);
    }
    if (this.influencedByWorldHeat && this.world.heatEnable) {
        this.vy -= this.world.heat+Util.randomFloat(0,0.3*this.world.heat);
    }
    if (this.influencedByLauncherHeat && this.launcher.heatEnable) {
        this.vy -= this.launcher.heat+Util.randomFloat(0,0.3*this.launcher.heat);
    }
    if (this.influencedByWorldWind && this.world.windEnable) {
        this.vx += this.world.wind+Util.randomFloat(0,0.3*this.world.wind);
    }
    if (this.influencedByLauncherWind && this.launcher.windEnable) {
        this.vx += this.launcher.wind+Util.randomFloat(0,0.3*this.launcher.wind);
    }
    this.y += this.vy;
    this.x += this.vx;
    this.alpha = this.initAlpha * (1 - (this.world.time - this.birthTime) / this.life);

    //TODO 计算颜色 和 其他

};

粒子们怎么知道自己死了没?

Grain.prototype.isDead = function () {
    return Math.abs(this.world.time - this.birthTime)>this.life;
};

粒子们又该以怎样的姿态把自己展现出来?

Grain.prototype.paint = function () {
    if (this.isDead()) {
        this.launcher.swipeDeadGrain(this.id);
    } else {
        this.calculate();
        this.world.context.save();
        this.world.context.globalCompositeOperation = &#39;lighter&#39;;
        this.world.context.globalAlpha = this.alpha;
        this.world.context.drawImage(this.launcher.grainImage, this.x-(this.sizeX)/2, this.y-(this.sizeY)/2, this.sizeX, this.sizeY);
        this.world.context.restore();
    }
};

嗟乎。

Das obige ist der detaillierte Inhalt vonImplementieren Sie ein einfaches Codebeispiel für eine Partikel-Engine mit HTML5-Canvas. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn