• three.js 按键W前进、S退后、A左转、D右转运动


    效果:W 键 前进;S 键后退;A 键左转;D 键右转;使用了 tween.js 动画库; 

    代码:

    1. <template>
    2. <div>
    3. <el-container>
    4. <el-main>
    5. <div class="box-card-left">
    6. <div id="threejs">div>
    7. div>
    8. el-main>
    9. el-container>
    10. div>
    11. template>s
    12. <script>
    13. // 引入轨道控制器扩展库OrbitControls.js
    14. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
    15. import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
    16. import TWEEN from '@tweenjs/tween.js';
    17. export default {
    18. data() {
    19. return {
    20. scene: null,
    21. camera: null,
    22. renderer: null,
    23. res1: null,
    24. res2: null,
    25. clock: null,
    26. keyState: {
    27. W: false,
    28. S: false,
    29. A: false,
    30. D: false,
    31. },
    32. left_rotation: true, // 向左旋转的标志
    33. right_rotation: true, // 向右旋转的标志
    34. VW: new this.$three.Vector3(0, 0, 0),
    35. VS: new this.$three.Vector3(0, 0, 0),
    36. curr_v: new this.$three.Vector3(0, 0, 0),
    37. person: null,
    38. deltaTime: 0,
    39. a: 30, // 加速度
    40. damping: -0.04,
    41. };
    42. },
    43. created() {},
    44. mounted() {
    45. this.name = this.$route.query.name;
    46. this.init();
    47. },
    48. methods: {
    49. goBack() {
    50. this.$router.go(-1);
    51. },
    52. init() {
    53. this.clock = new this.$three.Clock();
    54. // 创建场景
    55. this.scene = new this.$three.Scene();
    56. // 创建辅助坐标轴对象
    57. const axesHelper = new this.$three.AxesHelper(100);
    58. this.scene.add(axesHelper);
    59. // 创建环境光
    60. const ambientLight = new this.$three.AmbientLight(0xffffff, 10);
    61. this.scene.add(ambientLight);
    62. // 创建相机对象
    63. this.camera = new this.$three.PerspectiveCamera(60,1,0.01,2000);
    64. this.camera.position.set(10,10,10);
    65. this.camera.lookAt(0,0,0);
    66. // 创建渲染器对象
    67. this.renderer = new this.$three.WebGLRenderer();
    68. this.renderer.setSize(1500,1200);
    69. // 创建GLTFLoader对象;加载人物模型
    70. const gltfLoader = new GLTFLoader();
    71. gltfLoader.load("models/gltf/person2/scene.gltf", gltf => {
    72. gltf.scene.position.set(0,0,-10);
    73. gltf.scene.scale.set(2,2,2);
    74. this.person = gltf.scene;
    75. this.scene.add(gltf.scene);
    76. this.renderer.render(this.scene, this.camera);
    77. window.document.getElementById("threejs").appendChild(this.renderer.domElement);
    78. })
    79. const controls = new OrbitControls(this.camera, this.renderer.domElement);
    80. controls.addEventListener("change", () => {
    81. this.renderer.render(this.scene, this.camera);
    82. })
    83. this.addEventListenerFn();
    84. this.renderLoop();
    85. },
    86. renderLoop() {
    87. const deltaTime = this.clock.getDelta();
    88. if(this.keyState.W) {
    89. if(this.VW.length() < 5) {
    90. this.VW.add(new this.$three.Vector3(0,0,1).multiplyScalar(this.a * deltaTime));
    91. this.curr_v = this.VW.clone();
    92. }
    93. let pos = this.VW.clone().multiplyScalar(deltaTime);
    94. this.person.position.add(pos);
    95. }
    96. if(this.keyState.S) {
    97. if(this.VS.length() < 5) {
    98. this.VS.add(new this.$three.Vector3(0,0,-1).multiplyScalar(this.a * deltaTime));
    99. this.curr_v = this.VS.clone();
    100. }
    101. let pos = this.VS.clone().multiplyScalar(deltaTime);
    102. this.person.position.add(pos);
    103. }
    104. if(this.keyState.A) {
    105. }
    106. if(this.person) {
    107. // .addScaledVector ( v : Vector3, s : Float ) : 将所传入的v与s相乘所得的乘积和这个向量相加。
    108. this.curr_v.addScaledVector(this.curr_v, this.damping);
    109. let pos = this.curr_v.clone().multiplyScalar(deltaTime);
    110. this.person.position.add(pos);
    111. }
    112. this.renderer.render(this.scene, this.camera);
    113. TWEEN.update();
    114. requestAnimationFrame(this.renderLoop);
    115. },
    116. addEventListenerFn() {
    117. // 监听按下的 W 键
    118. document.addEventListener("keydown", e => {
    119. if(e.code == "KeyW") {
    120. this.keyState.W = true;
    121. }
    122. if(e.code == "KeyS") {
    123. this.keyState.S = true;
    124. }
    125. if(e.code == "KeyA") {
    126. this.keyState.A = true;
    127. if(!this.left_rotation)return false;
    128. const tween0 = new TWEEN.Tween(this.person.rotation);
    129. let deg = this.$three.MathUtils.radToDeg(this.person.rotation.y);
    130. let rad = this.$three.MathUtils.degToRad(deg + 90);
    131. if(rad != null) {
    132. tween0.to({x:0, y: rad, z:0}, 1000);
    133. tween0.start();
    134. tween0.onStart(() => {
    135. this.left_rotation = false;
    136. });
    137. tween0.onComplete(() => {
    138. this.left_rotation = true;
    139. });
    140. }
    141. }
    142. if(e.code == "KeyD") {
    143. this.keyState.D = true;
    144. if(!this.right_rotation)return false;
    145. const tween0 = new TWEEN.Tween(this.person.rotation);
    146. let deg = this.$three.MathUtils.radToDeg(this.person.rotation.y);
    147. let rad = this.$three.MathUtils.degToRad(deg - 90);
    148. if(rad != null) {
    149. tween0.to({x:0, y: rad, z:0}, 1000);
    150. tween0.start();
    151. tween0.onStart(() => {
    152. this.right_rotation = false;
    153. });
    154. tween0.onComplete(() => {
    155. this.right_rotation = true;
    156. });
    157. }
    158. }
    159. })
    160. document.addEventListener("keyup", e => {
    161. if(e.code == "KeyW") {
    162. this.keyState.W = false;
    163. this.VW = new this.$three.Vector3(0, 0, 0);
    164. }
    165. if(e.code == "KeyS") {
    166. this.keyState.S = false;
    167. this.VS = new this.$three.Vector3(0, 0, 0);
    168. }
    169. if(e.code == "KeyA") {
    170. this.keyState.A = false;
    171. }
    172. if(e.code == "KeyD") {
    173. this.keyState.D = false;
    174. }
    175. })
    176. }
    177. },
    178. };
    179. script>
    180. <style lang="less" scoped>
    181. .box-card-left {
    182. display: flex;
    183. align-items: flex-start;
    184. flex-direction: row;
    185. width: 100%;
    186. .box-right {
    187. img {
    188. width: 500px;
    189. user-select: none;
    190. }
    191. }
    192. }
    193. style>

  • 相关阅读:
    10.力扣c++刷题-->两数之和
    Leetcode 392(会) 20注意细节 * 12 151 6 71
    深度 | 车载语音群雄并起共争智能座舱新高地
    Synchronized锁
    设计模式——15. 模板方法模式
    Java之常用类
    【ACWing】139. 回文子串的最大长度
    【分隔结构】同从分离
    【设计模式】职责链模式
    vue3: 1.如何利用 effectScope 自己实现一个青铜版pinia 一 state篇
  • 原文地址:https://blog.csdn.net/yinge0508/article/details/136626967