官术网_书友最值得收藏!

第2章 物理實驗

實驗8 質點運動與反射

簡介

物理實驗屬于物理引擎的范疇,物理引擎是計算機圖像學與物理學之間的一座橋梁。物理引擎通過為剛性物體賦予真實物理屬性的方式來計算運動、旋轉和碰撞反應。

物理引擎使用對象屬性(動量、扭矩或者彈性)來模擬剛體行為,這不僅可以得到更加真實的結果,對于開發人員來說也比編寫行為腳本要更加容易掌握。好的物理引擎允許有復雜的機械裝置,像球形關節、輪子、汽缸或者鉸鏈。有些也支持非剛性體的物理屬性,如流體。物理引擎可以從其他廠商購買,而一些游戲開發系統具備完整的物理引擎。還要注意,雖然有的系統在其特性列表中說它們有物理引擎,但其實是一些簡單的加速和碰撞檢測屬性而已。物理引擎可以實現粒子效果、流體效果、軟體效果等,本實驗先從最簡單的勻速直線運動談起。

勻速直線運動

物體在一條直線上運動,且在任意相等的時間間隔內位移相等,這種運動稱為勻速直線運動(Uniform Rectilinear Motion),如圖2-1所示。位移是速度對時間的累積,寫成公式就是:s=∫vdt。而計算機無法模擬無窮小的時間間隔,但是只要時間間隔足夠小,積分運算誤差就不大。時間間隔為(1/60)s,也就是60幀/秒。

圖2-1 勻速直線運動

在實驗2臺球中,按照如下方式定義小球:

        var ball={
                  position: { x: 100, y: 100 },
                  r: 15
                };

其中包含了小球的位置和半徑兩個屬性,因為要用小球來做物理實驗,所以為小球增加兩個屬性vx和vy,分別代表小球沿X軸方向和沿Y軸方向上的速度。這在物理學上叫做運動獨立性原理,即:一個物體同時參與幾種運動,各分運動都可看成獨立進行的,互不影響,物體的合運動則視為幾個相互獨立分運動疊加的結果。分運動和合運動之間具有:獨立性、等時性、矢量性、同體性。如下所示:

        var ball={
                  position: { x: 100, y: 100 },
                  r: 15,
                  vx: 190,
                  vy: 110
                };

代碼中假定了小球沿X軸方向的速度為190,沿Y軸方向上的速度為110。

定義好了小球的速度,如何把它的運動狀態體現在Canvas中呢?在實驗3中,已經用到了Jscex來實現畫圓動畫。這里繼續使用Jscex來實現小球的運動。

在使用Jscex之前依然要先引用Jscex壓縮后的庫函數:

        <scriptsrc="jscex.min.js"type="text/javascript"></script>

這樣就可以使用Jscex了。

        <canvasid="myCanvas"width="600"height="500">Your browser does not support the canvas element.
        </canvas>
        <scripttype="text/javascript">
        var canvas=document.getElementById("myCanvas");
        var cxt=canvas.getContext("2d");
        var ball={
                position: { x: 100, y: 100 },
                r: 15,
                vx: 190,
                vy: 110
            };
        var cyc=10;
        var moveAsync=eval(Jscex.compile("async", function () {
        while (true) {
                cxt.fillStyle="rgba(0, 0, 0, .3)";    \注:實現了殘影效果。\
                cxt.fillRect(0, 0, canvas.width, canvas.height);
                cxt.fillStyle="#fff";
                cxt.beginPath();
                cxt.arc(ball.position.x, ball.position.y, ball.r, 0, Math.PI * 2, true);
                cxt.closePath();
                cxt.fill();
                ball.position.x +=ball.vx * cyc / 1000;
                ball.position.y +=ball.vy * cyc / 1000;    \注:小球的x 坐標和 y坐標每隔一個周期(cyc)就發生變化。\
                $await(Jscex.Async.sleep(cyc));
                }
            }))
            moveAsync().start();
        </script>

