WEBGL学习笔记(七):实践练手1-飞行类小游戏之游戏控制
接上一节,游戏控制首先要解决的就是碰撞检测了
这里用到了学习笔记(三)射线检测的内容了
以鸟为射线原点,向前、上、下分别发射3个射线,射线的长度较短大概为10~30.
根据上一节场景的建设,我把y轴设为前进方向,z轴设为高度~
如果射线返回有结果,那么说明鸟遇到了障碍物。代码如下:
var raycaster1 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 1, 0), 0, 30) var raycaster2 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 0, 1), 0, 10) var raycaster3 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 0, -1), 0, 10) // var intersections1 = raycaster1.intersectObjects(objects); var intersections2 = raycaster2.intersectObjects(objects); var intersections3 = raycaster3.intersectObjects(objects); //如果前方有物体,向前速度为0 if (intersections1.length > 0) { velocity.y = 0; } //如果上方有物体,向上速度为0或为负值 if (intersections2.length > 0 ) { if (velocity.z > 0) { velocity.z = 0; } } //如果下方有物体,向下速度为0或为正值 if (intersections3.length > 0) { if (velocity.z < 0) { velocity.z = 0; } } if (birdmesh.position.z < 10) { birdmesh.position.z = 10; } if (birdmesh.position.z > 575) { birdmesh.position.z = 575; } if (velocity.y==0) { alert('您已死亡!'); }
其次需要解决的就是飞行前进和重力下降的问题
首先新建一个
var velocity = new THREE.Vector3();
用velocity.x和.y以及.z来表示像3个方向的速度。
y方向为前进方向,给定一个固定值就行,检测到碰撞停止。
x方向不用管,因为x方向没有运动。
z方向为高度方向,要做到鼠标点击飞高一段距离,然后重力下降。
首先鼠标点击给定一个固定的向上的速度,然后速度加速递减(重力效果),代码如下
window.addEventListener('mousedown', function (event) {
velocity.z = 500;
mixer.clipAction(clip).setDuration(0.1).play();
}, false);
window.addEventListener('mouseup', function (event) {
mixer.clipAction(clip).setDuration(1).play();
}, false);
var delta = clock.getDelta(); //这里100就是速度的一个因子,数值越大,重力效果越明显; velocity.z -= 9.8 * 100 * delta; birdmesh.position.z += velocity.z*delta; birdmesh.position.y += velocity.y * delta; velocity.y = 200;
另外上面代码仔细观察,你会发现鼠标点击和松开给定的鸟煽动翅膀的速度是不一样的
mixer.clipAction(clip).setDuration(1).play()
这是为了达到点击鼠标有鸟在努力向上飞的视觉效果~。
先写到这。全部源码先贴在这吧,其实上传工程的效果是最好的,但还没整理好。这个练手还没完!
预告后面两节
后1节:飞行类小游戏转置为win10通用UWP应用(我将上传至微软商店,敬请期待!)
后2节:飞行类小游戏转置为手机安卓应用
最后目前全部源码~
<!DOCTYPE html> <html lang="en"> <head> <title>练手</title> <meta charset="utf-8"> </head> <body> <script src="build/three.js"></script> <script src="js/Detector.js"></script> <script src="js/controls/OrbitControls.js"></script> <script> if (!Detector.webgl) Detector.addGetWebGLMessage(); var camera, scene, renderer; var clock = new THREE.Clock(); //var controls; var velocity = new THREE.Vector3(); var birdmesh; var objects = []; init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); // camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 100000); camera.up.set(0, 0, 1); camera.lookAt(new THREE.Vector3(-1, 1, 0)); scene = new THREE.Scene(); // scene.add( new THREE.HemisphereLight( 0x443333, 0x222233 ) ); var light = new THREE.DirectionalLight( 0xffffff, 1 ); light.position.set( 1, 1, 1 ); scene.add( light ); //------添加内容 //---地板,平面 geometry = new THREE.PlaneGeometry(512, 200000); //geometry.rotateX(-Math.PI / 2); var texture = new THREE.TextureLoader().load('img/dd.jpg'); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(8, 800) material = new THREE.MeshBasicMaterial({ map: texture }); //material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } ); mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, 0); scene.add(mesh); objects.push(mesh); ////箱子1 //geometry = new THREE.BoxGeometry(2, 2, 2); //material = new THREE.MeshBasicMaterial({color:0x000000}); //mesh = new THREE.Mesh(geometry, material); //mesh.position.set(0,0,0); //scene.add(mesh); ////箱子2 //geometry = new THREE.BoxGeometry(2, 2, 2); //material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); //mesh = new THREE.Mesh(geometry, material); //mesh.position.set(100, 0, 0); //scene.add(mesh); ////箱子3 //geometry = new THREE.BoxGeometry(2, 2, 2); //material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); //mesh = new THREE.Mesh(geometry, material); //mesh.position.set(0, 100, 0); //scene.add(mesh); ////箱子4 //geometry = new THREE.BoxGeometry(2, 2, 2); //material = new THREE.MeshBasicMaterial({ color: 0x0000ff }); //mesh = new THREE.Mesh(geometry, material); //mesh.position.set(0, 0, 100); //scene.add(mesh); //天空盒 var textureLoader = new THREE.TextureLoader(); var materials = [ new THREE.MeshBasicMaterial({ map: textureLoader.load('img/px.jpg') }), // right new THREE.MeshBasicMaterial({ map: textureLoader.load('img/nx.jpg') }), // left new THREE.MeshBasicMaterial({ map: textureLoader.load('img/py.jpg') }), // top new THREE.MeshBasicMaterial({ map: textureLoader.load('img/ny.jpg') }), // bottom new THREE.MeshBasicMaterial({ map: textureLoader.load('img/pz.jpg') }), // back new THREE.MeshBasicMaterial({ map: textureLoader.load('img/nz.jpg') }) // front ]; mesh = new THREE.Mesh(new THREE.BoxGeometry(100000, 100000, 100000, 7, 7, 7), new THREE.MultiMaterial(materials)); mesh.scale.x = -1; scene.add(mesh); //连续障碍物 for (var i = 0; i < 50;i++) { var ht=Math.random() * 450; geometry = new THREE.BoxGeometry(80, 20, ht); material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff }); mesh = new THREE.Mesh(geometry, material); mesh.position.x =0; mesh.position.y = (i+1) * 500; mesh.position.z = ht / 2; scene.add(mesh); objects.push(mesh); geometry = new THREE.BoxGeometry(80, 20, 450-ht); mesh = new THREE.Mesh(geometry, material); mesh.position.x = 0; mesh.position.y = (i + 1) * 500; mesh.position.z = ht + 140 + (450 - ht) / 2; scene.add(mesh); objects.push(mesh); } //鸟 var loader = new THREE.JSONLoader(); loader.load( "models/animated/flamingo.js", function( geometry ) { geometry.computeVertexNormals(); geometry.computeMorphNormals(); var material = new THREE.MeshPhongMaterial( { color: 0xffffff, morphTargets: true, morphNormals: true, vertexColors: THREE.FaceColors, shading: THREE.SmoothShading } ); birdmesh = new THREE.Mesh( geometry, material ); birdmesh.position.x = 0; birdmesh.position.y = 0; birdmesh.position.z = 200; birdmesh.scale.set(0.2, 0.2, 0.2); birdmesh.rotateX(-Math.PI / 2); birdmesh.rotateZ(Math.PI); scene.add(birdmesh); mixer = new THREE.AnimationMixer(birdmesh); var clip = THREE.AnimationClip.CreateFromMorphTargetSequence('bd', geometry.morphTargets, 30); mixer.clipAction(clip).setDuration(1).play(); window.addEventListener('mousedown', function (event) { velocity.z = 500; mixer.clipAction(clip).setDuration(0.1).play(); }, false); window.addEventListener('mouseup', function (event) { mixer.clipAction(clip).setDuration(1).play(); }, false); } ); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild( renderer.domElement ); //控制 //var controls = new THREE.OrbitControls(camera, renderer.domElement); //controls.addEventListener('change', render); //controls.target.set(0, 0, 0); //controls.update(); // window.addEventListener('resize', function onWindowResize(event) { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = 0.5 * window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); }, false); } // function animate() { requestAnimationFrame( animate ); render(); } function render() { var delta = clock.getDelta(); //这里100就是速度的一个因子,数值越大,重力效果越明显,等效于velocity.y =(velocity.y*0.01- 9.8 * delta)*100; velocity.z -= 9.8 * 100 * delta; birdmesh.position.z += velocity.z*delta; birdmesh.position.y += velocity.y * delta; velocity.y = 200; var raycaster1 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 1, 0), 0, 30) var raycaster2 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 0, 1), 0, 10) var raycaster3 = new THREE.Raycaster(birdmesh.position, new THREE.Vector3(0, 0, -1), 0, 10) // var intersections1 = raycaster1.intersectObjects(objects); var intersections2 = raycaster2.intersectObjects(objects); var intersections3 = raycaster3.intersectObjects(objects); //是否检测到 if (intersections1.length > 0) { velocity.y = 0; } if (intersections2.length > 0 ) { if (velocity.z > 0) { velocity.z = 0; } } if (intersections3.length > 0) { if (velocity.z < 0) { velocity.z = 0; } } if (birdmesh.position.z < 10) { birdmesh.position.z = 10; } if (birdmesh.position.z > 575) { birdmesh.position.z = 575; } if (velocity.y==0) { alert('您已死亡!'); } mixer.update(delta); camera.position.set(birdmesh.position.x+100, birdmesh.position.y - 50, birdmesh.position.z); renderer.clear(); renderer.render( scene, camera ); } </script> </body> </html>