引言

  在三维图形和游戏开发领域,three.js 作为一个基于 WebGL 的 JavaScript 库,提供了强大的功能来创建和显示动画化的 3D 计算机图形。它使得开发者能够轻松地在网页上构建复杂的 3D 场景和互动游戏。本文将作为一系列教程的第一课,介绍如何基于 three.js 引擎架构,开始实现一个简单的 3D 小游戏。

闲话少叙,亮个相吧!

一、代码结构说明

程序目录图:

主程序主要分为配置、入口、库、模型、多线程库、主代码以及资源。

其中 game.json;project.config.json;project.private.config.json;这三个文件是微信小程序游戏的配置文件

主入口在game.js中。

workers是js多线程的文件放在这里面,主要用来计算敌人位移攻击的一些算法。

units放了一些通用方法 数学计算等

models放了模型文件,包括主角模型,敌人模型 ,地图等

js是主要实现游戏的代码文件

images以及audio是资源文件库

二、效果展示与框架

2.1、游戏启动,初始画面

主角站在门口,等待控制闯关。敌人会自动寻向主角

初始化入口:game.js

    //引入微信库小程序文件

    import './js/libs/weapp-adapter'
    import './js/libs/symbol'
    //引入自定义主入口
    import game3d from './js/Main'

    //创建main中game3d类的游戏对象

    var mygame=new game3d()
main.js的主要逻辑代码
  

  constructor() {
var _this = this;
this.currentUnitObject = null;
this.unit = 1;//关卡
this.speed = 16;//移动速度
this.wt3dobject = null;
this.controlLever = null;
this.xpcobj = null;
this.ZJQiPao = null;//主角的气泡
this.qipaoParent = null;//母气泡
this.woker = wx.createWorker('workers/enemyWoker.js');
this.woker.onProcessKilled(function () {
console.log("线程被杀了");
_this.woker = wx.createWorker('workers/enemyWoker.js');
});
this.music = new Music()
this.createPublicObjects();
this.refreshScene(this.unit);
}

  

 说明:由于gif图限制大小缘故,后面的gif录屏智能选择模糊版

 2.2、控制主角移动

空过摇杆控制器控制主角跑动移动,这里先大概讲解如何实现控制器摇杆

三维场景中 有一个叫做hub模型 是指模型本身永远浮动在相机表面

创建模型:

   var jsonobj={"show":true,"name":"firstEye","uuid":"","objType":"plane","width":this.clBtnradius*0.9,"height":this.clBtnradius*0.9,"color":16777215,"pic":"images/eye.png","transparent":true,"opacity":1,"side":2,"materialType":"basic","position":{"x":-window.innerWidth/2+this.clBtnradius,"y":window.innerHeight/2-this.clBtnradius*3,"z":-150},"rotation":{"x":0,"y":0,"z":0},"scale":{"x":1,"y":1,"z":1},"showSortNub":7,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"wx":null,"wy":null,"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null}
w3Dobj.InitAddHudObject(jsonobj);

绑定模型事件

  touchStart (_obj, face, objs,event)  {
var _this=this;
if(_obj.name=="musicBack"){//开启背景音乐
_obj.visible=false;
this.w3Dobj.HudScene.children[9].visible=true;
this.music.stopBgm();
}else if(_obj.name=="noMusicBack"){//关闭背景音乐
_obj.visible=false; this.w3Dobj.HudScene.children[8].visible=true; this.music.playBgm(); }else if(_obj.name=="firstEye"){ this.selectFristEyeindex=event.changedTouches[0].identifier; var xpcobj= this.w3Dobj.commonFunc.findObject("xpc"); this.w3Dobj.camera.ooldPosition={ x: _this.w3Dobj.camera.position.x, y: _this.w3Dobj.camera.position.y, z: _this.w3Dobj.camera.position.z } this.w3Dobj.controls.ooldtarget={ x: _this.w3Dobj.controls.target.x, y: _this.w3Dobj.controls.target.y, z: _this.w3Dobj.controls.target.z } this.w3Dobj.camera.position.x=xpcobj.position.x; this.w3Dobj.camera.position.y=xpcobj.position.y+400; this.w3Dobj.camera.position.z=xpcobj.position.z; this.w3Dobj.controls.target.x=xpcobj.position.x+3000*Math.sin(xpcobj.rotation.y); this.w3Dobj.controls.target.y=xpcobj.position.y+200; this.w3Dobj.controls.target.z=xpcobj.position.z+3000*Math.cos(xpcobj.rotation.y); return false; } }

2.3、控制主角攻击

通过点击右侧招式 控制小人主角发大招,有冷却 运功时间

执行骨骼动画:

   //隐藏金钟罩
_this.hideJZZ();
//显示其它功夫控制器
_this.showKongFuControl();
clearInterval(_this.xpcobj.runTimeInterval);
//移动主角
_this.xpcobj.runTimeInterval = setInterval(() => {
if(_this.currentUnitObject){
_this.currentUnitObject.changeXPCPosition();
//修改摄像机
_this.currentUnitObject.changeCamera();
} //修改主角运动动画
if (Math.abs(_this.controlLever.speed.x) <= 0.1 && Math.abs(_this.controlLever.speed.y) <= 0.1) {
if (_this.xpcobj.currentAnimationNameName != "stand") {
_this.xpcobj.animation.doAnimation("stand")
_this.xpcobj.currentAnimationNameName = "stand";
}
}

2.4、敌人对战

这里涉及到敌人的移动,寻址。

我们要避开墙体

    /**
* 计算线 在法向量上的平移
* @param {any} x1
* @param {any} y1
* @param {any} x2
* @param {any} y2
* @param {any} moveLength >0 上移动 <0下移
*/
static LineTranslationByNormalvector(x1, y1, x2, y2,moveLength) {
//计算角度
var lineAngle = this.getAngle(x1, y1, x2, y2) / 180 * Math.PI;
var x1_new = x1 - moveLength * Math.sin(lineAngle);
var x2_new = x2 - moveLength * Math.sin(lineAngle);
var y1_new = y1 + moveLength * Math.cos(lineAngle);
var y2_new = y2 + moveLength * Math.cos(lineAngle);
return [x1_new, y1_new, x2_new, y2_new]
}
/**
* 计算两条线的焦点
* @param {any} a
* @param {any} b
* @param {any} c
* @param {any} d
*/
static segmentsIntr(a, b, c, d) {
var denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y);
if (denominator == 0) {
return false;
}
// 线段所在直线的交点坐标 (x , y)
var x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y)
+ (b.y - a.y) * (d.x - c.x) * a.x
- (d.y - c.y) * (b.x - a.x) * c.x) / denominator;
var y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x)
+ (b.x - a.x) * (d.y - c.y) * a.y
- (d.x - c.x) * (b.y - a.y) * c.y) / denominator;
/** 2 判断交点是否在两条线段上 **/
if (
// 交点在线段1上
(x - a.x) * (x - b.x) <= 0.0000001 && (y - a.y) * (y - b.y) <= 0.0000001
// 且交点也在线段2上
&& (x - c.x) * (x - d.x) <= 0.0000001 && (y - c.y) * (y - d.y) <= 0.0000001
) { // 返回交点p
return {
x: x,
y: y,
inline: true,
all: true
}
} else if (
// 交点在线段1上
(x - a.x) * (x - b.x)>= 0 && (y - a.y) * (y - b.y) >= 0
// 且交点也在线段2上
&& (x - c.x) * (x - d.x) >= 0 && (y - c.y) * (y - d.y) >= 0
) { // 返回交点p
return {
x: x,
y: y,
inline: false,
all: true
}
} else {
//否则不相交
return {
x: x,
y: y,
inline: false,
all: false
} } }

可以踢腿,可以发大招

执行发大招的骨骼动画,创建气体实例,让其沿着动作方向移动。

 _this.xpcobj.animation.doAnimation("taiji_k", 1, function (time, stepname) {
if (stepname == "qishi6") {
var qipao = wt3DObj.commonFunc.findObject("ZJqipao");
_this.ZJQiPao = qipao;
qipao.visible = true;
var lhp = _this.xpcobj.children[4].children[0].children[0].getWorldPosition()
var rhp = _this.xpcobj.children[3].children[0].children[0].getWorldPosition();
qipao.position.x = (lhp.x + rhp.x) / 2;
qipao.position.y = (lhp.y + rhp.y) / 2 + 30;
qipao.position.z = (lhp.z + rhp.z) / 2;
qipao.scale.x = 1;
qipao.scale.y = 1;
qipao.scale.z = 1; _this.currentUnitObject.QIPAOcollisionDetection(qipao); }
// console.log(stepname);
})

2.5、过关到下一关

打过了第一关,来到第二关。

切换关卡

 refreshScene(unit) {
var _this=this;
//回收
wx.triggerGC();
_this.unit=unit;
if (unit == 1) {
_this.currentUnitObject = new unit01BSS(_this,THREE,TWEEN);
_this.currentUnitObject.load();
}else if(unit==2){
if( _this.currentUnitObject){
_this.currentUnitObject.destory(function(){
_this.currentUnitObject = new unit02BSS(_this,THREE,TWEEN);
_this.currentUnitObject.load();
})
}else{
_this.currentUnitObject = new unit02BSS(_this,THREE,TWEEN);
_this.currentUnitObject.load();
} } }

三、设计游戏规则

开发一款游戏实属不易,尽管这款游戏尚未正式上线,但它已然是three.js在微信小游戏平台上的一次勇敢尝试与实践。 就当前阶段而言,这款游戏在画面设计、关卡设置以及整体可玩性和激励性方面,尚缺乏专业视角的打磨与指引。然而,我们深知罗马非一日建成,因此正稳步前行,逐步改进。 对于程序员而言,在现阶段的游戏设计中,他们主要聚焦于两大核心要素:一是游戏的可玩性,确保玩家能够沉浸其中,享受游戏带来的乐趣;二是游戏的性能,力求在保障游戏流畅运行的同时,为玩家提供稳定、高质量的游戏体验。这款游戏虽尚显稚嫩,但作为学习教程已绰绰有余,为我们后续的开发工作奠定了坚实的基础。

技术交流 1203193731@qq.com

如果你有什么要交流的心得 可邮件我

后面的课程将继续讲解

第二课:代码实现人物骨骼模型

第三课:小游戏控制杆的实现

第四课:地图的制作

第五课:敌人自主攻击

第六课:关卡设计、背景音乐、攻击音乐等

姑且按照上述的先安排后续系列教程吧。

技术交流 1203193731@qq.com

如果你有什么要交流的心得 可邮件我

其它相关文章:

如何基于three.js(webgl)引擎架构,实现3D医院、3D园区导航,3D科室路径导航

如何基于three.js(webgl)引擎架构,实现3D密集架库房,3D档案室(3d机器人取档、机器人盘点、人工查档、设备巡检)

如何使用webgl(three.js)实现煤矿隧道、井下人员定位、掘进面、纵采面可视化解决方案——第十九课(一)

如何使用webgl(three.js)实现3D消防、3D建筑消防大楼、消防数字孪生、消防可视化解决方案——第十八课(一)

webgl(three.js)3D光伏,3D太阳能能源,3D智慧光伏、光伏发电、清洁能源三维可视化解决方案——第十六课

如何用webgl(three.js)搭建一个3D库房,3D仓库3D码头,3D集装箱,车辆定位,叉车定位可视化孪生系统——第十五课

webgl(three.js)实现室内三维定位,3D定位,3D楼宇bim、实时定位三维可视化解决方案——第十四课(定位升级版)

使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课

如何用three.js(webgl)搭建3D粮仓、3D仓库、3D物联网设备监控-第十二课

如何用webgl(three.js)搭建处理3D隧道、3D桥梁、3D物联网设备、3D高速公路、三维隧道桥梁设备监控-第十一课

如何用three.js实现数字孪生、3D工厂、3D工业园区、智慧制造、智慧工业、智慧工厂-第十课

使用webgl(three.js)创建3D机房,3D机房微模块详细介绍(升级版二)

如何用webgl(three.js)搭建一个3D库房-第一课

如何用webgl(three.js)搭建一个3D库房,3D密集架,3D档案室,-第二课

使用webgl(three.js)搭建一个3D建筑,3D消防模拟——第三课

使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课

如何用webgl(three.js)搭建不规则建筑模型,客流量热力图模拟

使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课(炫酷版一)

使用webgl(three.js)搭建3D智慧园区、3D大屏,3D楼宇,智慧灯杆三维展示,3D灯杆,web版3D,bim管理系统——第六课

如何用webgl(three.js)搭建处理3D园区、3D楼层、3D机房管线问题(机房升级版)-第九课(一)