也可以讓小球往返不停地運動:

        var moveAsync=eval(Jscex.compile("async", function () {
        while (true) {
        while (ball.position.x < 500) {
                        cxt.fillStyle="rgba(0, 0, 0, .3)";
                        cxt.fillRect(0, 0, canvas.width, canvas.height);
                        cxt.fillStyle="#fff";
                        cxt.beginPath();
                        cxt.arc(ball.position.x, ball.position.y, ball.r, 0, Math.PI * 2, true);
                        cxt.closePath();
                        cxt.fill();
                        ball.position.x +=ball.vx * cyc / 1000;
                        ball.position.y +=ball.vy * cyc / 1000;
                        $await(Jscex.Async.sleep(cyc));
                      }
        while (ball.position.x > 100) {
                        cxt.fillStyle="rgba(0, 0, 0, .3)";
                        cxt.fillRect(0, 0, canvas.width, canvas.height);
                        cxt.fillStyle="#fff";
                        cxt.beginPath();
                        cxt.arc(ball.position.x, ball.position.y, 15, 0, Math.PI * 2, true);
                        cxt.closePath();
                        cxt.fill();
                        ball.position.x -=ball.vx * cyc / 1000;
                        ball.position.y -=ball.vy * cyc / 1000;
                        $await(Jscex.Async.sleep(cyc));
                      }
                  }
                }))
                moveAsync().start();

可以看到上面這段代碼共有3個while,從上到下依次無限循環執行下去,效果如圖2-2所示。

圖2-2 Canvas中模擬勻速運動的小球

倘若小球和四壁碰撞,就會發生反彈,反彈符合反射定律,如圖2-3所示。

圖2-3 反射定律

其中,入射角i與反射角r是相等的。所以在Canvas中模擬的結果就是:當小球與上下壁相撞時,Y軸速度方向變成其反方向,大小不變,X軸速度不變;當小球與左右兩壁碰撞時,X軸速度方向變成其反方向,大小不變,Y軸速度大小及方向都不變。可以得出:

        var canvas=document.getElementById("myCanvas");
        var cxt=canvas.getContext("2d");
        var ball={
                  x: 100,
                  y: 100,
                  r: 15,
                  vx: 190,
                  vy: 110
                };
        var cyc=10;
        var moveAsync=eval(Jscex.compile("async", function () {
        while (true) {
                        cxt.fillStyle="rgba(0, 0, 0, .3)";
                        cxt.fillRect(0, 0, canvas.width, canvas.height);
                        cxt.fillStyle="#fff";
                        cxt.beginPath();
                        cxt.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, true);
                        cxt.closePath();
                        cxt.fill();
        //與左右兩壁碰撞。
        if (ball.r+ball.x > canvas.width || ball.x < ball.r) ball.vx *=-1;
        //與上下兩壁碰撞。
        if (ball.r+ball.y > canvas.height || ball.y < ball.r) ball.vy *=-1;
                        ball.x +=ball.vx * cyc / 1000;
                        ball.y +=ball.vy * cyc / 1000;
                        $await(Jscex.Async.sleep(cyc));
                  }
                }))
                moveAsync().start();

這樣小球就永遠逃不出Canvas畫布的范圍了,當然這是碰撞的一種特殊情況,因為碰撞面分別與X軸和Y軸平行,所以處理起來非常方便。如果遇到任意碰撞面,就不能這么簡單地把方向設反,而要通過向量計算速度的變化,在后面的實驗中將解決這一問題。

主站蜘蛛池模板: 龙山县| 剑阁县| 龙口市| 镇宁| 晋宁县| 泗洪县| 灵寿县| 连南| 仲巴县| 溧阳市| 饶平县| 扶余县| 呈贡县| 太仆寺旗| 外汇| 乡城县| 慈溪市| 井冈山市| 鄂伦春自治旗| 新源县| 银川市| 章丘市| 临颍县| 嘉义市| 彩票| 包头市| 七台河市| 江陵县| 安仁县| 百色市| 灌阳县| 黎平县| 会东县| 南召县| 兴国县| 文安县| 根河市| 开阳县| 天门市| 湘潭县| 大同市|