three.js尝试(二)模拟游戏开发:3D人物在地图上行走
本次尝试,模拟了一个小人物在场景中行走,使用简单模型建立了森林,图片纹理模拟草地,加载3D模型呈现人物,使用按键asdw模拟人物的行走,行走和站立时人物的切换等。
主要用到点:3D模型的加载,模型的动画(行走与站立)之间的切换。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。不足之处:没有检测碰撞与边界。
需要注意的是,代码需要运行在服务器端,切记。
代码如下:
<!DOCTYPE html> <html><head> <meta charset="UTF-8"> <style> </style> <title>测试</title> <script src="../js/three.js"></script> <script src="../js/dat.gui.min.js"></script> <script src="../js/OrbitControls.js"></script> <script src="../js/util.js"></script> <script src="../js/GLTFLoader.js"></script> </head>
<body> <script> var scene, camera, renderer, controls, flag = 1; var target; var trees; // 荧光棒 var role; // 主角 var textPlane; var stateList = {}; var actionMap = { up: { direction: 'up', rotation: Math.PI, axes: 'z' }, down: { direction: 'down', rotation: 0, axes: 'z' }, left: { direction: 'left', rotation: - Math.PI / 2, axes: 'x' }, right: { direction: 'right', rotation: Math.PI / 2, axes: 'x' } }; var nopeAction = { direction: null }; var nextAction = { direction: 'down', rotation: 0 }; var clock, mixer, currentAction, previousAction, lastkey; function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 500); camera.position.z = 20; camera.lookAt(scene.position); scene.add(camera); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap document.body.appendChild(renderer.domElement); controls = new THREE.OrbitControls(camera, renderer.domElement); controls.update(); clock = new THREE.Clock(); window.addEventListener('resize', onWindowResize, false);
var axesHelper = new THREE.AxesHelper(50); scene.add(axesHelper); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; renderer.setSize(window.innerWidth, window.innerHeight); } function run() { init(); createRole(); //创建角色 createAmbientLight(); // 绘制环境光 // createSpotlist(new THREE.Vector3(50, 50, 50), role); createPlane(); // 创建舞台平面 createTrees(20); window.addEventListener('keydown', keyPressed, false); window.addEventListener('keyup', keyUp, false) render(); }
function render() { var dt = clock.getDelta(); if (mixer) mixer.update(dt); requestAnimationFrame(render); controls.update(); handleRoleAction(); renderer.render(scene, camera); }
run();
function createAmbientLight() { var light = new THREE.AmbientLight(0xdddddd); // soft white light scene.add(light); } function createPlane() { //Create a plane that receives shadows (but does not cast them) var planeGeometry = new THREE.PlaneBufferGeometry(1000, 1000); var texture = new THREE.TextureLoader().load('../images/grasslight-big.jpg'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(25, 25); var planeMaterial = new THREE.MeshStandardMaterial({ map: texture, side: THREE.DoubleSide }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.rotation.x = -Math.PI / 2; plane.position.y = -16; plane.receiveShadow = true; scene.add(plane); } function createSpotlist(Vector3, target) { var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(Vector3.x, Vector3.y, Vector3.z);
spotLight.castShadow = true; spotLight.angle = Math.PI / 18; spotLight.shadow.mapSize.width = 512; spotLight.shadow.mapSize.height = 512;
spotLight.shadow.camera.near = 0.5; spotLight.shadow.camera.far = 500; spotLight.shadow.camera.fov = 30; spotLight.target = target; scene.add(spotLight);
// Create a helper for the spotlight // var helper = new THREE.SpotLightHelper(spotLight); // scene.add(helper);
// //Create a helper for the shadow camera (optional) // var helper = new THREE.CameraHelper(spotLight.shadow.camera); // scene.add(helper); } function createTrees(num) { for (let i = 0; i < num; i++) { let treeNode = new THREE.Object3D();
var treeTopGeo = new THREE.CylinderGeometry(0, 10, 20, 32); var treeTopMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); var treeTop = new THREE.Mesh(treeTopGeo, treeTopMaterial); treeTop.position.y = 4; // 树底部中心点高度是-11,底部的上边高度是-6,这样树顶部中心点高度默认是0的话,下边是-10,如果想让下边高度为-6,则中心点高度为4
var treeBottomGeo = new THREE.CylinderGeometry(5, 5, 10, 32); var treeBottomMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); var treeBottom = new THREE.Mesh(treeBottomGeo, treeBottomMaterial); treeBottom.position.y = -11; // 底面位置是-16,底部圆柱体中心点高度默认是0的话,底边高度是-5,所以将position.y设置为-11,这样下边高度是-16
treeNode.add(treeTop); treeNode.add(treeBottom);
treeNode.position.set(util.createRandomPos(-250, 250), 0, util.createRandomPos(-250, 250)); scene.add(treeNode); } } function createRole() { // model var loader = new THREE.GLTFLoader(); loader.load('../models/RobotExpressive.glb', function (gltf) { role = gltf.scene; role.position.y = -16; mixer = new THREE.AnimationMixer(role); stateList.Walking = mixer.clipAction(gltf.animations[10]); stateList.Standing = mixer.clipAction(gltf.animations[8]); // 设置下面两项主要是站着的时候,别抖了 stateList.Standing.clampWhenFinished = true; stateList.Standing.loop = THREE.LoopOnce; currentAction = stateList.Standing; currentAction.play(); scene.add(role); createSpotlist(new THREE.Vector3(50, 50, 50), role);
}, undefined, function (e) { console.error(e); }); } function keyPressed(e) { var key = event.keyCode; if (lastkey != key) { lastkey = key; fadeToAction('Walking', 0.2); } switch (key) { case 87: /*w*/ nextAction = actionMap.up; break; case 65: /*a*/ nextAction = actionMap.left; break;
case 83: /*s*/ nextAction = actionMap.down; break; case 68: /*d*/ nextAction = actionMap.right; break; } if (role) role.rotation.y = nextAction.rotation; } function keyUp() { lastkey = null; nextAction = nopeAction; fadeToAction('Standing', 0.2); } function handleRoleAction() { if (role) { if (nextAction.direction == 'down' || nextAction.direction == "right") { flag = 1; } else if (nextAction.direction == 'up' || nextAction.direction == "left") { flag = -1; } else { flag = 0; } role.position[nextAction.axes] += 0.2 * flag; } } function fadeToAction(name, duration) { previousAction = currentAction; currentAction = stateList[name]; if (previousAction !== currentAction) { previousAction.fadeOut(duration); } if (currentAction) { currentAction .reset() .setEffectiveTimeScale(1) .setEffectiveWeight(1) .fadeIn(duration) .play(); } } </script> </body>
</html>

更多精彩