使用three.js,实现微信3D小游戏系列教程,框架篇(一)的更多相关文章

  1. 原生JS实现的h5小游戏-植物大战僵尸

    代码地址如下:http://www.demodashi.com/demo/12755.html 项目介绍 本项目是利用原生js实现的h5小游戏-植物大战僵尸,主要结合了一下自己对于h5小游戏的理解,结 ...

  2. js实现表格配对小游戏

    js实现表格配对小游戏 一.总结 一句话总结: 二.js实现表格配对 1.配对游戏案例说明 实例描述: 当用户点击两个相同的图案或字符后配对成功,全部配对成功后游戏获胜 案例008采用了大家常见的小游 ...

  3. JS实现植物大战僵尸小游戏,代码记录及效果展示

    前几天看到了一个很有趣的demo,用js制作植物大战僵尸小游戏,本着学习的心态,对照着做了一下,发现这里面的一些代码设计的确很精妙,这里分享下源码和效果,如果有需要,可以看下. 效果如下: 下载地址

  4. 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇)

    系列文章 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇) 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇) 前言 好久不见,很久没更新博客了,前段时间 ...

  5. C#微信公众号开发系列教程三(消息体签名及加解密)

    http://www.cnblogs.com/zskbll/p/4139039.html C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C ...

  6. 微信公众号开发系列教程一(调试环境部署续:vs远程调试)

    http://www.cnblogs.com/zskbll/p/4080328.html 目录 C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试 ...

  7. [js高手之路] html5 canvas系列教程 - 图片操作(drawImage,clip,createPattern)

    接着上文[js高手之路] html5 canvas系列教程 - 文本样式(strokeText,fillText,measureText,textAlign,textBaseline)继续,本文介绍的 ...

  8. C#微信公众号开发系列教程二(新手接入指南)

    http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...

  9. C#微信公众号开发系列教程六(被动回复与上传下载多媒体文件)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  10. C#微信公众号开发系列教程五(接收事件推送与消息排重)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

随机推荐

  1. Quartz.NET - 教程 1: 使用 Quartz

    译者注: 目录在这 Quartz.NET 3.x 教程 原文在这 Lesson 1: Using Quartz 在你使用调度器之前, 你需要先实例化(能猜到是谁么?). 要实例化, 请使用 ISche ...

  2. Dubbo 中的集群容错

    前言 在微服务架构中,服务间的依赖关系复杂且动态,任何一个服务的故障都可能引发连锁反应,导致系统雪崩.一个好的容错设计可以避免这些问题发生: 服务雪崩效应:单个服务崩溃或响应延迟可能导致调用链上的所有 ...

  3. win11的go安装

    背靠国外各大金主的go语言,在各种推动下,可谓是新的弄潮儿,但国内虽然各种推销,但从安装到开发再到维护,资料都少之又少,可能被垄断了解释权吧. 因此下面的也只是一个记录而已,是一次仅限于本人本机本阶段 ...

  4. Mono GC

    1.虽然是stw但mark阶段可以concurrent 2.并行mark就需要写屏障 3.unity的gc也不是扫描整个堆内存 https://schani.wordpress.com/2012/12 ...

  5. JMeter提取多个变量值总结

  6. 保存计算过程的计算器——java实现

    一.设计模型 按照MVC-Model View Control(模型,视图,控制器)的设计思想展开程序的设计和代码的编写.数据模型部分相当于MVC中的Model角色,视图设计部分给出的界面部分相当于M ...

  7. 机器人操作系统ROS2之简介

    什么是ROS2? ROS(机器人操作系统)是用于机器人应用的开源软件开发工具包.ROS 为各行业的开发者提供了一个标准的软件平台,帮助他们从研究和原型设计一直推进到部署和生产,从驱动程序到最先进的算法 ...

  8. WIN10桌面图标间距变得很大怎么办?

    转载来源: 作者:填鸭式教育受益者链接:https://www.zhihu.com/question/328872597/answer/1862986629来源:知乎 1.按Win+R打开运行,输入r ...

  9. 一个Controller网关根据请求参数和版本号调用分发多个Service和方法

    一个Controller网关根据请求参数和版本号分发Service 公司原有项目就是根据请求参数进行分发逻辑的,这次想着通过反射加入了版本号的分发,减轻各种版本的业务代码逻辑耦合度. 在一个项目中需要 ...

  10. VS2019 webApi(.net core2.2版本)上传到Gitee

    一.本地创建项目 创建本地项目,依次点击下一步,在选择"目标框架"时选择2.2, 二.配置swagger 1.添加依赖项 2.修改Startup.cs public void Co ...