您的位置:新葡亰496net > 服务器网络 > 新葡亰496net:用js重建星际争霸_基础知识_脚本之

新葡亰496net:用js重建星际争霸_基础知识_脚本之

发布时间:2019-12-12 08:15编辑:服务器网络浏览(168)

    演示地址

    说到做游戏,必不可少的需要用到寻路算法,一般游戏里的寻路算法大多数都以A*算法为主,这里也就实现了js里采用a*寻路的程序,在51js和蓝色都开了帖。 程序是以前写的,后来也没有修正或者精简,有冗余之处大家还见谅一下。 当然,这个寻路算法也不是最优化的,像幻宇开发的“交点寻径法”也是个中精品,两者可谓各有千秋,只是如果地图很大的情况下,我们会惊讶于“交点寻径法”的迅速。

    从本节开始,我们探讨如何使用VUE和WebPack开发一款类似于植物大战僵尸的前端游戏,当游戏完成后,情况如下:

    use A* to find path...

    新葡亰496net 1

    背景介绍 对很多人来说,javaScript是一种颇为神秘的语言,这种语言由浏览器解析,可以实现很复杂的功能,但在实际中又使用甚少。在以相对定位为基础的网站体系中,js并不是必不可少的,最早的浏览器并不支持js,只需使用纯静态的html,也能建立功能完备的网站。对于页面开发人员来说,使用js的时候估计也就是用于数据合法性检查而已。近年来,随着ajax概念崛起,js的使用有所增加,不过除了web邮箱等少数工具型的网站之外,其作用仍然是辅助性的。 实际上,js作为最流行的脚本语言,功能是非常强大的,笔者就曾经利用js来模拟星际争霸。大家都知道,星际争霸是即时战略游戏史上的里程碑,在玩家心目中的地位是不言而喻的,泡在各种各样的网吧里玩星际曾经是笔者生活的一部分。仅凭一腔热血,我就着手用js来开发星际,这是一次坚难的历程,充满了挫折,也享受到了乐趣,最后能够完成,却是开始时我也没有奢望到的。 js星际源码最早发布于无忧脚本的论坛里,得到了很多网友的好评,让我感动之余,也唯有更加努力。通过这次开发,我的js开发技术有了很多提高,还认识了许多喜欢js开发的朋友,幸哉!js星际现在的存放地址是

    设置起点 设置终点 设置障碍点 25,0;25,1;25,3;25,4;25,5;25,6;25,7;0,8;1,8;2,8;3,8;4,8;5,8;6,8;7,8;25,8;7,9;25,9;7,10;25,10;7,11;25,11;6,12;25,12;5,13;6,13;25,13;5,14;21,14;25,14;5,15;18,15;19,15;20,15;21,15;25,15;5,16;11,16;12,16;13,16;14,16;15,16;16,16;17,16;18,16;19,16;22,16;25,16;5,17;11,17;23,17;24,17;25,17;5,18;6,18;7,18;8,18;9,18;10,18;11,18;13,18;23,18;24,18;25,18;6,19;7,19;8,19;13,19;23,19;24,19;25,19;6,20;14,20;23,20;24,20;26,20;7,21;8,21;13,21;14,21;15,21;20,21;21,21;22,21;27,21;0,22;1,22;2,22;4,22;5,22;6,22;7,22;12,22;13,22;14,22;16,22;19,22;20,22;21,22;26,22;27,22;28,22;8,23;9,23;10,23;11,23;12,23;13,23;17,23;18,23;19,23;22,23;13,24;14,24;15,24;18,24;21,24;23,24;20,25;24,25;19,26;25,26;26,26;19,28;19,29;19,30;19,31

    这里写图片描述

    解决方案 寻径算法是游戏的基础,也是运算量最大的部分。我没有使用A*算法,因为对脚本来说开销太大了,而是自主开发一种新算法,称之为交点法,特点是线性寻径,运算量比较小,缺点是不能保证结果为最短路径。交点法的基本思路简述如下: 1.从起点到终点画直线,与障碍物相交时,总会出现对应的穿入点和穿出点。 2.从穿入点的两个方向同时绕行障碍物,选择先到达穿出点的路线作为前进路线,这样就得到了一条比较原始的路线。 3.对路线进行优化,判断两点是否形成通路,删除冗余点,得到最终的路径。 寻径时大量使用了判断是否障碍点的运算,一般的做法是遍历数组,分别比较才能得到结果。我把障碍点序列变成一个长字符串,通过字符串包含关系就可以判断出当前点是否障碍点,这样就减少了很多运算量。 js星际所实现的,相当于是星际争霸的开场部分,即采矿、制造建筑物和生产士兵,战斗部分略有涉及。在编码之前,就需要有许多准备工作,光是图片的制作就非常烦锁,需要万分的耐心才行。另外,我还用hta技术开发了一个地图编辑器,用于生成地图数据。 游戏里的控制面板比较精简,缩略地图和选择信息集成到右上角的一个小面板里,其他部分都属于游戏场景。每个移动单位有8个方向,以枪兵为例,需要用24张图片来表现站立和走动各种姿态。这些图片都集成在一张大图里,根据走动或站立情况,显示其中的对应部分,比如在走动时,判断出走动方向,一边移动枪兵位置,一边三张图片轮显,表现出走动的情形。 游戏初始化时,载入地图数据,根据不同的建筑物属性,一方面生成场景,另一方面生成障碍物列表,用于寻路之用。默认情况下,地图上有几个矿工,圈选后,点击目标可以自主行走,根据游戏要求,如果点击到的是矿石,就会在矿区和总部间来回走动,每次往返都会增加矿藏量。 至于哪一种建筑物能生产什么兵,每个兵需要多少资源,建筑物的生产顺序是什么,这些相对来说都比较容易,无非是做更多的图片处理和更多的逻辑判断而已,限于篇幅就不详细介绍了。

    更详细的讲解和代码调试演示过程,请点击链接

    经验分享 不用太担心功能的实现,因为js已经非常完善了,可以随心所欲地进行各种运算,使用绝对定位的机制,可以轻松创建界面,再利用时钟模拟多线程,实时移动图片,就可以表现动画了,问题主要体现在速度和性能上。因为js作为一种脚本语言,其计算性能无疑是先天不足的,同时浏览器也不支持directX和openGL等硬加速,动画能力无法另人满意。只有通过减轻运算量,合理分配动画资源,才能保证游戏的平滑运行。js星际的开发,正是处处遵循了这个原则,能简则简,能省则省,非常节约地使用各种资源,才最终得以实现。 千万不要在游戏中使用滤镜技术,特别是动态滤镜,滤镜渲染时会占用大量的cpu,在cpu占用达到80%以上时,游戏就会感觉比较卡。这一点和flash做的同类程序有明显区别,即使cpu占用率接近100%,flash程序仍然能保持相当的平滑。 凭心而论,客户端的游戏开发,应该还是以flash为主。与之相比,js的好处是可与网站无缝连接,也不需要安装插件。当然了,只要是好玩实用的游戏,即使是用js开发的,也未尝不可。

    游戏的设定如下,一系列外星飞船从天而降入侵地球,为了保护地球,玩家需要使用各种道具防止外星飞船落入底部的地球。如图所示,这些道具可以是箱子,也可以是卫星。当外星飞船被成功阻挡时,界面会弹出一系列奖章,也就是图片里面的"E",点击这些奖章后,玩家可以获得积分,一旦积分达到要求,玩家就可以选择炮台,也就是图片中红色的物体,炮台可以发射子弹,一旦子弹打中外星飞船,飞船就会从界面上消失,游戏的玩法其实和植物大战僵尸是如出一辙。本节,我们先完成代码基本架构的设计。

    先在本地目录新建一个VUE工程,在工程目录下打开index.html做如下修改:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimal-ui">
      <meta name="apple-mobile-web-app-capable" content="yes">
        <script type="text/javascript" src="./static/tweenjs-0.5.1.min.js"></script>
        <script type="text/javascript" src="./static/easeljs-0.7.1.min.js"></script>
        <script type="text/javascript" src="./static/movieclip-0.7.1.min.js"></script>
        <script type="text/javascript" src="./static/assets.js"></script>
        <script type="text/javascript">
          window.createjs = createjs
          window.assetsLib = lib
        </script>
        <title>Space Defender</title>
      </head>
      <body>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    

    在代码中,我们先把需要使用的若干类库给加载进来,在本项目中,我们新增了两个类库,一个是movieclip-0.7.1.min.js,另一个是assets.js,后者是一个资源类库,我们游戏所有的图片资源都压缩在这个类库里,后面我们会详细解读它的作用。

    接着进入src/目录,在里面修改App.vue:

    <template>
      <div id="app">
        <game-container></game-container>
      </div>
    </template>
    
    <script>
    import GameContainer from './components/gamecontainer'
    export default {
      name: 'app',
      components: {
        GameContainer
      }
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    

    它的主要作用是引入GameContainer组件,游戏的启动将由GameContainer组件加载如页面后开始,我们再看看该组件的实现,进入component/目录,在里面新增一个文件名为:gamecomponent.vue,然后添加如下代码:

    <template>
      <div>
        <header>
          <div class="row">
            <h1>Space Defender</h1>
          </div>
        </header>
        <div>
          <game-scene></game-scene>
        </div>
      </div>
    </template>
    
    <script>
      import GameScene from './GameSceneComponent'
      export default {
        components: {
          GameScene
        }
      }
    </script>
    
    <style scoped>
      body, h1, h2, p {
        margin: 0;
        padding: 0;
      }
    
    </style>
    

    新葡亰496net,它的逻辑简单,主要是在页面显示游戏标题,它最重要的作用是将GameScene引入页面,游戏的所有特效,场景都将由GameScene组件来完成,接着,我们重点查看GameScene的实现,在目录下新建一个文件名为gamescenecomponent.vue,打开后先完成以下代码:

    <template>
      <section id="game" class="row">
        <canvas id="canvas" width="640" height="1000">
        </canvas>
        ...
    </template>
    

    template部分的代码主要用来设计游戏界面,在上面代码中,我们现在页面加载一个html5的’画布‘组件,也就是canvas,游戏所有的特效显示将依赖canvas组件来完成。继续在template部分添加如下代码:

    <template>
      ....
       <div id="hud">
          <div>Lives: </div>
          <div>E: </div>
          <div>Waves: </div>
        </div>
    </template>
    

    上面代码的作用是在页面头部显示与游戏相关的数据,上面代码完对应的就是前面游戏界面截图中的头部显示内容:

    新葡亰496net 2

    这里写图片描述

    在游戏舞台的底部,我们添加按钮,以便玩家在页面上添加各种能消灭或阻止外星飞船入侵地球的障碍物,相关代码如下:

    <template>
      ....
      <div class="add-buttons">
          <a class="add-button" title="space Junk" data-type="SpaceJunk">J</a>
          <a class="add-button" title="Satellite" data-type="Satillite">S</a>
          <a class="add-button" title="Satellite " data-type="Satellite2">S </a>
          <a class="add-button" title="Castle" data-type="Castle">C</a>
          <a class="add-button" title="Castle " data-type="Castle2">C </a>
        </div>
    </template>
    

    上面代码完成后,在游戏界面的下方会出现一系列按钮,情形如下:

    新葡亰496net 3

    这里写图片描述

    接着,我们添加style标签代码,这部分代码其实是一段css,用来对template部分的html代码进行界面美化:

    <style scoped>
      #game {
        position: relative;
        width:  640px;
        height: 1000px;
        border: 1px solid black;
      }
      #canvas {
        position: absolute;
        top: 0px;
        left: 0px;
        background-color: #94A9B0;
      }
    
      #hud {
        position: absolute;
        width: 100%;
        height: 60px;
        background: rgba(0,0,0,0.5);
        color: white;
      }
    
      .add-buttons {
        position: absolute;
        width: 100%;
        height: 60px;
        bottom: 0;
        background: rgba(0, 0, 0, 0.5);
      }
    
      .add-button {
        display: inline-block;
        width: 50px;
        height: 50px;
        background-color: rgba(255, 255, 255, 0.3);
        color: white;
        text-decoration: none;
        text-align: center;
        line-height: 50px;
        curosr: pointer;
      }
    
      .add-button:hover {
        background-color: rgba(255, 255, 255, 0.6);
      }
    </style>
    

    现在我们开始集中精力完成程序的主逻辑代码,也就是script标签部分的代码,在文件中先添加如下代码:

    <script>
      export default {
        data () {
          return {
            gameWidth: 640,
            gameHeight: 1000,
            cjs: null,
            canvas: null,
            stage: null,
            lives: 20,
            energies: 120,
            assetsLib: null
          }
        },
    
        mounted () {
          this.init()
        },
    

    data()接口用于设置组件的内部数据,当组件被页面加载后,mounted()函数就会被执行,一旦它执行后,它会调用init()函数执行组件的初始化工作。我们看看init()初始化函数的实现:

    methods: {
          init () {
            this.cjs = window.createjs
            this.assetsLib = window.assetsLib
            this.canvas = document.getElementById('canvas')
            this.stage = new this.cjs.Stage(this.canvas)
    
            this.bgLayer = new this.cjs.Container()
            this.bgLayer.addChild(new this.assetsLib.Background())
            this.stage.addChild(this.bgLayer)
    
            this.boardLayer = this.Board()
            this.stage.addChild(this.boardLayer)
    
            this.effectLayer = new this.cjs.Container()
            this.stage.addChild(this.effectLayer)
    
            this.setHud()
    
            this.cjs.Ticker.setFPS(40)
            this.cjs.Ticker.addEventListener('tick', this.stage)
            this.cjs.Ticker.addEventListener('tick', this.tick)
          },
    
          tick () {
            if (this.cjs.Ticker.getPaused()) {
              return
            }
    
            this.livesSpan.textContent = this.lives
            this.energiesSpan.textContent = this.energies
            this.wavesSpan.textContent = 1
          },
    
          Board () {
            var board = new this.cjs.Container()
            board.x = 10
            board.y = 60
    
            board.rows = 10
            board.cols = 7
    
            this.tileWidth = 87
            this.tileHeight = 83
    
            var sprite = new this.assetsLib.Board()
            board.addChild(sprite)
            sprite.y = board.tileHeight
    
            return board
          },
    

    在init函数里,我们先获取createjs对象,图片的显示和特性都需要该类库提供支持。这里我们需要了解一下assetsLib,这个对象来自于index.html里面引入的类库assets.js,该游戏所使用的各种图形例如红色的炮台,入侵的宇宙飞船,阻挡飞船的箱子,卫星等,全是由flash制作出来的,这些图片资源全部打包在一个名为assets.fla文件中,这个文件必须使用flash相关软件才可以查看,为了能够在js代码中使用fla文件中的资源,通过flash软件就可以把.fla文件转为js代码文件,通过这个代码文件我们就可以获取由flash创建的各种图片资源。assetsLib就是由assets.js导出来的一个对象,通过调用该对象的接口,我们可以把flash创建的图片资源加载到页面上。

    我们看下面这段代码片段:

    this.bgLayer = new this.cjs.Container()
    this.bgLayer.addChild(new this.assetsLib.Background())
    this.stage.addChild(this.bgLayer)
    

    代码先创建了一个图层容器bgLayer,该图层主要用来绘制游戏的背景图,而背景图片就是assets.Background()接口返回的,我们把背景图绘制到bgLayer对象里,然后把该对象加入舞台容器控件,也就是stage,这样背景图片就可以显示在页面上了, 背景图的部分显示如下:

    新葡亰496net 4

    这里写图片描述

    我们接着看下面的代码片段:

            this.boardLayer = this.Board()
            this.stage.addChild(this.boardLayer)
    
            this.effectLayer = new this.cjs.Container()
            this.stage.addChild(this.effectLayer)
    

    新葡亰496net:用js重建星际争霸_基础知识_脚本之家,开发一款太空版植物大战僵尸的前端页游。这部分代码用给页面添加两个图层,一个是boardLayer,这个图层的作用是绘制玩家在页面上添加的物件,例如箱子,卫星,以及炮台。而effectLayer这个图层则用来绘制动态特效,例如飞动的E奖章,以及炮台射出的子弹。当我们把boardLayer图层添加到舞台容器后,我们就会发现页面背景图上方添加了一系列网格图案,玩家选择的所有物件都必须放置在网格里:

    新葡亰496net 5

    这里写图片描述

    最后的代码片段:

            this.setHud()
    
            this.cjs.Ticker.setFPS(40)
            this.cjs.Ticker.addEventListener('tick', this.stage)
            this.cjs.Ticker.addEventListener('tick', this.tick)
    

    setHud()的作用是初始化在页面头部的相关信息,例如玩家有多少条命,还剩多少能量值等,同时为底层的按钮点击设置响应函数。同时代码启动了一个定时器,每秒调用组件提供的tick函数刷新页面,实现页面的更新效果。我们继续阅读和解析余下的代码:

    setHud () {
            var addButtons = document.querySelectorAll('.add-button')
            this.livesSpan = document.getElementById('lives')
            this.energiesSpan = document.getElementById('energies')
            this.wavesSpan = document.getElementById('waves')
    
            for (var i = 0, len = addButtons.length; i < len; i  ) {
              var button = addButtons[i]
              button.onmousedown = this.addButtonOnMouseDown
            }
          },
    
          addButtonOnMouseDown (e) {
            if (this.cjs.Ticker.getPaused()) {
              return
            }
    
            var buildingType = this.dataset.type
            var cost = this.getBuildingCostByType()
            if (cost && this.energies >= cost) {
              this.energies -= cost
              this.buildingType = buildingType
              this.readyToPlaceBuilding()
            }
          },
    
          getBuildingCostByType (type) {
            // TODO
            return 0
          },
    
          readyToPlaceBuilding () {
            // TODO
          }
    

    在setHud中,我们通过getElementById获得html控件的对象,以便我们后面改变他们该显示的信息。同时给底部几个按钮设置点击响应函数,当按钮被点击是,组件的addButtonOnMouseDown()就会被调用,在该函数里,代码判断用户点击的按钮对应哪种物件,并判断当前玩家所有的资源是否足够建筑对应的建筑物,如果资源足够,那么就调用readyToPlaceBuidling()函数实现建筑物在页面上的显示。最后两个函数我们我们还没有实现,他们的代码将在下节课程中再实现。完成上面代码后,在控制台运行npm run dev命令,代码被浏览器加载后显示如下:

    新葡亰496net 6

    这里写图片描述

    本节我们搭建了游戏的基本框架,加载了游戏背景图以及一些基本控件,下节我们进进入到游戏主流程的开发中。

    更详细的讲解和代码调试演示过程,请点击链接

    更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

    新葡亰496net 7

    这里写图片描述

    本文由新葡亰496net发布于服务器网络,转载请注明出处:新葡亰496net:用js重建星际争霸_基础知识_脚本之

    关键词: