昨天拆出了 ui.js 和 scene.js:ui.js 負責用 HTML DOM 取出和畫面顯示有關的元素(提示框),scene.js 負責 Three.js 和模型取景相關的東西(scene、camera、controls……)。
今天把這兩個檔案的功能補齊,切得更細:
scene.js 多了兩個函式:enableResize()(視窗縮放)和 startRenderLoop()(動畫迴圈)ui.js 多了結算面板的控制:showResult() 和 hideResult()
切完之後,main.js 大概只剩一百行出頭,可以很清楚地看出主要脈絡:載入模型的行為,加上兩個事件監聽。
這兩個函式,就是原本寫在 main.js 裡的縮放事件和動畫迴圈,包成函式搬進來:
export function enableResize(camera, renderer, controls) {
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
controls.handleResize();
});
}
export function startRenderLoop(scene, camera, renderer, controls) {
renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});
}
兩個函式的參數,都是 createScene() 回傳的物件。因為 camera、renderer、controls 是 createScene() 裡的區域變數,main.js 要用,就得把它們傳進去,所以 main.js 的呼叫是:
const {scene, camera, renderer, controls} = createScene();
enableResize(camera, renderer, controls);
startRenderLoop(scene, camera, renderer, controls)
const toast = document.getElementById('toast');
const resultPanel = document.getElementById('result');
const resultTime = document.getElementById('result-time');
let toastTimer;
export function showToast(message, duration = 2500) {
toast.textContent = message;
toast.classList.add('show');
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
toast.classList.remove('show');
}, duration);
}
export function showResult(seconds) {
resultTime.textContent = `用時 ${seconds} 秒`;
resultPanel.classList.add('show');
}
export function hideResult() {
resultPanel.classList.remove('show');
}
showResult(seconds) 負責在結算面板顯示用時,「用時 X 秒」這句話寫在 ui.js 裡,main.js 只要把數字傳進來。畫面上的文字屬於 UI,不該散在 main.js。
為了不讓程式碼佔許多版面,有興趣的讀者,可以自行到 GitHub 上研究全部的資訊內容
昨天畫了一張規畫圖,今天依 GitHub 上最新的程式碼,畫了一張現況圖。依今天的為主,搭配程式碼參考。
程式碼切割本來就沒有一個標準答案,這在於對於程式碼架構/分類的想法
所以圖只是供讀者參考
鐵人賽系列的文章,走了 2/3,已經接近尾聲,整理一下接下來的規畫
blender_output.glb 目前已經放在 repo 裡(約 50 MB),之後打算換成 3D 版模型,然後優化模型的樣貌;現在的模型是使用任務 2D map 飛行,所以有物件中間鏤空的問題,想看 3D 流程走一遍後,是否能解決.glb