精华内容
下载资源
问答
  • 开发的前端游戏
  • 该项目是基于html+css+js开发的俄罗斯方块前端游戏 项目包含项目源码与项目说明文档 已部署到远程服务器,可直接访问: 也可以直接运行项目源码中的 html/index.html 开始游戏 还包含了一个Java版的源码,设计思路一样
  • 高级WEB前端游戏开发教程(完整)

    千次阅读 2019-03-16 10:59:24
    高级WEB前端游戏开发视频教程 下载地址:百度网盘

    高级WEB前端游戏开发视频教程

     

    下载地址:百度网盘

    展开全文
  • 前端游戏框架哪个好

    万次阅读 2018-08-14 00:44:08
    那么作为一个普通的前端开发者,如何取选择一个合适的游戏开发框架来学习和提高开发效率呢? 本场 Chat 将包含以下内容: 当今国内外流行的游戏开发框架有哪些 每个框架的特点以及优缺点 怎样去选择一个适合的...

    随着浏览器功能越来越强大,在网页端实现各种小游戏已经是家常便饭。微信小游戏出现后,游戏(特别是小型游戏)的开发已经进入了一个相当火爆的时期。那么作为一个普通的前端开发者,如何取选择一个合适的游戏开发框架来学习和提高开发效率呢?

    本场 Chat 将包含以下内容:

    1. 当今国内外流行的游戏开发框架有哪些
    2. 每个框架的特点以及优缺点
    3. 怎样去选择一个适合的框架来学习和使用
    4. 使用框架的注意事项

    我是一名前端开发人员,目前在一家新闻网站担任前端工作。我的公司不算大,技术部门加起来也就 20 来人,算一个中小型的公司,主要做的是宣传方面的工作。由于公司主要是做宣传方面的工作,所以也是比较注重宣传的形式以及展现出来的效果。

    正由于公司的性质,我所做的可能跟很多其他的前端工作者不一样。我所接触的技术,更多是 css3 动画,canvas 动画以及 webgl;而不是 vue、react 和 angular 这一些跟数据打交道比较多的框架和类库。

    处在这样一个环境下,让我对前端动画和小游戏有了一定程度的了解,下面我就和大家一起分享一下我在这方面的一些小见解。

    • 当今国内外流行的游戏开发框架有哪些。
    • 每个框架的特点以及优缺点。
    • 怎样去选择一个适合的框架来学习和使用。
    • 使用框架的注意事项。

    当今国内外流行的游戏开发框架有哪些

    开发动画和游戏,跟我们做数据交互不一样;游戏和动画开发起来比较复杂和耗时,是比较依赖框架和工具的。那么现在都有那些框架和工具呢?下面我们就来看一下。

    Name2D3D
    Three.jsnoyes
    Phaseryesno
    Createjsyesno
    Egretyesyes
    Cocos2d-jsyesno
    每个框架的特点以及优缺点

    上面表格的框架,是我总结出来,比较多同行关注并且学习使用的框架。

    Three.js

    一款历史比较悠久的开源项目,准确地说它不是一个游戏引擎,是一个 JavaScript 的 3D 库。然而我们可以用它来做各种的 3D 效果和游戏。

    优点:
    1. 专注于三维效果的 JavaScript 实现,能够在网页端实现大部分三维效果。

    2. 文档齐全,并具有搜索功能,方便快速查阅。

    3. 国外项目,目前仍然持续更新,不需要担心没人维护国外。

    4. 纯 js 代码开发,引入库即可用,不需要借助其他工具,方面接入任何的系统。

    缺点:
    1. 文档大部分是英文,需要具备一定英文水平才能读懂。

    2. 学习难度比较大,除了 js 代码基础,还需要具备高中的几何知识、webgl 知识、线性代数等等。

    3. 国内例子相对比较少,中文教程也不多,基本上都是看官网的例子和文档进行学习和研究。

    4. 网页 3d 效果的兼容性和性能问题,需要详细研究需求后才能使用。

    Phaser

    免费开源的 html5 游戏框架,支持 canvas 和 webgl 渲染,github 上 2w + star,比较不错的游戏框架。

    优点:
    1. 专注于 2d 游戏的 JavaScript 实现,集合了渲染、物理引擎,能够完成大部分小游戏。

    2. 使用方法简单,容易上手。

    3. 官方网站上有大量例子,代码都不负责,基本需要使用的效果都能找到对应的例子。

    4. 纯 js 代码开发,引入库即可用,不需要借助其他工具,方面接入任何的系统。

    5. 能够在微信小游戏中使用,并支持 typescript。

    缺点:
    1. 官方文档大部分是英文,并且没有搜索功能,需要按照类一层层往下搜索;假如在官方例子中找不到合适的代码,需要花时间研究文档。

    2. 目前稳定版本是 2.10,但是版本是社区维护;官方在开发新的 3.0 版本,暂时还在调整阶段。

    3. 由于纯代码编写,如果游戏逻辑复杂,代码会比较多和繁琐,需要在前期做比较好的规划。

    Createjs

    免费开源的 html5 游戏、动画和交互应用框架,adobe animate 软件基于该库来生成代码。

    优点:
    1. 动画和交互效果小能手,众多好看和高质量的 h5 展示效果使用 createjs 制作。

    2. 可以使用纯代码开发,或者使用 adobe animate 软件开发。

    3. 国内教程比较丰富,学习成本不大。

    4. 核心库分为四个,分别支持渲染、动画、预加载和音频,可以按需求加载对于库。

    缺点:
    1. 例子相对较少,遇到新或者复杂的需求,基本需要查看 api,无法寻找相似例子。

    2. 没有封装好粒子系统、骨骼动画、瓦片地图等等,轻量级的库,不适合大型游戏。

    3. 动画制作一般需要大量图片,涉及图片压缩和使用精灵图方面的技术。

    Egret

    国内优秀的游戏制作引擎,具备一整套的开发工具和教程。

    优点:
    1. 大型游戏制作能手,能够使用图形化工具制作游戏,性能优越。

    2. 使用 typescript 开发业务逻辑,代码规范。

    3. 中文文档和教程,学习方便。

    4. 同时支持 3d 和 2d,并且带有各种模块,游戏制作基本属于全能。

    5. 支持接入微信小游戏。

    缺点:
    1. 需要使用工具开发,不方便接入其他业务系统。

    2. 虽然具备中文文档,当时需要熟悉各种工具,学习成本不低。

    3. 例子相对较少,制作大型游戏需要大量填坑。

    Cocos2d-js

    历史比较悠久的游戏开发框架,类似 egret。

    优点:
    1. 2D 优秀开发引擎,同样使用图形化工具制作游戏,操作方便。

    2. 核心使用 JavaScript 编写。

    3. 中文文档和教程,学习方便,并且资料和例子丰富。

    4. 功能相当完整,游戏中需要的功能几乎都能够找到。

    5. 支持接入微信小游戏。

    缺点:
    1. 需要使用工具开发,不方便接入其他业务系统。

    2. 需要熟悉各种工具,学习成本不低,这点类似 egret。

    3. 擅长 2D 游戏开发,3D 游戏开发没有其它几个游戏框架专业。

    怎样去选择一个适合的框架来学习和使用

    学习:

    从学习上来说,我推荐初学者挑选纯代码进行开发的框架(three.js、createjs 和 phaser)进行学习。学习这类型的框架,虽然难度比较大,花时间比较长;但是能够提高自己的代码编写水平,还能更加深刻地理解游戏开发。

    如果有些小伙伴比较喜欢图形化界面操作,也可以尝试 egret 和 coco2d。这两个框架都是国内比较流行的游戏框架,学习哪一个都会有所帮助。

    如果有小伙伴之前是做 flash 的,我推荐使用 adobe animate 软件。

    这款软件其实就是以前的 flash 加上了 html5 的 canvas,它既可以生成 flash,也可以制作网页动画;制作的方法也以前的 flash 软件基本一样,只是多了 JavaScript 代码编写。

    工作:

    在工作中,特别是一些中小型公司,选择游戏框架就跟学习的时候不一样了。

    首先需要明确需要制作什么类型的游戏,是否需要接入自己公司的业务系统。

    • 如果是一些小游戏,类似跳一跳、推箱子等等,可以使用纯代码开发的框架。这样无论后面需求是否修改,是否需要接入业务系统,都能够方便进行修改。

    • 如果游戏的形式不太清晰,但是需要接入自己业务系统,例如游戏过后要抽奖、要统计数据等等;也建议优先选择纯代码开发的框架,毕竟纯代码开发的框架,就算前后端没有完全分离,也可以在页面上面放 php 或者 java 代码。

    • 如果需要制作比较复杂的游戏,图形化的开发工具是第一选择。图形化界面能够大大提升游戏开发的效率,而且游戏的结构也是清晰可见,性价比比较高。

    • 如果游戏需求比较复杂,而且需要接入自己的业务系统。这种情况,需要先测试图形化工具缩生成的代码是否能够顺利接入系统,然后再选择使用。

    使用框架的注意事项

    最后,给小伙伴们几个使用框架的建议,下面的都是我经过无数次踩坑总结出来的。

    1. 学习使用过程,遇到英文资料或者文档,建议不要使用翻译软件,通过例子和上下文去理解。

    2. 注意游戏的图片和模型加载,合理使用精灵图和框架的预加载功能。

    3. 开始开发之前,注意测试需要用到的框架属性,是否存在兼容性问题,特别是安卓和苹果手机的区别。

    4. 多复习一下高中的立体几何、解析几何,大学的线性代数、算法和图形图像。

    5. 跟美工打好关系,做游戏时,图片和模型的调整会非常多,没有他们的配合,很难进行。


    本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。

    阅读全文: http://gitbook.cn/gitchat/activity/5b62c74ca120e74da6655b63

    您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

    FtooAtPSkEJwnW-9xkCLqSTRpBKX

    展开全文
  • 前言偶然接触到CSS的3D属性, 就萌生了一种做3D游戏的想法.了解过css3D属性的同学应该都了解过perspective、perspective-origin、transform-st...

    前言

    偶然接触到CSS的3D属性, 就萌生了一种做3D游戏的想法.

    了解过css3D属性的同学应该都了解过perspectiveperspective-origintransform-style: preserve-3d这个三个属性值, 它们构成了CSS的3d世界.

    同时, 还有transform属性来对3D的节点进行平移、缩放、旋转以及拉伸.

    属性值很简单, 在我们平时的web开发中也很少用到.

    那用这些CSS3D属性可以做3D游戏吗?

    当然是可以的.

    即使只有沙盒, 也有我的世界这种神作.

    今天我就来带大家玩一个从未有过的全新3D体验.

    废话不多说, 我们先来看下效果:

    这里是试玩地址pc端畅玩[1]

    我们要完成这个迷宫大作战,需要完成以下步骤:

    1. 创建一个3D世界

    2. 写一个3D相机的功能

    3. 创建一座3D迷宫

    4. 创建一个可以自由运动的玩家

    5. 在迷宫中找出一条最短路径提示

    我们先来看下一些前置知识.

    做一款CSS3D游戏需要的知识和概念

    CSS3D坐标系

    在css3D中, 首先要明确一个概念, 3D坐标系.
    使用左手坐标系, 伸出我们的左手, 大拇指和食指成L状, 其他手指与食指垂直, 如图:

    WechatIMG315.png

    大拇指为X轴, 食指为Y轴, 其他手指为Z轴.
    这个就是CSS3D中的坐标系.

    透视属性

    perspective为css中的透视属性.

    这个属性是什么意思呢, 可以把我们的眼睛看作观察点, 眼睛到目标物体的距离就是视距, 也就是这里说的透视属性.

    大家都知道, 「透视」+「2D」= 「3D」.

    perspective: 1200px;
    -webkit-perspective:  1200px;
    复制代码
    

    3D相机

    在3D游戏开发中, 会有相机的概念, 即是人眼所见皆是相机所见.
    在游戏中场景的移动, 大部分都是移动相机.
    例如赛车游戏中, 相机就是跟随车子移动, 所以我们才能看到一路的风景.
    在这里, 我们会使用CSS去实现一个伪3d相机.

    变换属性

    在CSS3D中我们对3D盒子做平移、旋转、拉伸、缩放使用transform属性.

    • translateX 平移X轴

    • translateY 平移Y轴

    • translateZ 平移Z轴

    • rotateX 旋转X轴

    • rotateY 旋转Y轴

    • rotateZ 旋转Z轴

    • rotate3d(x,y,z,deg) 旋转X、Y、Z轴多少度

    注意:
    这里「先平移再旋转」和「先旋转再平移」是不一样的
    旋转的角度都是角度值.

    这里还有不清楚的同学可以参阅羽飞的这篇[juejin.cn/post/699769…[2]] 附带有demo

    矩阵变换

    我们完成游戏的过程中会用到矩阵变换.
    在js中, 获取某个节点的transform属性, 会得到一个矩阵, 这里我打印一下, 他就是长这个样子:

    var _ground = document.getElementsByClassName("ground")[0];
    var bg_style = document.defaultView.getComputedStyle(_ground, null).transform;
    console.log("矩阵变换---->>>",bg_style)
    复制代码
    
    WechatIMG307.png

    那么我们如何使用矩阵去操作transform呢?

    在线性变换中, 我们都会去使用矩阵的相乘.
    CSS3D中使用4*4的矩阵进行3D变换.
    下面的矩阵我均用二维数组表示.
    例如matrix3d(1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1)可以用二维数组表示:

    [
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ]
    复制代码
    

    平移即使使用原来状态的矩阵和以下矩阵相乘, dx, dy, dz分别是移动的方向x, y, z.

    [
        [1, 0, 0, dx],
        [0, 1, 0, dy],
        [0, 0, 1, dz],
        [0, 0, 0, 1]
    ]
    复制代码
    

    绕X轴旋转????, 即是与以下矩阵相乘.

    [
        [1, 0, 0, 0],
        [0, cos????, sin????, 0],
        [0, -sin????, cos????, 0],
        [0, 0, 0, 1]
    ]
    复制代码
    

    绕Y轴旋转????, 即是与以下矩阵相乘.

    [
        [cos????, 0, -sin????, 0],
        [0, 1, 0, 0],
        [sin????, 0, cos????, 0],
        [0, 0, 0, 1]
    ]
    复制代码
    

    绕Z轴旋转????, 即是与以下矩阵相乘.

    [
        [cos????, sin????, 0, 0],
        [-sin????, cos????, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ]
    复制代码
    

    具体的矩阵的其他知识这里讲了, 大家有兴趣可以自行下去学习.
    我们这里只需要很简单的旋转应用.

    开始创建一个3D世界

    我们先来创建UI界面.

    • 相机div

    • 地平线div

    • 棋盘div

    • 玩家div(这里是一个正方体)

    注意
    正方体先旋转在平移, 这种方法应该是最简单的.
    一个平面绕X轴、Y轴旋转180度、±90度, 都只需要平移Z轴.
    这里大家试过就明白了.

    我们先来看下html部分:

        <div class="camera">
            <!-- 地面 -->
            <div class="ground">
                <div class="box">
                    <div class="box-con">
                        <div class="wall">z</div>
                        <div class="wall">z</div>
                        <div class="wall">y</div>
                        <div class="wall">y</div>
                        <div class="wall">x</div>
                        <div class="wall">x</div>
                        <div class="linex"></div>
                        <div class="liney"></div>
                        <div class="linez"></div>
                    </div>
                    <!-- 棋盘 -->
                    <div class="pan"></div>
                </div>
            </div>
        </div>
    复制代码
    

    很简单的布局, 其中linexlineylinez是我画的坐标轴辅助线.
    红线为X轴, 绿线为Y轴, 蓝线为Z轴. 接着我们来看下正方体的主要CSS代码.

    ...
      .box-con{
          width: 50px;
          height: 50px;
          transform-style: preserve-3d;
          transform-origin: 50% 50%;
          transform: translateZ(25px) ;
          transition: all 2s cubic-bezier(0.075, 0.82, 0.165, 1);
      }
      .wall{
          width: 100%;
          height: 100%;
          border: 1px solid #fdd894;
          background-color: #fb7922;
        
      }
      .wall:nth-child(1) {
          transform: translateZ(25px);
      }
      .wall:nth-child(2) {
          transform: rotateX(180deg) translateZ(25px);
      }
      .wall:nth-child(3) {
          transform: rotateX(90deg) translateZ(25px);
      }
      .wall:nth-child(4) {
          transform: rotateX(-90deg) translateZ(25px);
      }
      .wall:nth-child(5) {
          transform: rotateY(90deg) translateZ(25px);
      }
      .wall:nth-child(6) {
          transform: rotateY(-90deg) translateZ(25px);
      }
    复制代码
    

    粘贴一大堆CSS代码显得很蠢.
    其他CSS这里就不粘贴了, 有兴趣的同学可以直接下载源码查看. 界面搭建完成如图所示:

    WechatIMG308.png

    接下来就是重头戏了, 我们去写js代码来继续完成我们的游戏.

    完成一个3D相机功能

    相机在3D开发中必不可少, 使用相机功能不仅能查看3D世界模型, 同时也能实现很多实时的炫酷功能.

    一个3d相机需要哪些功能?

    最简单的, 上下左右能够360度无死角观察地图.同时需要拉近拉远视距.

    通过鼠标交互

    鼠标左右移动可以旋转查看地图; 鼠标上下移动可以观察上下地图; 鼠标滚轮可以拉近拉远视距.

    ✅ 1. 监听鼠标事件

    首先, 我们需要通过监听鼠标事件来记录鼠标位置, 从而判断相机上下左右查看.

        /** 鼠标上次位置 */
        var lastX = 0, lastY = 0;
          /** 控制一次滑动 */
        var isDown = false;
          /** 监听鼠标按下 */
        document.addEventListener("mousedown", (e) => {
            lastX = e.clientX;
            lastY = e.clientY;
            isDown = true;
        });
            /** 监听鼠标移动 */
        document.addEventListener("mousemove", (e) => {
            if (!isDown) return;
            let _offsetX = e.clientX - lastX;
            let _offsetY = e.clientY - lastY;
            lastX = e.clientX;
            lastY = e.clientY;
            //判断方向
            var dirH = 1, dirV = 1;
            if (_offsetX < 0) {
                dirH = -1;
            }
            if (_offsetY > 0) {
                dirV = -1;
            }
        });
        document.addEventListener("mouseup", (e) => {
            isDown = false;
        });
    复制代码
    

    ✅ 2. 判断相机上下左右

    使用perspective-origin来设置相机的上下视线.
    使用transform来旋转Z轴查看左右方向上的360度.

    /** 监听鼠标移动 */
        document.addEventListener("mousemove", (e) => {
            if (!isDown) return;
            let _offsetX = e.clientX - lastX;
            let _offsetY = e.clientY - lastY;
            lastX = e.clientX;
            lastY = e.clientY;
            var bg_style = document.defaultView.getComputedStyle(_ground, null).transform;
            var camera_style = document.defaultView.getComputedStyle(_camera, null).perspectiveOrigin;
            var matrix4 = new Matrix4();
            var _cy = +camera_style.split(' ')[1].split('px')[0];
            var str = bg_style.split("matrix3d(")[1].split(")")[0].split(",");
            var oldMartrix4 = str.map((item) => +item);
            var dirH = 1, dirV = 1;
            if (_offsetX < 0) {
                dirH = -1;
            }
            if (_offsetY > 0) {
                dirV = -1;
            }
            //每次移动旋转角度
            var angleZ = 2 * dirH;
            var newMartri4 = matrix4.set(Math.cos(angleZ * Math.PI / 180), -Math.sin(angleZ * Math.PI / 180), 0, 0, Math.sin(angleZ * Math.PI / 180), Math.cos(angleZ * Math.PI / 180), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
            var new_mar = null;
            if (Math.abs(_offsetX) > Math.abs(_offsetY)) {
                new_mar = matrix4.multiplyMatrices(oldMartrix4, newMartri4);
            } else {
                _camera.style.perspectiveOrigin = `500px ${_cy + 10 * dirV}px`;
            }
            new_mar && (_ground.style.transform = `matrix3d(${new_mar.join(',')})`);
        });
    复制代码
    

    这里使用了矩阵的方法来旋转Z轴, 矩阵类Matrix4是我临时写的一个方法类, 就俩方法, 一个设置二维数组matrix4.set, 一个矩阵相乘matrix4.multiplyMatrices.
    文末的源码地址中有, 这里就不再赘述了.

    ✅ 3. 监听滚轮拉近拉远距离

    这里就是根据perspective来设置视距.

    //监听滚轮
    document.addEventListener('mousewheel', (e) => {
        var per = document.defaultView.getComputedStyle(_camera, null).perspective;
        let newper = (+per.split("px")[0] + Math.floor(e.deltaY / 10)) + "px";
        _camera.style.perspective = newper
    }, false);
    复制代码
    

    注意:
    perspective-origin属性只有X、Y两个值, 做不到和u3D一样的相机.
    我这里取巧使用了对地平线的旋转, 从而达到一样的效果.
    滚轮拉近拉远视距有点别扭, 和3D引擎区别还是很大.

    完成之后可以看到如下的场景, 已经可以随时观察我们的地图了.

    index1.gif

    这样子, 一个3D相机就完成, 大家有兴趣的可以自己下去写一下, 还是很有意思的.

    绘制迷宫棋盘

    绘制格子地图最简单了, 我这里使用一个15*15的数组.
    0」代表可以通过的路, 「1」代表障碍物.

    var grid = [
        0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
        0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
        1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
        0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
        0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
        0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
        1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
        1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
        0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1,
        0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
        1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
        1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
        0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0
    ];
    复制代码
    

    然后我们去遍历这个数组, 得到地图.
    写一个方法去创建地图格子, 同时返回格子数组和节点数组.
    这里的block是在html中创建的一个预制体, 他是一个正方体.
    然后通过克隆节点的方式添加进棋盘中.

    /** 棋盘 */
    function pan() {
        const con = document.getElementsByClassName("pan")[0];
        const block = document.getElementsByClassName("block")[0];
        let elArr = [];
        grid.forEach((item, index) => {
            let r = Math.floor(index / 15);
            let c = index % 15;
            const gezi = document.createElement("div");
            gezi.classList = "pan-item"
            // gezi.innerHTML = `${r},${c}`
            con.appendChild(gezi);
            var newBlock = block.cloneNode(true);
            //障碍物
            if (item == 1) {
                gezi.appendChild(newBlock);
                blockArr.push(c + "-" + r);
            }
            elArr.push(gezi);
        });
        const panArr = arrTrans(15, grid);
        return { elArr, panArr };
    }
    const panData = pan();
    复制代码
    

    可以看到, 我们的界面已经变成了这样.

    WechatIMG310.png

    接下来, 我们需要去控制玩家移动了.

    控制玩家移动

    通过上下左右w s a d键来控制玩家移动.
    使用transform来移动和旋转玩家盒子.

    ✅ 监听键盘事件

    通过监听键盘事件onkeydown来判断key值的上下左右.

    document.onkeydown = function (e) {
        /** 移动物体 */
        move(e.key);
    }
    复制代码
    

    ✅ 进行位移

    在位移中, 使用translate来平移, Z轴始终正对我们的相机, 所以我们只需要移动X轴和Y轴.
    声明一个变量记录当前位置.
    同时需要记录上次变换的transform的值, 这里我们就不继续矩阵变换了.

    /** 当前位置 */
    var position = { x: 0, y: 0 };
    /** 记录上次变换值 */
    var lastTransform = {
        translateX: '0px',
        translateY: '0px',
        translateZ: '25px',
        rotateX: '0deg',
        rotateY: '0deg',
        rotateZ: '0deg'
    };
    复制代码
    

    每一个格子都可以看成是二维数组的下标构成, 每次我们移动一个格子的距离.

     switch (key) {
        case 'w':
            position.y++;
            lastTransform.translateY = position.y * 50 + 'px';
            break;
        case 's':
            position.y--;
            lastTransform.translateY = position.y * 50 + 'px';
            break;
        case 'a':
            position.x++;
            lastTransform.translateX = position.x * 50 + 'px';
            break;
        case 'd':
            position.x--;
            lastTransform.translateX = position.x * 50 + 'px';
            break;
    }
    //赋值样式
    for (let item in lastTransform) {
        strTransfrom += item + '(' + lastTransform[item] + ') ';
    }
    target.style.transform = strTransfrom;
    复制代码
    

    到这里, 我们的玩家盒子已经可以移动了.

    注意
    在css3D中的平移可以看成是世界坐标.
    所以我们只需要关心X、Y轴. 而不需要去移动Z轴. 即使我们进行了旋转.

    ✅ 在移动的过程中进行旋转

    在CSS3D中, 3D旋转和其他3D引擎中不一样, 一般的诸如u3D、threejs中, 在每次旋转完成之后都会重新校对成世界坐标, 相对来说 就很好计算绕什么轴旋转多少度.

    然而, 笔者也低估了CSS3D的旋转.
    我以为上下左右滚动一个正方体很简单. 事实并非如此.

    CSS3D的旋转涉及到四元数和万向锁.

    比如我们旋转我们的玩家盒子. 如图所示:

    首先, 第一个格子(0,0)向上绕X轴旋转90度, 就可以到达(1.0); 向左绕Y轴旋转90度, 可以到达(0,1); 那我们是不是就可以得到规律如下:

    WechatIMG312.png

    如图中所示, 单纯的向上下, 向左右绕轴旋转没有问题, 但是要旋转到红色的格子, 两种不同走法, 到红色的格子之后旋转就会出现两种可能. 从而导致旋转出错.

    同时这个规律虽然难寻, 但是可以写出来, 最重要的是, 按照这个规律来旋转CSS3D中的盒子, 是不对的

    那有人就说了, 这不说的屁话吗?

    经过笔者实验, 倒是发现了一些规律. 我们继续按照这个规律往下走.

    • 旋转X轴的时候, 同时看当前Z轴的度数, Z轴为90度的奇数倍, 旋转Y轴, 否则旋转X轴.

    • 旋转Y轴的时候, 同时看当前Z轴的度数, Z轴为90度的奇数倍, 旋转X轴, 否则旋转Z轴.

    • 旋转Z轴的时候, 继续旋转Z轴

    这样子我们的旋转方向就搞定了.

    if (nextRotateDir[0] == "X") {
        if (Math.floor(Math.abs(lastRotate.lastRotateZ) / 90) % 2 == 1) {
            lastTransform[`rotateY`] = (lastRotate[`lastRotateY`] + 90 * dir) + 'deg';
        } else {
            lastTransform[`rotateX`] = (lastRotate[`lastRotateX`] - 90 * dir) + 'deg';
        }
    }
    if (nextRotateDir[0] == "Y") {
        if (Math.floor(Math.abs(Math.abs(lastRotate.lastRotateZ)) / 90) % 2 == 1) {
            lastTransform[`rotateX`] = (lastRotate[`lastRotateX`] + 90 * dir) + 'deg';
        } else {
            lastTransform[`rotateZ`] = (lastRotate[`lastRotateZ`] + 90 * dir) + 'deg';
        }
    }
    if (nextRotateDir[0] == "Z") {
        lastTransform[`rotate${nextRotateDir[0]}`] = (lastRotate[`lastRotate${nextRotateDir[0]}`] - 90 * dir) + 'deg';
    }
    复制代码
    

    然而, 这还没有完, 这种方式的旋转还有个坑, 就是我不知道该旋转90度还是-90度了.
    这里并不是简单的上下左右去加减.

    旋转方向对了, 旋转角度不知该如何计算了.

    具体代码可以查看源码[3].

    彩蛋时间

    ⚠️⚠️⚠️ 同时这里会伴随着「万向锁」的出现, 即是Z轴与X轴重合了. 哈哈哈哈~
    ⚠️⚠️⚠️ 这里笔者还没有解决, 也希望万能的网友能够出言帮忙~
    ⚠️⚠️⚠️ 笔者后续解决了会更新的. 哈哈哈哈, 大坑.

    好了, 这里问题不影响我们的项目. 我们继续讲如何找到最短路径并给出提示.

    最短路径的计算

    在迷宫中, 从一个点到另一个点的最短路径怎么计算呢? 这里笔者使用的是广度优先遍历(BFS)算法来计算最短路径.

    我们来思考:

    1. 二维数组中找最短路径

    2. 每一格的最短路径只有上下左右相邻的四格

    3. 那么只要递归寻找每一格的最短距离直至找到终点

    这里我们需要使用「队列」先进先出的特点.

    我们先来看一张图:

    WechatIMG313.png

    很清晰的可以得到最短路径.

    注意
    使用两个长度为4的数组表示上下左右相邻的格子需要相加的下标偏移量.
    每次入队之前需要判断是否已经入队了.
    每次出队时需要判断是否是终点.
    需要记录当前入队的目标的父节点, 方便获取到最短路径.

    我们来看下代码:

    //春初路径
    var stack = [];
    /**
     * BFS 实现寻路
     * @param {*} grid 
     * @param {*} start {x: 0,y: 0}
     * @param {*} end {x: 3,y: 3}
     */
    function getShortPath(grid, start, end, a) {
        let maxL_x = grid.length;
        let maxL_y = grid[0].length;
        let queue = new Queue();
        //最短步数
        let step = 0;
        //上左下右
        let dx = [1, 0, -1, 0];
        let dy = [0, 1, 0, -1];
        //加入第一个元素
        queue.enqueue(start);
        //存储一个一样的用来排查是否遍历过
        let mem = new Array(maxL_x);
        for (let n = 0; n < maxL_x; n++) {
            mem[n] = new Array(maxL_y);
            mem[n].fill(100);
        }
        while (!queue.isEmpty()) {
            let p = [];
            for (let i = queue.size(); i > 0; i--) {
                let preTraget = queue.dequeue();
                p.push(preTraget);
                //找到目标
                if (preTraget.x == end.x && preTraget.y == end.y) {
                    stack.push(p);
                    return step;
                }
                //遍历四个相邻格子
                for (let j = 0; j < 4; j++) {
                    let nextX = preTraget.x + dx[j];
                    let nextY = preTraget.y + dy[j];
    
                    if (nextX < maxL_x && nextX >= 0 && nextY < maxL_y && nextY >= 0) {
                        let nextTraget = { x: nextX, y: nextY };
                        if (grid[nextX][nextY] == a && a < mem[nextX][nextY]) {
                            queue.enqueue({ ...nextTraget, f: { x: preTraget.x, y: preTraget.y } });
                            mem[nextX][nextY] = a;
                        }
                    }
                }
            }
            stack.push(p);
            step++;
        }
    }
    /* 找出一条最短路径**/
    function recall(end) {
        let path = [];
        let front = { x: end.x, y: end.y };
        while (stack.length) {
            let item = stack.pop();
            for (let i = 0; i < item.length; i++) {
                if (!item[i].f) break;
                if (item[i].x == front.x && item[i].y == front.y) {
                    path.push({ x: item[i].x, y: item[i].y });
                    front.x = item[i].f.x;
                    front.y = item[i].f.y;
                    break;
                }
            }
        }
        return path;
    }
    
    复制代码
    

    这样子我们就可以找到一条最短路径并得到最短的步数.
    然后我们继续去遍历我们的原数组(即棋盘原数组).
    点击提示点亮路径.

    var step = getShortPath(panArr, { x: 0, y: 0 }, { x: 14, y: 14 }, 0);
    console.log("最短距离----", step);
    _perstep.innerHTML = `请在<span>${step}</span>步内走到终点`;
    var path = recall({ x: 14, y: 14 });
    console.log("路径---", path);
    /** 提示 */
    var tipCount = 0;
    _tip.addEventListener("click", () => {
        console.log("9999", tipCount)
        elArr.forEach((item, index) => {
            let r = Math.floor(index / 15);
            let c = index % 15;
            path.forEach((_item, i) => {
                if (_item.x == r && _item.y == c) {
                    // console.log("ooo",_item)
                    if (tipCount % 2 == 0)
                        item.classList = "pan-item pan-path";
                    else
                        item.classList = "pan-item";
                }
            })
        });
        tipCount++;
    });
    复制代码
    

    这样子, 我们可以得到如图的提示:

    WechatIMG314.png

    大功告成. 嘿嘿, 是不是很惊艳的感觉~

    尾声

    当然, 我这里的这个小游戏还有可以完善的地方 比如:

    • 可以增加道具, 拾取可以减少已走步数

    • 可以增加配置关卡

    • 还可以增加跳跃功能

    • ...

    原来如此, CSS3D能做的事还有很多, 怎么用全看自己的想象力有多丰富了.

    哈哈哈, 真想用CSS3D写一个「我的世界」玩玩, 性能问题恐怕会有点大.

    本文例子均在PC端体验较好.

    试玩地址[4]

    源码地址[5]

    欢迎大家拍砖指正, 笔者功力尚浅, 如有不当之处请斧正!

    文章粗浅, 望诸位不吝您的评论和点赞~

    注: 本文系作者呕心沥血之作, 转载须声明

    关于本文

    作者:起小就些熊

    https://juejin.cn/post/7000963575573381134

    推荐阅读

    纯CSS实现720全景?不用Three.js 也可以

    关注下方「前端开发博客」,回复 “加群”

    加入我们一起学习,天天进步

    如果觉得这篇文章还不错,来个【分享、点赞、在看】三连吧,让更多的人也看到~

    展开全文
  • 10月15号,国庆后来成都11天,准备转行做前端游戏开发。 虽然快步入三十,之前工作混日子,但是自己喜欢ui界面,之前又是做seo的。以后想做H5游戏开发,准备自学前端。csdn和github就是我经历的见证。 ...

    10月15号,国庆后来成都11天,准备转行做前端游戏开发。

    虽然快步入三十,之前工作混日子,但是自己喜欢ui界面,之前又是做seo的。以后想做H5游戏开发,准备自学前端。csdn和github就是我经历的见证。

    展开全文
  • 一个前端游戏的项目,由html、css和JavaScript编写而成,非常适合初学者!
  • 前端游戏框架记录

    千次阅读 2018-03-21 15:11:28
    1、lufylegend 比较小巧,基于canvas,有时间多学习下 官方网站: http://lufylegend.com/lufylegend API文档: ... 2、cocos2d-x ...HTML游戏框架,由独立的4个模块构成,小巧精干,值得学习。
  • 前端游戏引擎CreateJS与PixiJS之比较

    万次阅读 2017-12-17 16:35:08
    经过数年的发展演化,HTML 5 为基础的游戏引擎很多,本文将就其中两个著名的引擎CreateJS和PixiJS进行比较分析。对比了他们的API设计,功能,性能,工具支持,维护和开发几个方面。
  • arpg前端游戏框架

    千次阅读 2012-07-26 17:26:49
    请看http://blog.sina.com.cn/s/blog_a4d5872d01016dd9.html csdn博客不再更新
  • 有人需要 cocos2d 学习资料,看了下自己收集的资料,索性就把这一块内容全部分享出来,希望对大家有帮助。 有人需要 cocos2d 学习资料,看了下自己收集的资料,索性就把这一块内容全部分享出来,希望对大家有...
  • 前端开发小游戏

    2018-06-10 10:32:46
    一个前端开发新手练手小游戏,js和jQuery我的运用,以及简单移动框架的使用,通过注册点击事件来实现的一个点水果的小游戏
  • 前端项目游戏网站开发——剑网3,前端项目游戏网站开发——剑网3前端项目游戏网站开发——剑网3前端项目游戏网站开发——剑网3前端项目游戏网站开发——剑网3前端项目游戏网站开发——剑网3
  • H5游戏龙珠效果很好,微信打飞机,游戏飞机大战,html5霍比特人射箭类游戏源码
  • 游戏前端 游戏前端服务。 要在开发模式下运行,只需运行npm start 。 要打包部署文件,请运行npm run-script package 。
  • 游戏主题的网页前端

    2018-06-29 20:33:04
    主题关于游戏前端网页,首页index,点击游戏封面可跳转网页,点击不同的游戏代表作显示不同游戏封面。
  • 前端游戏贪吃蛇

    2018-11-20 11:16:59
    前端游戏(包括贪吃蛇、拼图、俄罗斯方块、找不同)
  • 前端游戏

    千次阅读 2019-01-19 08:40:52
    音乐小游戏,建议使用手机端打开,手指随便一划就是一个曲子。 点一下有趣的就来了 https://static.hfi.me/mikutap/ 注意!搬运内容,原页面(Origin Site): https://aidn.jp/mikutap 作者 daniwell (twitter) ...
  • 消消乐小游戏前端

    2018-09-28 11:54:17
    消消乐小游戏前端,不含后端,流行彩虹岛消消乐游戏,自己研究
  • 游戏前端——看您的细节把握能力

    万次阅读 多人点赞 2015-04-23 13:04:01
    大约一年前曾经通过两篇文章给大家推荐了几个前端游戏《玩游戏学前端——猜颜色、选择器》、《玩游戏学前端——颜色您了解多少?》,刚刚又给大家分享了《玩游戏学前端——钢笔工具边玩边学》,通过玩游戏来学东西真...
  • 游戏前端——钢笔工具边玩边学

    千次阅读 多人点赞 2015-04-23 11:56:40
    引入大约一年前曾经通过两篇文章给大家推荐了几个前端游戏《玩游戏学前端——猜颜色、选择器》、《玩游戏学前端——颜色您了解多少?》,如果大家看到过定然会发现,通过玩游戏来学东西真的轻松愉快。今天我们继续给...
  • 腾讯游戏页面前端 分块源码
  • 前端实战 游戏官网手风琴.wmv
  • 游戏类 这是游戏前端页面。
  • web前端游戏贪吃蛇源码下载
  • 前端游戏代码.zip

    2021-03-25 15:21:18
    这是我收集的前端游戏代码。。。。,有需要的可以下载看看
  • 利用前端知识设计飞机大战游戏
  • 前端2048小游戏

    2020-11-18 10:26:45
    这是个益智游戏,规则很简单,按上、下、左、右键,使游戏区域的所有方块向该方向滑动,每次滑动时,相碰的两个相同数字会合并。同时,空白的地方也会在随机出现一个数字方块(2 或者 4)。游戏目标,是想办法合成 ...
  • 写个前端游戏

    万次阅读 多人点赞 2020-04-24 19:23:00
    突发奇想,写个前端游戏让她开心开心。 虽然可以搜得到很多大佬写的小游戏,但觉得自己写的会更有意义! 一、游戏描述 点击开始游戏就可以玩碰碰球小游戏啦 若小球碰到下边框时,游戏结束。需要刷新页面后重新开始...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 79,558
精华内容 31,823
关键字:

前端游戏