本次尝试,模拟了一个小人物在场景中行走,使用简单模型建立了森林,图片纹理模拟草地,加载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. 面经手册 · 第2篇《数据结构,HashCode为什么使用31作为乘数?》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在面经手册的前两篇介绍了<面试官都问我啥>和<认知自己的技术栈盲区 ...

  2. Android Studio--家庭记账本(四)

    今天,实现了在数据库中的删除功能,但是无法实现对表单的删除与自动更新.需要重新启动虚拟机重新从数据库中读取数据才可以实现表单的更新.List表单中的remove功能不太会用.

  3. 教你看懂Docker和K8S!

    转载于 https://my.oschina.net/jamesview/blog/2994112 2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司. 这家公司主要 ...

  4. 【工具】之002-Mac下常用工具

    写在前面 我很懒,,,不想敲一个命令一个命令敲... "偷懒是有前提的,不是之前,就是之后." 常用命令 测试端口是否畅通 nc -z 10.254.3.86 30003 查看端口 ...

  5. tensorflow 三种模型:ckpt、pb、pb-savemodel

    1.CKPT 目录结构 checkpoint: model.ckpt-1000.index model.ckpt-1000.data-00000-of-00001 model.ckpt-1000.me ...

  6. java 接口二

    一 接口的多实现 接口最重要的体现:解决多继承的弊端.将多继承这种机制在java中通过多实现完成了. interface Fu1 { void show1(); } interface Fu2 { v ...

  7. Caused by: org.postgresql.util.PSQLException: 错误: 语法错误 在 "desc" 、语法错误 在 "from" 附近

    此错误一般是由于postgres的数据库表字段名定义与关键字重名所致: 如下,创建的数据库表包含名称为“desc”的字段与倒叙查询的desc关键字冲突会导致Caused by: org.postgre ...

  8. ThinkPHP 6.0 基础教程 - 安装

    ThinkPHP6.0 的环境: PHP >= 7.1.0 我本地环境: Win10 PhpStudy 安装 PhpStudy 如果你已经安装 PhpStudy 或其他环境,请忽略这里 安装方法 ...

  9. 二、JAVA 的了解与安装

    1.java了解 1.1.java三大版本 javaSE:标准版(桌面程序,控制台开发...) javaME:嵌入式开发(手机.小家电...)[可以忽略] javaEE:企业版开发(web端,服务器开 ...

  10. python3中文输出乱码的问题

    最近使用you-get这个工具下载视频,发现命令行窗口里显示的媒体标题是乱码(但文件管理器里显示正常).我的命令行窗口的code page是936,sys.stdout.encoding是utf-8, ...