PlayCanvas — WebXR 3D 戰神
PlayCanvas 是 100% Web 技術 打造的即時 3D 引擎,兼具 VR / AR 支援與雲端協作。其瀏覽器即開發環境(熱重載、多人編輯)讓團隊能在任何地方快速迭代、立即佈署。
核心特色
- 雲端 IDE:專案、程式、素材全在線協作,改一行即時更新。
- WebXR Ready:一套程式,同時跑桌機、行動、VR、AR。
- 物理引擎整合:Ammo.js 內建,支援剛體、碰撞、車輛組件。
- 輕量高效:引擎核心不到 500 KB(gzip 後),載入極快。
- REST 發佈 API:CLI 或 GitHub Action 自動推版本、一鍵佈署。
- 多材質渲染:PBR、光照貼圖、Area Lights、粒子系統。
10 個實戰範例
1. 旋轉立方體 入門
最小可執行範例,建立一個場景、攝影機與持續旋轉的立方體。
// 建立 Canvas
const canvas1 = document.createElement('canvas');
canvas1.id = 'canvas1';
document.body.appendChild(canvas1);
// 建立 APP
const app1 = new pc.Application(canvas1, {
mouse: new pc.Mouse(document.body),
keyboard: new pc.Keyboard(window)
});
app1.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app1.setCanvasResolution(pc.RESOLUTION_AUTO);
window.addEventListener('resize', () => app1.resizeCanvas());
// 場景基本設定
app1.scene.ambientLight = new pc.Color(0.4, 0.4, 0.4);
// 創建攝影機
const camera1 = new pc.Entity();
camera1.addComponent('camera', { clearColor: new pc.Color(0.1, 0.1, 0.1) });
camera1.setPosition(0, 0, 3);
app1.root.addChild(camera1);
// 創建立方體
const cube1 = new pc.Entity();
cube1.addComponent('model', { type: 'box' });
app1.root.addChild(cube1);
// 每禎旋轉
app1.on('update', dt => { cube1.rotate(30 * dt, 45 * dt, 0); });
// 啟動
app1.start();
2. 點擊換材質 互動
示範基本事件繫結,點擊模型切換顏色。
const canvas2 = document.createElement('canvas');
canvas2.id = 'canvas2';
document.body.appendChild(canvas2);
const app2 = new pc.Application(canvas2, {
mouse: new pc.Mouse(document.body),
keyboard: new pc.Keyboard(window)
});
app2.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app2.setCanvasResolution(pc.RESOLUTION_AUTO);
window.addEventListener('resize', () => app2.resizeCanvas());
app2.scene.ambientLight = new pc.Color(0.4, 0.4, 0.4);
const camera2 = new pc.Entity();
camera2.addComponent('camera', { clearColor: new pc.Color(0.1, 0.1, 0.1) });
camera2.setPosition(0, 0, 3);
app2.root.addChild(camera2);
const cube2 = new pc.Entity();
cube2.addComponent('model', { type: 'box' });
app2.root.addChild(cube2);
const colors = [new pc.Color(1, 0, 0), new pc.Color(0, 1, 0), new pc.Color(0, 0, 1)];
let idx = 0;
cube2.model.meshInstances[0].material = new pc.StandardMaterial();
cube2.model.meshInstances[0].material.diffuse = colors[idx];
cube2.model.meshInstances[0].material.update();
app2.mouse.on('mousedown', () => {
idx = (idx + 1) % colors.length;
cube2.model.meshInstances[0].material.diffuse = colors[idx];
cube2.model.meshInstances[0].material.update();
});
app2.start();
3. 掉落木箱堆 物理
使用剛體與碰撞組件產生真實掉落效果(需引入 Ammo.js)。
const canvas3 = document.createElement('canvas');
canvas3.id = 'canvas3';
document.body.appendChild(canvas3);
const app3 = new pc.Application(canvas3, {
mouse: new pc.Mouse(document.body),
keyboard: new pc.Keyboard(window)
});
app3.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
app3.setCanvasResolution(pc.RESOLUTION_AUTO);
window.addEventListener('resize', () => app3.resizeCanvas());
app3.scene.ambientLight = new pc.Color(0.4, 0.4, 0.4);
const camera3 = new pc.Entity();
camera3.addComponent('camera', { clearColor: new pc.Color(0.1, 0.1, 0.1) });
camera3.setPosition(0, 5, 10);
app3.root.addChild(camera3);
function addBox(x, y, z) {
const box = new pc.Entity();
box.addComponent('model', { type: 'box' });
box.addComponent('collision', { type: 'box' });
box.addComponent('rigidbody', { type: 'dynamic', mass: 1 });
box.setPosition(x, y, z);
app3.root.addChild(box);
}
const floor = new pc.Entity();
floor.addComponent('model', { type: 'box' });
floor.addComponent('collision', { type: 'box', halfExtents: new pc.Vec3(5, 0.1, 5) });
floor.addComponent('rigidbody', { type: 'static' });
floor.setLocalScale(10, 0.2, 10);
app3.root.addChild(floor);
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
addBox(i - 2, 5 + j, j - 2);
}
}
app3.start();
注意:需額外引入 Ammo.js 物理引擎才能運行。