【精选】ThreeJS第一人称视角处理

您所在的位置:网站首页 lpl第一人称视角 【精选】ThreeJS第一人称视角处理

【精选】ThreeJS第一人称视角处理

2024-03-13 19:34| 来源: 网络整理| 查看: 265

简介

第一人称控件指针锁定API允许您在游戏界面中锁定鼠标或其他指针设备,以便您不用绝对定位光标就可以获得坐标变化值,从而准确地判断用户正在做什么,并且还可以防止用户意外地进入另一块屏幕或别的什么地方,从而导致误操作。

在ThreeJs中实现第一人称操作有一个控件FirstPersonControl, 但是就这个控件使用起来有一些弊端; 所以我们这边使用PointerLockControls写了一个控件。

常用方法属性 方法属性描述getObject().translateX锁定控件对象,可通过此设置锁定控件的位置isLocked判断当前鼠标是否锁定Lock鼠标锁定开始 使用方法:

1、首先需要引入 PointerLockControls 控件文件

2、创建PointerLockControls对象,并把相机传入,放到我们的场景中 let controls = new THREE.PointerLockControls( camera ); scene.add(controls );

3、鼠标锁定只有通过用户才能触发,所以需要在页面上添加dom标签,并实现点击之后锁定

点击要实现如下方法 control.lock();

当我们锁定了这个控件之后,鼠标移动只会改变在场景中的视角,是不能够选中其他东西的,退出点击键盘Esc键。

4、通过实例化的对象可以通过 getObject() 获取到控制对象,可以设置它的位置来调整进入场景的位置。最后将对象放置到 scene 场景当中。

controls.getObject().position.y = 50; controls.getObject().position.x = 100; scene.add( controls.getObject() );

5、最后,在 render 当中,我们让 controls 调用 update 函数实现更新

controls.getObject().translateX( velocity.x * delta ); controls.getObject().translateY( velocity.y * delta ); controls.getObject().translateZ( velocity.z * delta );

这里我们注意一下controls.getObject().translateX( velocity.x * delta ) 方法和直接改变位置 controls.getObject().position.x += ( velocity.x * delta ) 的区别,translate方法会根据视角重新调整前后左右,而直接修改位置则以最先视角准,不会修改主视角。

实现按键移动

我们要实现可以通过键盘案例进行控制器位置调整,首先就是要监听事件,所以我们监听的键盘按下事件和键盘抬起事件:

document.addEventListener( 'keydown', onKeyDown, false ); document.addEventListener( 'keyup', onKeyUp, false );

当鼠标按下时,开始移动

