如何利用Three.js實(shí)現(xiàn)跳一跳小游戲
前言
跳一跳是微信小程序的一個(gè)小游戲。長(zhǎng)按屏幕讓小人蓄力跳躍,進(jìn)行游玩。按照小人跳躍盒子的數(shù)量,以及特殊盒子加分項(xiàng)計(jì)算得分。
游戲地址:不會(huì)搞(所以沒(méi)放)git地址:gitee.com/fwjzzz/Jump
游戲規(guī)則
十分簡(jiǎn)單:長(zhǎng)按鼠標(biāo)蓄力、放手,方塊就會(huì)從一個(gè)盒子跳到另一個(gè)盒子。然而就是這個(gè)小動(dòng)作,讓你一旦開(kāi)始就魔性地停不下來(lái)。
Three.js
Three.js 是一款運(yùn)行在瀏覽器中的 3D 引擎,你可以用它創(chuàng)建各種三維場(chǎng)景,包括了攝影機(jī)、光影、材質(zhì)等各種對(duì)象。
- 創(chuàng)建一個(gè)場(chǎng)景
- 設(shè)置光源
- 創(chuàng)建相機(jī),設(shè)置相機(jī)位置和相機(jī)鏡頭的朝向
- 創(chuàng)建3D渲染器,使用渲染器把創(chuàng)建的場(chǎng)景渲染出來(lái)
整個(gè)程序的結(jié)構(gòu)
實(shí)現(xiàn)
html文件引入three.js引擎
<script src="/js/three.min.js"></script>
頁(yè)面結(jié)構(gòu)
<div class="mask"> <div class="content"> <div class="score-container"> <p class="title">本次得分</p> <h1 class="score">0</h1> </div> <button class="restart"> 重新開(kāi)始 </button> </div> </div> <div class="info"> <audio loop="loop" autoplay controls src="https://m801.music.126.net/20220413225245/3060206bc37e3226b7f45fa1 49b0fb2b/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/13866197954/e351/984c/1f8b/f6d3165d6b04dc78ec0d3c273ce02ff2.mp3"> </audio> <div class="gaming-score"> 得分:<span class="current-score">0</span> </div> </div>
場(chǎng)景
let scene=new THREE.Scene(); //創(chuàng)建一個(gè)場(chǎng)景
相機(jī)
常用的相機(jī)有兩種:
- 透視相機(jī)PerspectiveCamera
符合人心理習(xí)慣,近大遠(yuǎn)小。
- 正視相機(jī)OrthographicCamera
遠(yuǎn)處和近處一樣大
let camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,1,1000); //創(chuàng)建一個(gè)透視相機(jī) 4個(gè)參數(shù)(視覺(jué)范圍,寬高比例,近距離,遠(yuǎn)距離) camera.position.z=10; camera.position.y=3; camera.position.x=8; //相機(jī)的xyz場(chǎng)景方向
幾何體
使用CubeGeometry創(chuàng)建一個(gè)立方幾何體,使用MeshLambertMaterial材質(zhì)用來(lái)配置立方體渲染看上去暗淡不光亮的表面,該材質(zhì)會(huì)對(duì)場(chǎng)景中的光源產(chǎn)生反應(yīng),這個(gè)材質(zhì)可以配置一些其他屬性如:顏色等。
let geometry=new THREE.CubeGeometry(4,2,4); //創(chuàng)建一個(gè)幾何體對(duì)象 (寬,高,深度) let material=new THREE.MeshLambertMaterial({color:0xbebebe}); //創(chuàng)建了一個(gè)可以用于立方體的材質(zhì),對(duì)象包含了顏色、透明度等屬性, let cube=new THREE.Mesh(geometry,material); //結(jié)合在一起 cube.position.x=16; scene.add(cube); //添加到場(chǎng)景中
光源
場(chǎng)景Scene主要是由幾何體模型和光Light構(gòu)成,在實(shí)際開(kāi)發(fā)過(guò)程中,大多數(shù)三維場(chǎng)景往往需要設(shè)置光源,通過(guò)不同的光源對(duì)模型模擬生活中的光照效果,尤其是為了提高Threejs的渲染效果更需要設(shè)置好光源,就像攝影師拍照要打燈一樣。
let directionalLight=new THREE.DirectionalLight(0xffffff,1.1); //平行光 (顏色,強(qiáng)度) directionalLight.position.set(3,10,5); //平行光位置 scene.add(directionalLight); //在場(chǎng)景中加入平行光 let light=new THREE.AmbientLight(0xffffff,0.4); //光的材質(zhì) scene.add(light); //把光添加到場(chǎng)景
渲染
直接通過(guò)WebGL渲染器WebGLRenderer的.setSize()
方法設(shè)置渲染尺寸為瀏覽器body區(qū)域?qū)捀叨取?/p>
let renderer=new THREE.WebGLRenderer({antialias:true}); //創(chuàng)建一個(gè)渲染器 (讓邊緣動(dòng)畫(huà)沒(méi)有鋸齒感) renderer.setSize(window.innerWidth,window.innerHeight); // 畫(huà)布寬高 renderer.setClearColor(0x282828); //修改畫(huà)布顏色 renderer.render(scene,camera); //渲染場(chǎng)景相機(jī) (后續(xù)更新也是這里) document.body.appendChild(renderer.domElement); //把當(dāng)前渲染的畫(huà)布放到body里面 let x=8; function render() { //遞歸 x-=0.1; camera.position.x=x; renderer.render(scene,camera); //更新重新渲染 if(x>=-8){ //滿足當(dāng)前條件 requestAnimationFrame(render) //循環(huán)渲染 } }
目前為止實(shí)現(xiàn)了一個(gè)雛形
添加第二塊
_createCube() { let geometry = new THREE.CubeGeometry(this.config.cubeWidth, this.config.cubeHeight, this.config.cubeDeep); //創(chuàng)建一個(gè)幾何體對(duì)象 (寬,高,深度) let material = new THREE.MeshLambertMaterial({ color: this.config.cubeColor }); //材質(zhì),對(duì)象包含了顏色、透明度等屬性, let cube = new THREE.Mesh(geometry, material); //合并在一起 if (this.cubes.length) { //從第二塊開(kāi)始隨機(jī)左右方向出現(xiàn) cube.position.x = this.cubes[this.cubes.length - 1].position.x; cube.position.y = this.cubes[this.cubes.length - 1].position.y; cube.position.z = this.cubes[this.cubes.length - 1].position.z; this.cubeStat.nextDir = Math.random() > 0.5 ? "left" : "right"; //要不左邊要不右邊 if (this.cubeStat.nextDir == "left") { //左邊改變x軸否則y軸 cube.position.x = cube.position.x - Math.round(Math.random() * 4 + 6); } else { cube.position.z = cube.position.z - Math.round(Math.random() * 4 + 6); } } this.cubes.push(cube); //統(tǒng)一添加塊 if (this.cubes.length > 5) { //頁(yè)面最多看到5個(gè)塊 this.scene.remove(this.cubes.shift()); //超過(guò)就移除 } this.scene.add(cube); //添加到場(chǎng)景中 if (this.cubes.length > 1) { //更新鏡頭位置 this._updateCameraPros(); } };
定義一個(gè)方塊數(shù)組,判斷從第二塊開(kāi)始向左右兩邊隨機(jī)出現(xiàn)。this.cubeStat.nextDir = Math.random() > 0.5 ? "left" : "right"
如上圖:(這是由兩張圖組成的)
跳塊
_createJumper() { let geometry = new THREE.CubeGeometry(this.config.jumperWidth, this.config.jumperHeight, this.config .jumperDeep); // (寬,高,深度) let material = new THREE.MeshLambertMaterial({ color: this.config.jumperColor }); //材質(zhì),顏色、透明度 this.jumper = new THREE.Mesh(geometry, material); //合并在一起 this.jumper.position.y = 1; //顯示跳塊 geometry.translate(0, 1, 0); //平移 this.scene.add(this.jumper); //添加到場(chǎng)景中 }
使用Geometry幾何體對(duì)象有一系列的頂點(diǎn)屬性和方法,通過(guò).scale()
、.translate()
、.rotateX()
等方法可以對(duì)幾何體本身進(jìn)行縮放、平移、旋轉(zhuǎn)等幾何變換。注意本質(zhì)上都是改變結(jié)合體頂點(diǎn)位置坐標(biāo)數(shù)據(jù)。
鼠標(biāo)按下?tīng)顟B(tài)
this.jumperStat = { //鼠標(biāo)按下速度 ready: false, xSpeed: 0, ySpeed: 0 };
_handleMouseDown() { if (!this.jumperStat.ready && this.jumper.scale.y > 0.02) { this.jumper.scale.y -= 0.01; //壓縮塊 this.jumperStat.xSpeed += 0.004; this.jumperStat.ySpeed += 0.008; this._render(); requestAnimationFrame(() => { this._handleMouseDown() }) } };
鼠標(biāo)松開(kāi)彈起狀態(tài)
人生不就是這樣嗎?只要你跳對(duì)了位置,就能夠“逆襲”!
//鼠標(biāo)松開(kāi)談起狀態(tài) _handleMouseUp() { this.jumperStat.ready = true; if (this.jumper.position.y >= 1) { if (this.jumper.scale.y < 1) { this.jumper.scale.y += 0.1; //壓縮狀態(tài)小于1就+ } if (this.cubeStat.nextDir == "left") { //挑起盒子落在哪里 this.jumper.position.x -= this.jumperStat.xSpeed; } else { this.jumper.position.z -= this.jumperStat.xSpeed; } this.jumper.position.y += this.jumperStat.ySpeed; this.jumperStat.ySpeed -= 0.01; //上升落下?tīng)顟B(tài) this._render(); requestAnimationFrame(() => { //循環(huán)執(zhí)行 this._handleMouseUp(); }) } else { //落下?tīng)顟B(tài) this.jumperStat.ready = false; this.jumperStat.xSpeed = 0; this.jumperStat.ySpeed = 0; this.jumper.position.y = 1; this.jumper.scale.y = 1; this._checkInCube(); //檢測(cè)落在哪里 if (this.falledStat.location == 1) { //下落后等于1,+分?jǐn)?shù) this.score++; this._createCube(); this._updateCamera(); if (this.successCallback) { //否則失敗 this.successCallback(this.score); } } else { this._falling() } } };
落在哪里
學(xué)會(huì)控制速度感是非常奇妙的事情。當(dāng)你慢下來(lái)了,學(xué)會(huì)控制速度。因?yàn)樵诿恳粋€(gè)過(guò)程當(dāng)中,都有你生命中值得停下來(lái)瀏覽、欣賞、感受的事物。在我們的認(rèn)知中,總覺(jué)得越快,擁有的時(shí)間就越多,效率就越高,生產(chǎn)力就提高。其實(shí)并不是。如果你的頭腦常常處在思維高速運(yùn)轉(zhuǎn)的狀態(tài),一定會(huì)感覺(jué)繁忙且毫無(wú)頭緒;如果你總是擔(dān)心著未來(lái)或者掛念過(guò)去,就無(wú)法專注在當(dāng)下所做的事,也一定感到時(shí)間不夠用,效率大大降低。
this.falledStat = { location: -1, //落在哪里 當(dāng)前塊塊上 distance: 0, //距離是否倒下 }; this.fallingStat = { //有沒(méi)有落到點(diǎn) end: false, speed: 0.2 }
//檢測(cè)落在哪里 //-1 -10從當(dāng)前盒子掉落 //1 下一個(gè)盒子上 10從下一個(gè)盒子上掉落 //0沒(méi)有落在盒子上 _checkInCube() { let distanceCur, distanceNext; //當(dāng)前盒子距離 下一個(gè)盒子距離 let should = (this.config.jumperWidth + this.config.cubeWidth) / 2; // if (this.cubeStat.nextDir == "left") { //往左走了 distanceCur = Math.abs(this.jumper.position.x - this.cubes[this.cubes.length - 2].position.x); distanceNext = Math.abs(this.jumper.position.x - this.cubes[this.cubes.length - 1].position.x); } else { //往右走了 distanceCur = Math.abs(this.jumper.position.z - this.cubes[this.cubes.length - 2].position.z); distanceNext = Math.abs(this.jumper.position.z - this.cubes[this.cubes.length - 1].position.z); } if (distanceCur < should) { //落在當(dāng)前塊 this.falledStat.distance = distanceCur; this.falledStat.location = distanceCur < this.config.cubeWidth / 2 ? -1 : -10; } else if (distanceNext < should) { //落在下一個(gè)塊上 this.falledStat.distance = distanceNext; this.falledStat.location = distanceNext < this.config.cubeWidth / 2 ? 1 : 10; } else { //落在中間 this.falledStat.location = 0; } };
落到方塊上,停上一會(huì)兒,放松自己,亦會(huì)有十分的額外獎(jiǎng)勵(lì)。人生路上,匆匆忙忙趕路的時(shí)候,不要忘了適度休息調(diào)整,你會(huì)有意外地收獲,命運(yùn)的魔方會(huì)給你別致的驚喜。人生很短,何須急著走完。
//下落過(guò)程 _falling() { if (this.falledStat.location == 10) { //從下一個(gè)盒子落下 if (this.cubeStat.nextDir == "left") { //判斷左方向 if (this.jumper.position.x > this.cubes[this.cubes.length - 1].position.x) { this._fallingRotate("leftBottom") } else { this._fallingRotate("leftTop") } } else { //判斷右方向 if (this.jumper.position.z > this.cubes[this.cubes.length - 1].position.z) { this._fallingRotate("rightBottom") } else { this._fallingRotate("rightTop") } } } else if (this.falledStat.location == -10) { //從當(dāng)前盒子落下 if (this.cubeStat.nextDir == "left") { this._fallingRotate("leftTop") } else { this._fallingRotate("rightTop") } } else if (this.falledStat.location == 0) { this._fallingRotate("none") } };
結(jié)尾
贏也好,輸也罷,人生就是一個(gè)起起伏伏的過(guò)程,處在巔峰不驕,跌落低谷不餒。這才是正確的人生姿勢(shì)。當(dāng)然,這里不僅僅說(shuō)的是游戲。有可能是埋頭玩游戲的你,也許你早注意到那個(gè)小方塊的玩家形象,就是生活中的“ 自己 ”。這個(gè)世界就如 “跳一跳” 游戲:規(guī)則和目標(biāo)都明確的智力游戲,玩家可以自由地行動(dòng),站對(duì)位置就可以加分。時(shí)時(shí)輕拂拭,勿使惹塵埃。便可有收獲,享受生活,熱愛(ài)人世間的煙火?。?!
到此這篇關(guān)于如何利用Three.js實(shí)現(xiàn)跳一跳小游戲的文章就介紹到這了,更多相關(guān)Three.js跳一跳小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript實(shí)現(xiàn)頁(yè)面電子時(shí)鐘
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)頁(yè)面電子時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06javascript經(jīng)典特效分享 手風(fēng)琴、輪播圖、圖片滑動(dòng)
這篇文章主要介紹了javascript經(jīng)典特效,手風(fēng)琴、輪播圖、圖片滑動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09ajax java 實(shí)現(xiàn)自動(dòng)完成功能
都知道百度建議是用ajax做的,想要做的快速穩(wěn)定,可復(fù)制可移植就不容易了,花時(shí)間研究還不如自己來(lái)寫(xiě)。根據(jù)一個(gè)pdf文檔提供的資料,用了小半天時(shí)間,終于實(shí)現(xiàn)了。在此與大家分享2012-12-12JS中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼
這篇文章主要介紹了JS中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼,也是json的入門知識(shí),需要的朋友可以參考下2018-05-05用console.table()調(diào)試javascript
昨天我了解到Chrome調(diào)試工具一個(gè)小巧的調(diào)試方法,在WDCC期間, Marcus Ross(@zahlenhelfer) 介紹了,chrome調(diào)試工具各種調(diào)試方法,這個(gè)只是其中一種,現(xiàn)在我來(lái)給大家秀下。2014-09-09js獲取iframe中的window對(duì)象的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇JS獲得iframe中的window對(duì)象的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05JavaScript中如何對(duì)多維數(shù)組(矩陣)去重的實(shí)現(xiàn)
這篇文章主要介紹了JavaScript中如何對(duì)多維數(shù)組(矩陣)去重的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12javascript 兼容所有瀏覽器的DOM擴(kuò)展功能
技術(shù)文章寫(xiě)得少,所以有時(shí)候想寫(xiě)點(diǎn)什么卻下不了手,不知道該寫(xiě)什么;往往到了準(zhǔn)備要寫(xiě)的時(shí)候才發(fā)現(xiàn)自己想寫(xiě)的東西其實(shí)很無(wú)聊,甚至覺(jué)得很幼稚,于是又關(guān)掉了編緝器2012-08-08JSONP獲取Twitter和Facebook文章數(shù)的具體步驟
這篇文章主要介紹了JSONP獲取Twitter和Facebook文章數(shù)的方法,需要的朋友可以參考下2014-02-02