<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧

        來源:懂視網 責編:小采 時間:2020-11-27 20:49:53
        文檔

        用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧

        用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧:系列簡介 也許,三百年前的艾薩克·牛頓爵士(Sir Issac Newton, 1643-1727)并沒幻想過,物理學廣泛地應用在今天許多游戲、動畫中。為什么在這些應用中要使用物理學?筆者認為,自我們出生以來,一直感受著物理世界的規律,意識到物體在這世界是如何正常移動
        推薦度:
        導讀用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧:系列簡介 也許,三百年前的艾薩克·牛頓爵士(Sir Issac Newton, 1643-1727)并沒幻想過,物理學廣泛地應用在今天許多游戲、動畫中。為什么在這些應用中要使用物理學?筆者認為,自我們出生以來,一直感受著物理世界的規律,意識到物體在這世界是如何正常移動

        系列簡介
        也許,三百年前的艾薩克·牛頓爵士(Sir Issac Newton, 1643-1727)并沒幻想過,物理學廣泛地應用在今天許多游戲、動畫中。為什么在這些應用中要使用物理學?筆者認為,自我們出生以來,一直感受著物理世界的規律,意識到物體在這世界是如何"正常移動",例如射球時球為拋物線(自旋的球可能會做成弧線球) 、石子系在一根線的末端會以固定頻率擺動等等。要讓游戲或動畫中的物體有真實感,其移動方式就要符合我們對"正常移動"的預期。
        今天的游戲動畫應用了多種物理模擬技術,例如運動學模擬(kinematics simulation)、剛體動力學模擬(rigid body dynamics simulation)、繩子/布料模擬(string/cloth simulation)、柔體動力學模擬(soft body dynamics simulation)、流體動力學模擬(fluid dynamics simulation)等等。另外碰撞偵測(collision detection)是許多模擬系統里所需的。
        本系列希望能介紹一些這方面最基礎的知識,繼續使用JavaScript做例子,以即時互動方式體驗。
        本文簡介
        作為系列第一篇,本文介紹最簡單的運動學模擬,只有兩條非常簡單的公式。運動學模擬可以用來模擬很多物體運動(例如馬里奧的跳躍、炮彈等),本文將會配合粒子系統做出一些視覺特效(粒子系統其實也可以用來做游戲的玩法,而不單是視覺特效)。
        運動學模擬
        運動學(kinematics)研究物體的移動,和動力學(dynamics)不同之處,在于運動學不考慮物體的質量(mass)/轉動慣量(moment of inertia),以及不考慮加之于物體的力(force )和力矩(torque)。
        我們先回憶牛頓第一運動定律:
        當物體不受外力作用,或所受合力為零時,原先靜止者恒靜止,原先運動者恒沿著直線作等速度運動。該定律又稱為「慣性定律」。此定律指出,每個物體除了其位置(position)外,還有一個線性速度(linear velocity)的狀態。然而,只模擬不受力影響的物體并不有趣。撇開力的概念,我們可以用線性加速度(linear acceleration)去影響物體的運動。例如,要計算一個自由落體在任意時間t的y軸座標,可以使用以下的分析解(analytical solution):

        當中,和分別是t=0時的y軸起始座標和速度,而g則是重力加速度(gravitational acceleration)。
        這分析解雖然簡單,但是有一些缺點,例如g是常數,在模擬過程中不能改變;另外,當物體遇到障礙物,產生碰撞時,這公式也很難處理這種不連續性(discontinuity) 。
        在計算機模擬中,通常需要計算連續的物體狀態。用游戲的用語,就是計算第一幀的狀態、第二幀的狀態等等。設物體在任意時間t的狀態:位置矢量為、速度矢量為、加速度矢量為。我們希望從時間的狀態,計算下一個模擬時間的狀態。最簡單的方法,是采用歐拉方法(Euler method)作數值積分(numerical integration):

        歐拉方法非常簡單,但有準確度和穩定性問題,本文會先忽略這些問題。本文的例子采用二維空間,我們先實現一個JavaScript二維矢量類:
        代碼如下:
        // Vector2.js
        Vector2 = function(x, y) { this.x = x; this.y = y; };

        Vector2.prototype = {
        copy : function() { return new Vector2(this.x, this.y); },
        length : function() { return Math.sqrt(this.x * this.x + this.y * this.y); },
        sqrLength : function() { return this.x * this.x + this.y * this.y; },
        normalize : function() { var inv = 1/this.length(); return new Vector2(this.x * inv, this.y * inv); },
        negate : function() { return new Vector2(-this.x, -this.y); },
        add : function(v) { return new Vector2(this.x + v.x, this.y + v.y); },
        subtract : function(v) { return new Vector2(this.x - v.x, this.y - v.y); },
        multiply : function(f) { return new Vector2(this.x * f, this.y * f); },
        divide : function(f) { var invf = 1/f; return new Vector2(this.x * invf, this.y * invf); },
        dot : function(v) { return this.x * v.x + this.y * v.y; }
        };

        Vector2.zero = new Vector2(0, 0);

        然后,就可以用HTML5 Canvas去描繪模擬的過程:
        代碼如下:
        var position = new Vector2(10, 200);
        var velocity = new Vector2(50, -50);
        var acceleration = new Vector2(0, 10);
        var dt = 0.1;
        function step() {
        position = position.add(velocity.multiply(dt));
        velocity = velocity.add(acceleration.multiply(dt));
        ctx.strokeStyle = "#000000";
        ctx.fillStyle = "#FFFFFF";
        ctx.beginPath();
        ctx.arc(position.x, position.y, 5, 0, Math.PI*2, true);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        }
        start("kinematicsCancas", step);













        修改代碼試試看


      1. 改變起始位置

      2. 改變起始速度(包括方向)

      3. 改變加速度


      4. 這程序的核心就是step()函數頭兩行代碼。很簡單吧?
        粒子系統
        粒子系統(particle system)是圖形里常用的特效。粒子系統可應用運動學模擬來做到很多不同的效果。粒子系統在游戲和動畫中,常常會用來做雨點、火花、煙、爆炸等等不同的視覺效果。有時候,也會做出一些游戲性相關的功能,例如敵人被打敗后會發出一些閃光,主角可以把它們吸收。
        粒子的定義
        粒子系統模擬大量的粒子,并通常用某些方法把粒子渲染。粒子通常有以下特性:
      5. 粒子是獨立的,粒子之間互不影響(不碰撞、沒有力)

      6. 粒子有生命周期,生命結束后會消失

      7. 粒子可以理解為空間的一個點,有時候也可以設定半徑作為球體和環境碰撞

      8. 粒子帶有運動狀態,也有其他外觀狀態(例如顏色、影像等)

      9. 粒子可以只有線性運動,而不考慮旋轉運動(也有例外)
      10. 以下是本文例子里實現的粒子類:
        代碼如下:// Particle.js
        Particle = function(position, velocity, life, color, size) {
        this.position = position;
        this.velocity = velocity;
        this.acceleration = Vector2.zero;
        this.age = 0;
        this.life = life;
        this.color = color;
        this.size = size;
        };

        游戲循環
        粒子系統通常可分為三個周期:
        發射粒子
        模擬粒子(粒子老化、碰撞、運動學模擬等等)
        渲染粒子
        在游戲循環(game loop)中,需要對每個粒子系統執行以上的三個步驟。
        生與死
        在本文的例子里,用一個JavaScript數組particles儲存所有活的粒子。產生一個粒子只是把它加到數組末端。代碼片段如下:
        代碼如下://ParticleSystem.js
        function ParticleSystem() {
        // Private fields
        var that = this;
        var particles = new Array();
        // Public fields
        this.gravity = new Vector2(0, 100);
        this.effectors = new Array();
        // Public methods
        this.emit = function(particle) {
        particles.push(particle);
        };
        // ...
        }

        粒子在初始化時,年齡(age)設為零,生命(life)則是固定的。年齡和生命的單位都是秒。每個模擬步,都會把粒子老化,即是把年齡增加\Delta t,年齡超過生命,就會死亡。代碼片段如下:
        代碼如下:function ParticleSystem() {
        // ...
        this.simulate = function(dt) {
        aging(dt);
        applyGravity();
        applyEffectors();
        kinematics(dt);
        };
        // ...
        // Private methods
        function aging(dt) {
        for (var i = 0; i < particles.length; ) {
        var p = particles[i];
        p.age += dt;
        if (p.age >= p.life)
        kill(i);
        else
        i++;
        }
        }
        function kill(index) {
        if (particles.length > 1)
        particles[index] = particles[particles.length - 1];
        particles.pop();
        }
        // ...
        }

        在函數kill()里,用了一個技巧。因為粒子在數組里的次序并不重要,要刪除中間一個粒子,只需要復制最末的粒子到那個元素,并用pop()移除最末的粒子就可以。這通常比直接刪除數組中間的元素快(在C++中使用數組或std::vector亦是)。
        運動學模擬
        把本文最重要的兩句運動學模擬代碼套用至所有粒子就可以。另外,每次模擬會先把引力加速度寫入粒子的加速度。這樣做是為了將來可以每次改變加速度(續篇會談這方面)。
        代碼如下:function ParticleSystem() {
        // ...
        function applyGravity() {
        for (var i in particles)
        particles[i].acceleration = that.gravity;
        }
        function kinematics(dt) {
        for (var i in particles) {
        var p = particles[i];
        p.position = p.position.add(p.velocity.multiply(dt));
        p.velocity = p.velocity.add(p.acceleration.multiply(dt));
        }
        }
        // ...
        }

        渲染
        粒子可以用很多不同方式渲染,例如用圓形、線段(當前位置和之前位置)、影像、精靈等等。本文采用圓形,并按年齡生命比來控制圓形的透明度,代碼片段如下:
        代碼如下:function ParticleSystem() {
        // ...
        this.render = function(ctx) {
        for (var i in particles) {
        var p = particles[i];
        var alpha = 1 - p.age / p.life;
        ctx.fillStyle = "rgba("
        + Math.floor(p.color.r * 255) + ","
        + Math.floor(p.color.g * 255) + ","
        + Math.floor(p.color.b * 255) + ","
        + alpha.toFixed(2) + ")";
        ctx.beginPath();
        ctx.arc(p.position.x, p.position.y, p.size, 0, Math.PI * 2, true);
        ctx.closePath();
        ctx.fill();
        }
        }
        // ...
        }

        基本粒子系統完成
        以下的例子里,每幀會發射一個粒子,其位置在畫布中間(200,200),發射方向是360度,速率為100,生命為1秒,紅色、半徑為5象素。
        代碼如下:
        var ps = new ParticleSystem();
        var dt = 0.01;
        function sampleDirection() {
        var theta = Math.random() * 2 * Math.PI;
        return new Vector2(Math.cos(theta), Math.sin(theta));
        }
        function step() {
        ps.emit(new Particle(new Vector2(200, 200), sampleDirection().multiply(100), 1, Color.red, 5));
        ps.simulate(dt);
        clearCanvas();
        ps.render(ctx);
        }
        start("basicParticleSystemCanvas", step);












        修改代碼試試看


      11. 改變發射位置

      12. 向上發射,發射范圍在90度內

      13. 改變生命

      14. 改變半徑

      15. 每幀發射5個粒子


      16. 簡單碰撞
        為了說明用數值積分相對于分析解的優點,本文在粒子系統上加簡單的碰撞。我們想加入一個需求,當粒子碰到長方形室(可設為整個Canvas大小)的內壁,就會碰撞反彈,碰撞是完全彈性的(perfectly elastic collision)。
        在程序設計上,我把這功能用回調方式進行。 ParticleSystem類有一個effectors數組,在進行運動學模擬之前,先執行每個effectors對象的apply()函數:
        而長方形室就這樣實現:
        代碼如下:// ChamberBox.js
        function ChamberBox(x1, y1, x2, y2) {
        this.apply = function(particle) {
        if (particle.position.x - particle.size < x1 || particle.position.x + particle.size > x2)
        particle.velocity.x = -particle.velocity.x;
        if (particle.position.y - particle.size < y1 || particle.position.y + particle.size > y2)
        particle.velocity.y = -particle.velocity.y;
        };
        }

        這其實就是當偵測到粒子超出內壁的范圍,就反轉該方向的速度分量。
        此外,這例子的主循環不再每次把整個Canvas清空,而是每幀畫一個半透明的黑色長方形,就可以模擬動態模糊(motion blur)的效果。粒子的顏色也是隨機從兩個顏色中取樣。
        代碼如下:
        var ps = new ParticleSystem();
        ps.effectors.push(new ChamberBox(0, 0, 400, 400)); // 最重要是多了這語句
        var dt = 0.01;
        function sampleDirection(angle1, angle2) {
        var t = Math.random();
        var theta = angle1 * t + angle2 * (1 - t);
        return new Vector2(Math.cos(theta), Math.sin(theta));
        }
        function sampleColor(color1, color2) {
        var t = Math.random();
        return color1.multiply(t).add(color2.multiply(1 - t));
        }
        function step() {
        ps.emit(new Particle(new Vector2(200, 200), sampleDirection(Math.PI * 1.75, Math.PI * 2).multiply(250), 3, sampleColor(Color.blue, Color.purple), 5));
        ps.simulate(dt);
        ctx.fillStyle="rgba(0, 0, 0, 0.1)";
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ps.render(ctx);
        }
        start("collisionChamberCanvas", step);





        互動發射
        最后一個例子加入互動功能,在鼠標位置發射粒子,粒子方向是按鼠標移動速度再加上一點噪音(noise)。粒子的大小和生命都加入了隨機性。
        代碼如下:var ps = new ParticleSystem();
        ps.effectors.push(new ChamberBox(0, 0, 400, 400));
        var dt = 0.01;
        var oldMousePosition = Vector2.zero, newMousePosition = Vector2.zero;
        function sampleDirection(angle1, angle2) {
        var t = Math.random();
        var theta = angle1 * t + angle2 * (1 - t);
        return new Vector2(Math.cos(theta), Math.sin(theta));
        }
        function sampleColor(color1, color2) {
        var t = Math.random();
        return color1.multiply(t).add(color2.multiply(1 - t));
        }
        function sampleNumber(value1, value2) {
        var t = Math.random();
        return value1 * t + value2 * (1 - t);
        }
        function step() {
        var velocity = newMousePosition.subtract(oldMousePosition).multiply(10);
        velocity = velocity.add(sampleDirection(0, Math.PI * 2).multiply(20));
        var color = sampleColor(Color.red, Color.yellow);
        var life = sampleNumber(1, 2);
        var size = sampleNumber(2, 4);
        ps.emit(new Particle(newMousePosition, velocity, life, color, size));
        oldMousePosition = newMousePosition;
        ps.simulate(dt);
        ctx.fillStyle="rgba(0, 0, 0, 0.1)";
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ps.render(ctx);
        }
        start("interactiveEmitCanvas", step);
        canvas.onmousemove = function(e) {
        if (e.layerX || e.layerX == 0) { // Firefox
        e.target.style.position='relative';
        newMousePosition = new Vector2(e.layerX, e.layerY);
        }
        else
        newMousePosition = new Vector2(e.offsetX, e.offsetY);
        };




        總結
        本文介紹了最簡單的運動學模擬,使用歐拉方法作數值積分,并以此法去實現一個有簡單碰撞的粒子系統。本文的精華其實只有兩條簡單公式(只有兩個加數和兩個乘數),希望讓讀者明白,其實物理模擬可以很簡單。雖然本文的例子是在二維空間,但這例子能擴展至三維空間,只須把Vector2換成Vector3。本文完整源代碼可下載。
        續篇會談及在此基礎上加入其他物理現象,有機會再加入其他物理模擬課題。希望各位支持,并給本人更多意見。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧

        用JavaScript玩轉游戲物理(一)運動學模擬與粒子系統_javascript技巧:系列簡介 也許,三百年前的艾薩克·牛頓爵士(Sir Issac Newton, 1643-1727)并沒幻想過,物理學廣泛地應用在今天許多游戲、動畫中。為什么在這些應用中要使用物理學?筆者認為,自我們出生以來,一直感受著物理世界的規律,意識到物體在這世界是如何正常移動
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 色偷偷亚洲男人天堂| 亚洲精品自拍视频| 特级做a爰片毛片免费看| 成年女人毛片免费观看97| 97久久国产亚洲精品超碰热| 人与禽交免费网站视频| 亚洲国产中文在线视频| 在线看片v免费观看视频777| 亚洲最大的黄色网| 女人张开腿等男人桶免费视频| 亚洲婷婷综合色高清在线| 国产2021精品视频免费播放| 亚洲国产美女精品久久| 青娱分类视频精品免费2| 亚洲中文字幕无码久久| 日本一道综合久久aⅴ免费| 日韩电影免费在线观看网址 | 亚洲第一中文字幕| 黄+色+性+人免费| 亚洲中文字幕无码中文| 免费欧洲美女牲交视频| 人成电影网在线观看免费| 精品亚洲一区二区| 97性无码区免费| 精品成人一区二区三区免费视频| 亚洲国产成人久久一区久久| 日本黄色动图免费在线观看| 亚洲中文无码av永久| 国产男女性潮高清免费网站| 9久热精品免费观看视频| 亚洲日本VA午夜在线影院| 国产美女做a免费视频软件| 久久er国产精品免费观看8| 亚洲人成网www| 好爽好紧好大的免费视频国产| 青草青草视频2免费观看| 亚洲国产精品无码久久久秋霞2| 国产免费一区二区三区| 男男gvh肉在线观看免费| 久久精品国产亚洲AV大全| 免费人成网站在线高清|