本次尝试,模拟了一个小人物在场景中行走,使用简单模型建立了森林,图片纹理模拟草地,加载3D模型呈现人物,使用按键asdw模拟人物的行走,行走和站立时人物的切换等。

主要用到点:3D模型的加载,模型的动画(行走与站立)之间的切换。

不足之处:没有检测碰撞与边界。

需要注意的是,代码需要运行在服务器端,切记。

代码如下:

<!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>
附上github链接:https://github.com/liujiekun/threeJS记得在服务端启动,直接浏览器运行是看不到图片、纹理以及动画原型的。

three.js尝试(二)模拟游戏开发:3D人物在地图上行走的更多相关文章

  1. 喵的Unity游戏开发之路 - 在球体上行走

    很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3D游戏开发. 本文不 ...

  2. 拜托,使用Three.js让二维图片具有3D效果超酷的好吗 💥

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 逛 sketchfab 网站的时候我看到有很多二维平面转 3D 的模型例子 ...

  3. [Unity3D]Unity3D游戏开发3D选择场景中的对象,并显示轮廓效果强化版

    大家好,我是秦培,欢迎关注我的博客,我的博客地址blog.csdn.net/qinyuanpei. 在上一篇文章中,我们通过自己定义着色器实现了一个简单的在3D游戏中选取.显示物体轮廓的实例. 在文章 ...

  4. 【游戏开发】小白学Lua(上)

    在很多游戏中,脚本语言是不可或缺的一部分,很多游戏都使用到了Lua,js,python一类的脚本,脚本语言可以在很多方面给开发进程带来帮助.脚本语言可以作为初始化文件读入变量和游戏数据的一个快速而方便 ...

  5. html5游戏开发--"动静"结合用地图块拼成大地图 & 初探lufyl

    一.前言   本次教程将向大家讲解如何用html5将小地图块拼成大地图,以及如何用现有的高级html5游戏开发库件lufylegend.js开发游戏.   首先让我们来了解了解如何用html5实现动画 ...

  6. Unity游戏开发--30s制作精美地图

    "君子生非异也.善假于物也"--<劝学>荀子 引用这句话的目的,是我觉得有时候.利用工具来提高游戏开发效率是很必要的. 利用工具,解放程序员双手. 今天想给大家介绍下. ...

  7. three.js尝试(一)模拟演唱会效果

    工作闲暇之余,偶然翻到了Three.js的官网,立刻被它酷炫的案例给惊艳到了,当即下定决心要试验摸索一番,于是看demo,尝试,踩坑,解决问题,终于搞定了,一个模拟演唱会场景. 主角围绕一个钢管在舞动 ...

  8. 游戏开发3D基础知识

    概念学习: 向量 向量简介 我们将所有彼此平行的向量进行平移,使其起点与坐标原点重合,当某一向量的起始端与坐标原点重合,我们成该向量处于标准位置.这样,我们就可用向量的终点坐标来描述一个处于标准位置的 ...

  9. 从一点儿不会开始——Unity3D游戏开发学习(一)

    一些废话 我是一个windows phone.windows 8的忠实粉丝,也是一个开发者,开发数个windows phone应用和两个windows 8应用.对开发游戏一直抱有强烈兴趣和愿望,但奈何 ...

随机推荐

  1. cryptopp使用Qt mingw编译,以及海思平台交叉编译

    编译工程生成,使用qmake生成qt工程文件(海思平台时,要用海思平台的qmake),将 TEMPLATE = app 修改为: TEMPLATE = lib 添加如下: win32:LIBS += ...

  2. JS中escape()、encodeURI()、encodeURIComponent()区别详解

    avaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decode ...

  3. 每日一道 LeetCode (8):删除排序数组中的重复项和移除元素

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

  4. xadmin 安装

    xadmin 安装 环境(一定要一样) Python 3.6.2 Django 2.0 安装 pip install django==2.0, 指定特定的版本 pip install https:// ...

  5. [leetcode/lintcode 题解] Google面试题:合法组合

    给一个单词s,和一个字符串集合str.这个单词每次去掉一个字母,直到剩下最后一个字母.求验证是否存在一种删除的顺序,这个顺序下所有的单词都在str中.例如单词是’abc’,字符串集合是{‘a’,’ab ...

  6. Linux中C++提示‘close’ was not declared

    C++socket编程时关闭socket和epoll时出现‘close’ was not declared,是程序头文件缺失导致的.缺失头文件#include <unistd.h>

  7. Linux根目录下文件夹用途解释

    root目录:主要用于存放root用户相关文件的目录: usr目录:安装一个软件时,linux指定的此软件默认安装的目录: home目录:用于存放普通用户的相关文件的目录:例如:我使用adduser ...

  8. VM获取子网掩码和网关

  9. Vue管理系统前端系列四组件拆分封装

    目录 组件封装 首页布局拆分后结构 拆分后代码 状态管理中添加 app 模块 组件封装 在上一篇记录中,首页中有太多的代码,为了避免代码的臃肿,需要对主要的功能模块拆分,来让代码看起来更简洁,且能进行 ...

  10. Python Jinja2 Template: YAML File Cisco Example Tutorial

    原文链接:http://networkbit.ch/python-jinja-template/ template.txt如下: hostname {{ name }} interface Loopb ...