var onKeyDown = function ( event ) { switch ( event.keyCode ) { case 38: // up case 87: // w moveForward = true; break; case 37: // left case 65: // a moveLeft = true; break; case 40: // down case 83: // s moveBackward = true; break; case 39: // right case 68: // d moveRight = true; break; case 32: // space if ( canJump === true ) velocity.y += 350; canJump = false; break; } };

当鼠标抬起来时,停止移动

var onKeyUp = function ( event ) { switch ( event.keyCode ) { case 38: // up case 87: // w moveForward = false; break; case 37: // left case 65: // a moveLeft = false; break; case 40: // down case 83: // s moveBackward = false; break; case 39: // right case 68: // d moveRight = false; break; } };

最后,在 render 渲染中,进行判断当前的移动方向,实现的当前的移动,

var time = performance.now(); var delta = ( time - prevTime ) / 1000; velocity.x -= velocity.x * 10.0 * delta; velocity.z -= velocity.z * 10.0 * delta; velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass direction.z = Number( moveForward ) - Number( moveBackward ); direction.x = Number( moveLeft ) - Number( moveRight ); direction.normalize(); // this ensures consistent movements in all directions if ( moveForward || moveBackward ) velocity.z -= direction.z * 400.0 * delta; if ( moveLeft || moveRight ) velocity.x -= direction.x * 400.0 * delta; controls.getObject().translateX( velocity.x * delta ); //controls.getObject().position.x += ( velocity.x * delta ); controls.getObject().translateY( velocity.y * delta ); //controls.getObject().position.y += ( velocity.y * delta ); // new behavior //controls.getObject().position.z += ( velocity.z * delta ); // new behavior controls.getObject().translateZ( velocity.z * delta ); 使用Raycaster实现简单的碰撞检测

比如当我们在场景中撞到墙的时候是不能穿越墙的,这里就要用到碰撞检测。他所用的原理就是如果选中了就代表着要和他接触,如果接触就设定不能再往前了,就是这样一个检测,我们这里举例只使用了上下(垂直方向)碰撞。

raycaster.ray.origin.copy( controls.getObject().position ); raycaster.ray.origin.y -= 10; var intersections = raycaster.intersectObjects( objects ); var onObject = intersections.length > 0; if ( onObject === true ) { velocity.y = Math.max( 0, velocity.y ); canJump = true; } if ( controls.getObject().position.y < 10 ) { velocity.y = 0; controls.getObject().position.y = 10; canJump = true; }

举例:

第一步:添加模拟游览按钮

模拟游览

第二步:点击按钮,锁定第一人称视角游览控件。

document.getElementById("tour").addEventListener('click', function () { store.lockControl(); }, false);

第三步:

function Store3D() { this.spriteIsShow=1; // 存在精灵系统 如:标签之类的 }

  开启鼠标锁定

Store3D.prototype.lockControl=function() { if(this.spriteIsShow==1) // 如果锁定的时候场景中有精力系统会报错 { this.changeSpriteShow(); // 所以锁定之前的时候调用方法 隐藏精灵系统,具体精灵系统自行了解 } // 因为我们要模拟第一人称进入场景 所以我们改变相机的位置 this.camera.position.y = 100; // 改变相机的视角 this.camera.lookAt(0,100,0); // 模拟人的眼睛 人的眼睛就相当于现在相机的位置 this.lockcontrols.getObject().position.x =0; this.lockcontrols.getObject().position.y =100; this.lockcontrols.getObject().position.z =580; this.lockcontrols.lock(); // 调用lock这个时候就锁定控件鼠标了 },

第四步:第一人称视角移动

Store3D.prototype.firstPersonMove=function(){ // 如果当前是锁定的,就要进行第一视角的移动 if ( this.lockcontrols.isLocked === true ) { // 首先设置射线 用来做碰撞测试 // 射线的初始位置就是第一人称对象的位置 那么他的方向就是我前面对象的方向 this.raycaster.ray.origin.copy( this.lockcontrols.getObject().position ); // 我们这里举例只检测垂直方向 // 那么他朝向的位置 是当前位置往下 this.raycaster.ray.origin.y -= 10; // 查看是否相交 如果相交将所有物体放入intersections这个变量 var intersections = this.raycaster.intersectObjects( this.objects ); // 如果intersections.length大于0 则说明他与下面的物体相交了 这时将onObject设置为true var onObject = intersections.length > 0; // 每次都获取上一次的间隔时间 因为根据性能不同每次调用循环函数的时间都是不一样的 var time = performance.now(); // 为了不让性能影响操作的速度 我们将他设置为一个因数 所谓性能高那么间隔时间就短 var delta = ( time - this.prevTime ) / 1000; // 设置一下(10)减速因子 他越快整个过程中速度就会越慢 减速的过程就会越快 this.velocity.x -= this.velocity.x * 10.0 * delta; this.velocity.z -= this.velocity.z * 10.0 * delta; this.velocity.y -= 9.8 * 100.0 * delta; // y轴跳跃的速度 100.0 = mass // 鼠标操作的时候控制方向 的变量 // 如果正数就是往前 负数就是往后 this.direction.z = Number( this.moveForward ) - Number( this.moveBackward ); this.direction.x = Number( this.moveLeft ) - Number( this.moveRight ); // this ensures consistent movements in all directions this.direction.normalize(); //注意velocity向量,这是一个缓冲值,为了保证鼠标抬起后,场景不直接暂停,而是有一个简短的过渡效果: if ( this.moveForward || this.moveBackward ) this.velocity.z -= this.direction.z * 2000.0 * delta; if ( this.moveLeft || this.moveRight ) this.velocity.x -= this.direction.x * 2000.0 * delta; // 如果onObject为true, if ( onObject === true ) { // 此时需要将y轴的速度设置为0和之前速度的最大值 this.velocity.y = Math.max( 0, this.velocity.y ); this.canJump = true; } // 计算每次在x,y,z轴移动的距离 this.lockcontrols.getObject().translateX( this.velocity.x * delta ); this.lockcontrols.getObject().position.y += ( this.velocity.y * delta ); // new behavior this.lockcontrols.getObject().translateZ( this.velocity.z * delta ); // 为了保证我永远是高于地面的 所以我设置当y小于100时就让y等于100 if ( this.lockcontrols.getObject().position.y < 100 ) { this.velocity.y = 0; this.lockcontrols.getObject().position.y = 100; this.canJump = true; } this.prevTime = time; } },

第五步:设置鼠标控制

/** * 初始化PointLockControl * 设置鼠标控制 */ Store3D.prototype.initPointLockControl=function(object){ this.lockcontrols = new THREE.PointerLockControls( this.camera ); this.raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 ); // 设置键盘按下监听事件 var onKeyDown = function ( event ) { switch ( event.keyCode ) { case 38: // up case 87: // w object.moveForward = true; break; case 37: // left case 65: // a object.moveLeft = true; break; case 40: // down case 83: // s object.moveBackward = true; break; case 39: // right case 68: // d object.moveRight = true; break; case 32: // space if ( object.canJump === true ) object.velocity.y += 350; object.canJump = false; break; } }; // 设置键盘抬起监听事件 var onKeyUp = function ( event ) { switch ( event.keyCode ) { case 38: // up case 87: // w object.moveForward = false; break; case 37: // left case 65: // a object.moveLeft = false; break; case 40: // down case 83: // s object.moveBackward = false; break; case 39: // right case 68: // d object.moveRight = false; break; } }; document.addEventListener( 'keydown', onKeyDown, false ); document.addEventListener( 'keyup', onKeyUp, false ); },


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3