iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 25
2
Modern Web

PixiJS,方便好用的 WebGL 內容產生工具系列 第 25

[PixiJS - Day-25] 實作:基本繪圖、動態與使用 dat.GUI 測試

作為第一個介紹的實作,實作對象是這個 Gif:
alt

出處是 FB 上的某處,這張圖的微妙在數學
簡諧運動的球,在複製並平均分配到不同角度後,組成的大球也像在規律滾動

實作時一步步的想法:

Step1. 畫出線段與球:

  • 畫出一顆球與線段
  • 放進場景上
  • 將場景放到畫面正中間

**Step2. 讓球動:**由於不需要複雜的運動,直接寫在 app.ticker 的呼叫裡就好

**Step3. 複製線段與球:**依據設定,將線段與球等分複製到不同角度

**Step4. 調整運動的參數:**不同的線段裡的球,簡諧運動的參數不太相同

Step5. 加入調整介面: Gif 裡的球會自動增加.我的實作則是使用 dat.GUI 來手動調整球與線段的數量


Step1. 畫出線段與球:
alt

// 初始化一個 800 x 600 大小的 PIXI.Application
var app = new PIXI.Application(800, 600, {backgroundColor : 0xEEEEEE});
document.body.appendChild(app.view);

// 本例子適合把 stage 放在畫面正中間
app.stage.x = app.renderer.width * 0.5;
app.stage.y = app.renderer.height * 0.5;

// 建立容器
var objContainer = new PIXI.Container();
app.stage.addChild(objContainer);

// 畫球
var ball = new PIXI.Graphics();
ball.beginFill(0x000000, .3);
ball.drawCircle(0, 0, 10);
ball.endFill();

// 畫線
var objLine = new PIXI.Graphics();
objLine.lineStyle ( 1, 0x000000 , 0.3);
objLine.moveTo(-400, 0);
objLine.lineTo(400, 0);

objContainer.addChild(ball);
objContainer.addChild(objLine);

Step2. 讓球動:
alt

var tk = 0;
app.ticker.add(function(delta) {
    tk ++;
    if(tk == 360) { tk = 0; };
    //讓球做簡諧運動
    ball.x = Math.sin(tk  / (180 / Math.PI)) * (800 * 0.5);
});

由於 Math.sin 會回傳 -1~1,很適合用做簡諧運動的公式
800 是 PIXI.Application 的寬
800 * 0.5 是球會運動到左右邊界,也就是 -400 ~ 400 之間


Step3. 複製線段與球:
alt
將線段與球平均複製與旋轉到各個角度 (此時球還是同進同出)

var objCount = 9; // 會複製九段線與球
for(var i=1; i<objCount +1; i++){
	this["objContainer"+i] = new PIXI.Container();
// … 畫出球與線段的部分與前面相同
	this["objContainer"+i].rotation = (360 / objCount) * (i-1) * (Math.PI / 180);
	stage.addChild(this["objContainer"+i]);
}

角度轉弧度 的方法可能會比較不習慣
假設要轉90度,寫法是:

90 * (Math.PI / 180);

Step4. 調整運動的參數
不同線段裡的球,簡諧運動的參數不太相同
alt

var tk = 0;
app.ticker.add(function(delta) {
    tk ++;
    if(tk == 360) { tk = 0; };
    for(var i=1; i < objCount + 1; i++){
    app.stage.children[i].children[1].x= 800 * Math.sin(( tk + (360 / objCount) * i )  / (180 / Math.PI)) * 0.5;
    }
});

這段是數學,由於這個例子的簡諧運動公式是 Math.sin(tk / (180 / Math.PI)) * (800 * 0.5);
而 tk 會隨著時間遞增並取 / 360 後的餘數;

三組線段與球的例子來說,結果會是:
Math.sin(tk + 0 / (180 / Math.PI)) * (800 * 0.5);
Math.sin(tk + 120 / (180 / Math.PI)) * (800 * 0.5);
Math.sin(tk + 240 / (180 / Math.PI)) * (800 * 0.5);

歸納起來就是 Math.sin(( tk + (360 / objCount) * i ) / (180 / Math.PI)) 了

Step5. 加入調整介面:
alt
Step5-1. 頁面上匯入 dat.gui.js:<script src='js/libs/dat.gui.min.js'></script>
Step5-2. 頁面裡的程式碼:

var gui = new dat.GUI();
var effectController = {
    objCount: objCount
};

// 滑動的 controller,拖動範圍為 3~15,間隔為1
gui.add( effectController, "objCount", 3, 15, 1 ).onChange( countChange );

function countChange(){ // 拖動時會執行的程式
	rebuildObjs();
};

function rebuildObjs(){
    ... //把頁面上的元件都清掉,並重新複製線段與線
}

alt
gui.add( effectController, "objCount", 3, 15, 1 ).onChange( countChange );
controller 對應到 effectController 裡的 objCount 物件,最小值 3,最大值 15,每次拖動的間隔為 1;拖動結果為 3, 4, 5, 6… 15
當 controller 有變動時呼叫 countChange 方法

將 dat.GUI 實體 New 出來後,加入 controller 並設定事件即可
不用調整 HTML,也不用寫CSS


因為是實做的第一篇,不太容易拿捏要講的內容,
示範的程式碼並不是最終的程式碼.程式碼都放上來會很長並且混亂

最後結果:
http://eia.github.io/pixijs/170317/
alt
省略部分:
resize:
頁面上放上 resize 的事件監聽即可,resize 後需再設定 app.stage 的位置,將畫面置中
app.stage.x = app.renderer.width * 0.5;
app.stage.y = app.renderer.height * 0.5;

手機處理:

  • 手機旋轉,因為線段與球的邊界其實是頁面長寬裡比較短的邊,所以多給了一個變數並在 resize 時更新
  • 手機版調整 app.stage 的 scale 為 2

顏色調整:
讓結果與原 Gif 更相近


本文用到的一些方法,如有不太清楚的話可以參考先前的文章:


上一篇
[PixiJS - Day-24] 在專案上運用 PixiJS,以及各版本瀏覽器相容的作法
下一篇
[PixiJS - Day-26] 實作:PixiJS 也能做功能? 之合圖上傳
系列文
PixiJS,方便好用的 WebGL 內容產生工具31

1 則留言

0
cythilya
iT邦新手 4 級 ‧ 2017-12-28 09:37:04

/images/emoticon/emoticon58.gif

/images/emoticon/emoticon13.gif

我要留言

立即登入留言