如何使用three.js 制作一個(gè)三維的推箱子游戲
今天郭先生發(fā)現(xiàn)大家更喜歡看我發(fā)的three.js小作品,今天我就發(fā)一個(gè)3d版本推箱子的游戲,其實(shí)webGL有很多框架,three.js并不合適做游戲引擎,但是可以嘗試一些小游戲。在線案例請(qǐng)點(diǎn)擊
要制作一個(gè)推箱子游戲,正常要有以下4個(gè)步驟
- 定義一些數(shù)組,要有開(kāi)始箱子數(shù)組、結(jié)束箱子數(shù)組、地面數(shù)組還有墻面數(shù)組,有這四個(gè)數(shù)組就可以組成一個(gè)關(guān)卡。
- 根據(jù)數(shù)組初始化地面墻面箱子和目標(biāo)地點(diǎn)標(biāo)志物。
- 使用FirstPersonControls控制器,控制相機(jī)移動(dòng),根據(jù)地面箱子和墻面算出可移動(dòng)區(qū)域。
- 根據(jù)相機(jī)正對(duì)箱子時(shí),用鼠標(biāo)點(diǎn)擊箱子,控制箱子移動(dòng),并做成功性校驗(yàn)。
下面我們上代碼分析代碼
1. 定義數(shù)組
這四個(gè)數(shù)組分別是墻的數(shù)組、地面的數(shù)組、箱子初始位置數(shù)組和目標(biāo)數(shù)組。
wallArr = [[0, 0], [1, 0], [2, 0], [3, 0], [3, 1], [4, 1], [4, 2], [4, 3], [5, 3], [5, 4], [5, 5], [5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6], [0, 5], [0, 4], [0, 3], [0, 2], [0, 1]] scopeArr = [[1, 1], [2, 1], [1, 2], [2, 2], [3, 2], [1, 3], [2, 3], [1, 4], [4, 4], [1, 5], [2, 5], [3, 5], [4, 5]]; boxArr = [[3, 3], [2, 4], [3, 4]]; targetArr = [[2, 2], [1, 3], [2, 3]];
2. 根據(jù)箱子初始位置數(shù)組初始化箱子
initBox() { var textureBox = new THREE.TextureLoader().load("/static/images/base/crate.png"); if (boxGroup) { scene.remove(boxGroup) } boxGroup = new THREE.Group(); boxGroup.name = 'box_group' boxArr.forEach(d => { var boxGeom = new THREE.BoxGeometry(40, 40, 40); var boxMate = []; boxGeom.faces.forEach(d => boxMate.push(new THREE.MeshBasicMaterial({ map: textureBox }))) var boxMesh = new THREE.Mesh(boxGeom, boxMate); boxMesh.position.set(d[0] * 40 - 20, 20, d[1] * 40 - 20); boxMesh.name = 'box'; boxGroup.add(boxMesh); }) scene.add(boxGroup); //判斷是否贏得比賽 this.isWinner(boxArr, targetArr) }
3. 根據(jù)地面數(shù)組初始化地面
initGround() { var textureGround = new THREE.TextureLoader().load("/static/images/wall/plaster.jpg", () => {this.loaded_num --}); var textureGroundNormal = new THREE.TextureLoader().load("/static/images/wall/plaster-normal.jpg", () => {this.loaded_num --}); var textureGroundSpecular = new THREE.TextureLoader().load("/static/images/wall/plaster-diffuse.jpg", () => {this.loaded_num --}); textureGround.wrapS = textureGround.wrapT = THREE.RepeatWrapping; textureGround.repeat.set(50, 50); textureGroundNormal.wrapS = textureGroundNormal.wrapT = THREE.RepeatWrapping; textureGroundNormal.repeat.set(50, 50); var materialGround = new THREE.MeshPhongMaterial({ map: textureGround }) materialGround.normalMap = textureGroundNormal; materialGround.specularMap = textureGroundSpecular; var ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 1, 1), materialGround); ground.rotation.x = - Math.PI / 2; scene.add(ground); }
4. 根據(jù)墻數(shù)組初始化地面
initWall() { var normal = new THREE.TextureLoader().load("/static/images/wall/stone.jpg", () => {this.loaded_num --}); var bump = new THREE.TextureLoader().load("/static/images/wall/stone-bump.jpg", () => {this.loaded_num --}); wallArr.forEach(d => { var wallBox = new THREE.BoxGeometry(40, 40, 40); var material = new THREE.MeshPhongMaterial({ map: normal, bumpMap: bump, bumpScale: 1 }) var wall = new THREE.Mesh(wallBox, material); wall.position.x = d[0] * 40 - 20; wall.position.y = 20; wall.position.z = d[1] * 40 - 20; scene.add(wall); }) }
5. 根據(jù)目標(biāo)數(shù)組初始化目標(biāo)物
initTarget() { let objLoader = new OBJLoader(); objLoader.setPath("/static/images/texture/hongqi/"); objLoader.load('hongqi.obj', (object) => { this.loaded_num --; let hongqi = object.children[0]; targetArr.forEach(d => { hongqi.position.set(d[0] * 40 - 20, -50, d[1] * 40 - 20) hongqi.scale.set(0.12, 0.12, 0.12) hongqi.material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide }); scene.add(hongqi.clone()) }) }) }
6. 監(jiān)聽(tīng)箱子的點(diǎn)擊事件
每次點(diǎn)擊的時(shí)候執(zhí)行computeMove方法,判斷如果是否可移動(dòng)。
initEventListener() { raycaster = new THREE.Raycaster(); document.addEventListener('mousemove', function (event) { event.preventDefault(); mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; }, false) document.addEventListener('click', () => { if (scene.children && scene.getObjectByName('box')) { raycaster.setFromCamera(mouse, camera); let intersects = raycaster.intersectObjects(scene.getObjectByName('box_group').children); if (intersects[0] && intersects[0].object.name == 'box') { this.computeMove(intersects[0].object, camera.position); } } }) }
7. 監(jiān)聽(tīng)游戲成功
如果成功了,那么簡(jiǎn)單的彈出提示。
isWinner(arr1, arr2) { let boo = true; //true為贏 arr1.forEach(d => { let res = arr2.some(dd => { return d[0] == dd[0] && d[1] == dd[1] }) if(!res) { boo = false; } }) if(boo) { setTimeout(() => { alert('恭喜你贏了!') },100) } }
由于當(dāng)時(shí)做這個(gè)小案例時(shí)還是菜鳥(niǎo),所以很少用一些three.js的輔助方法,見(jiàn)笑了。
以上就是如何使用three.js 制作一個(gè)三維的推箱子游戲的詳細(xì)內(nèi)容,更多關(guān)于three.js 制作推箱子游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript DOM設(shè)置樣式詳細(xì)說(shuō)明和示例代碼
JavaScript也可以用來(lái)修改DOM元素的樣式,我們可以使用style屬性來(lái)訪問(wèn)和修改元素的樣式屬性,這篇文章主要給大家介紹了關(guān)于javascript DOM設(shè)置樣式詳細(xì)說(shuō)明和示例代碼的相關(guān)資料,需要的朋友可以參考下2024-06-06JS實(shí)現(xiàn)點(diǎn)擊下拉菜單把選擇的內(nèi)容同步到input輸入框內(nèi)的實(shí)例
下面小編就為大家分享一篇JS實(shí)現(xiàn)點(diǎn)擊下拉菜單把選擇的內(nèi)容同步到input輸入框內(nèi)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01基于JavaScript實(shí)現(xiàn)電子簽名功能
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)JavaScript實(shí)現(xiàn)簡(jiǎn)單的電子簽名功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-11-11用ASP將SQL搜索出來(lái)的內(nèi)容導(dǎo)出為T(mén)XT的代碼
用ASP將SQL搜索出來(lái)的內(nèi)容導(dǎo)出為T(mén)XT的代碼...2007-07-07showModalDialog模態(tài)對(duì)話框的使用詳解以及瀏覽器兼容
showModalDialog是jswindow對(duì)象的一個(gè)方法,和window.open一樣都是打開(kāi)一個(gè)新的頁(yè)面。區(qū)別是:showModalDialog打開(kāi)子窗口后,父窗口就不能獲取焦點(diǎn)了(也就是無(wú)法操作了)2014-01-01