yskang

threejs-minecraft-33

Apr 26th, 2020
1,651
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Point lock navigation tool
  3.  * Ref: https://ithelp.ithome.com.tw/articles/10208322
  4.  */
  5.  
  6. class NavigationTool {
  7.   constructor( camera, cannonBody ) {
  8.     this.camera = camera;
  9.     this.controls = null;
  10.     // this.raycaster = null;
  11.     // this.moveForward = false;
  12.     // this.moveBackward = false;
  13.     // this.moveLeft = false;
  14.     // this.moveRight = false;
  15.     // this.canJump = false;
  16.     // this.prevTime = Date.now(); // 初始時間
  17.     // this.velocity = new THREE.Vector3(); // 移動速度向量
  18.     // this.direction = new THREE.Vector3(); // 移動方向向量
  19.  
  20.     this.onControlLockedHandler = ( event ) => this.onControlLocked( event );
  21.     this.onControlUnlockedHandler = ( event ) => this.onControlUnlocked( event );
  22.     this.onInstructionsClickedHandler = ( event ) => this.onInstructionsClicked( event );
  23.     // this.onKeyDownHandler = ( event ) => this.onKeyDown( event );
  24.     // this.onKeyUpHandler = ( event ) => this.onKeyUp( event );
  25.  
  26.     this.initialize( cannonBody );
  27.     this.bindEvents();
  28.   }
  29.  
  30.   get enabled() {
  31.     return this.controls.isLocked;
  32.   }
  33.  
  34.   createUI() {
  35.     const blocker = document.createElement( 'div' );
  36.     blocker.id = 'blocker';
  37.     document.body.appendChild( blocker );
  38.  
  39.     const instructions = document.createElement( 'div' );
  40.     instructions.id = 'instructions';
  41.     blocker.appendChild( instructions );
  42.  
  43.     const spanTitle = document.createElement( 'span' );
  44.     spanTitle.style.fontSize = '40px';
  45.     spanTitle.innerText = '點擊開始';
  46.     instructions.appendChild( spanTitle );
  47.  
  48.     const breakLine = document.createElement( 'br' );
  49.     instructions.appendChild( breakLine );
  50.  
  51.     const spanControl = document.createElement( 'span' );
  52.     spanControl.innerText = '(W, A, S, D = 控制方向, SPACE = 跳躍, MOUSE = 轉動視角)';
  53.     instructions.appendChild( spanControl );
  54.   }
  55.  
  56.   initialize( cannonBody ) {
  57.     this.createUI();
  58.  
  59.     //const controls = new CannonPointerLockControls( this.camera, cannonBody );
  60.     const controls = new THREE.CannonPointerLockControls( this.camera, null, cannonBody );
  61.     //controls.getObject().position.set( 10, 0, 60 );
  62.     this.controls = controls;
  63.  
  64.     // 使用 Raycaster 實現簡單碰撞偵測
  65.     // this.raycaster = new THREE.Raycaster(
  66.     //   new THREE.Vector3(),
  67.     //   new THREE.Vector3( 0, -1, 0 ),
  68.     //   0,
  69.     //   10
  70.     // );
  71.   }
  72.  
  73.   uninitialize() {
  74.     this.clearEvents();
  75.   }
  76.  
  77.   attach( scene ) {
  78.     if( !(scene instanceof THREE.Scene) ) return;
  79.  
  80.     scene.add( this.controls.getObject() );
  81.   }
  82.  
  83.   detach( scene ) {
  84.     if( !(scene instanceof THREE.Scene) ) return;
  85.  
  86.     scene.remove( this.controls.getObject() );
  87.   }
  88.  
  89.   bindEvents() {
  90.     const instructions = document.getElementById( 'instructions' );
  91.  
  92.     const havePointerLock = 'pointerLockElement' in document ||
  93.                             'mozPointerLockElement' in document ||
  94.                             'webkitPointerLockElement' in document;
  95.  
  96.     if( havePointerLock ) {
  97.       instructions.addEventListener(
  98.         'click',
  99.         this.onInstructionsClickedHandler,
  100.         false
  101.       );
  102.  
  103.       this.controls.addEventListener(
  104.         'lock',
  105.         this.onControlLockedHandler
  106.       );
  107.  
  108.       this.controls.addEventListener(
  109.         'unlock',
  110.         this.onControlUnlockedHandler
  111.       );
  112.     } else {
  113.       instructions.innerHTML = '你的瀏覽器似乎不支援 Pointer Lock API,建議使用電腦版 Google Chrome 取得最佳體驗!';
  114.     }
  115.    
  116.     // document.addEventListener(
  117.     //   'keydown',
  118.     //   this.onKeyDownHandler,
  119.     //   false
  120.     // );
  121.  
  122.     // document.addEventListener(
  123.     //   'keyup',
  124.     //   this.onKeyUpHandler,
  125.     //   false
  126.     // );
  127.   }
  128.  
  129.   clearEvents() {
  130.     const instructions = document.getElementById( 'instructions' );
  131.  
  132.     instructions.removeEventListener(
  133.       'click',
  134.       this.onInstructionsClickedHandler,
  135.       false
  136.     );
  137.  
  138.     this.controls.removeEventListener(
  139.       'lock',
  140.       this.onControlLockedHandler
  141.     );
  142.  
  143.     this.controls.removeEventListener(
  144.       'unlock',
  145.       this.onControlUnlockedHandler
  146.     );
  147.  
  148.     // document.removeEventListener(
  149.     //   'keydown',
  150.     //   this.onKeyDownHandler,
  151.     //   false
  152.     // );
  153.  
  154.     // document.removeEventListener(
  155.     //   'keyup',
  156.     //   this.onKeyUpHandler,
  157.     //   false
  158.     // );
  159.   }
  160.  
  161.   update( scene, callback ) {
  162.     if( !(scene instanceof THREE.Scene) || this.controls.isLocked !== true ) return;
  163.  
  164.     // // 使用 Raycaster 判斷腳下是否與場景中物體相交
  165.     // this.raycaster.ray.origin.copy( this.controls.getObject().position ); // 複製控制器的位置
  166.     // const intersections = this.raycaster.intersectObjects( scene.children, true ); // 判斷是否在任何物體上
  167.     // const onObject = intersections.length > 0;
  168.  
  169.     // // 計算時間差
  170.     // const time = Date.now();
  171.     // const diff = time - this.prevTime;
  172.     // const delta = diff / 1000; // 大約為 0.016
  173.  
  174.     // // 設定初始速度變化
  175.     // this.velocity.x -= this.velocity.x * 10.0 * delta;
  176.     // this.velocity.z -= this.velocity.z * 10.0 * delta;
  177.     // this.velocity.y -= 9.8 * 100.0 * delta; // 預設墜落速度
  178.  
  179.     // // 判斷按鍵朝什麼方向移動,並設定對應方向速度變化
  180.     // this.direction.z = Number( this.moveForward ) - Number( this.moveBackward );
  181.     // this.direction.x = Number( this.moveLeft ) - Number( this.moveRight );
  182.     // // direction.normalize() // 向量正規化(長度為 1),確保每個方向保持一定移動量
  183.     // if( this.moveForward || this.moveBackward )
  184.     //   this.velocity.z -= this.direction.z * 400.0 * delta;
  185.     // if( this.moveLeft || this.moveRight )
  186.     //   this.velocity.x -= this.direction.x * 400.0 * delta;
  187.  
  188.     // // 處理跳躍對應 y 軸方向速度變化
  189.     // if( onObject === true ) {
  190.     //   this.velocity.y = Math.max( 0, this.velocity.y );
  191.     //   this.canJump = true;
  192.     // }
  193.  
  194.     // // 根據速度值移動控制器位置
  195.     // this.controls.getObject().translateX( this.velocity.x * delta );
  196.     // this.controls.getObject().translateY( this.velocity.y * delta );
  197.     // this.controls.getObject().translateZ( this.velocity.z * delta );
  198.  
  199.     // // 控制器下墜超過 -2000 則重置位置
  200.     // if( this.controls.getObject().position.y < -2000 ) {
  201.     //   this.velocity.y = 0;
  202.     //   this.controls.getObject().position.set( 10, 100, 60 );
  203.     //   this.canJump = true;
  204.     // }
  205.  
  206.     const time = Date.now();
  207.     const diff = time - this.prevTime;
  208.     callback && callback();
  209.     this.controls.update( diff );
  210.  
  211.     this.prevTime = time;
  212.   }
  213.  
  214.   onInstructionsClicked() {
  215.     this.controls.lock();
  216.   }
  217.  
  218.   onControlLocked() {
  219.     const blocker = document.getElementById( 'blocker' );
  220.     const instructions = document.getElementById( 'instructions' );
  221.  
  222.     instructions.style.display = 'none';
  223.     blocker.style.display = 'none';
  224.   }
  225.  
  226.   onControlUnlocked() {
  227.     const blocker = document.getElementById( 'blocker' );
  228.     const instructions = document.getElementById( 'instructions' );
  229.  
  230.     blocker.style.display = 'block';
  231.     instructions.style.display = '';
  232.   }
  233.  
  234.   // onKeyUp( event ) {
  235.   //   switch( event.keyCode ) {
  236.   //     case 38: // up
  237.   //     case 87: // w
  238.   //       this.moveForward = false;
  239.   //       break;
  240.   //     case 37: // left
  241.   //     case 65: // a
  242.   //       this.moveLeft = false;
  243.   //       break;
  244.   //     case 40: // down
  245.   //     case 83: // s
  246.   //       this.moveBackward = false;
  247.   //       break;
  248.   //     case 39: // right
  249.   //     case 68: // d
  250.   //       this.moveRight = false;
  251.   //       break;
  252.   //   }
  253.   // }
  254.  
  255.   // onKeyDown( event ) {
  256.   //   switch( event.keyCode ) {
  257.   //     case 38: // up
  258.   //     case 87: // w
  259.   //       this.moveForward = true;
  260.   //       break;
  261.   //     case 37: // left
  262.   //     case 65: // a
  263.   //       this.moveLeft = true;
  264.   //       break;
  265.   //     case 40: // down
  266.   //     case 83: // s
  267.   //       this.moveBackward = true;
  268.   //       break
  269.   //     case 39: // right
  270.   //     case 68: // d
  271.   //       this.moveRight = true
  272.   //       break;
  273.   //     case 32: // space
  274.   //       if( this.canJump === true )
  275.   //         this.velocity.y += 350; // 跳躍高度
  276.  
  277.   //       this.canJump = false;
  278.   //       break;
  279.   //   }
  280.   // }
  281. }
Advertisement
Add Comment
Please, Sign In to add comment