├── .gitattributes ├── README.md ├── mouseHit_tutorials ├── core-play -design │ └── Let’s Build Our Own Wack-A-Mole Game with Cocos Creator.pdf └── game-periphery-design │ └── Let’s Build Our Own Wack-A-Mole Game with Cocos Creator(Second).pdf ├── mouseHit_教程 ├── 核心玩法设计 │ └── 用CocosCreator快速制作打地鼠游戏.pdf └── 游戏外围设计 │ └── 用CocosCreator快速制作打地鼠游戏(二).pdf └── tankWar_教程 ├── 用 Cocos Creator 制作坦克大战游戏(一) ├── images │ ├── 1568103250049.png │ ├── 1568103350497.png │ ├── 1568103544022.png │ ├── 1568103811813.png │ ├── 1568104166126.png │ ├── 1568104441230.png │ ├── 1568104592244.png │ ├── 1568104613897.png │ ├── 1568105116383.png │ ├── 1568105273056.png │ ├── 1568106338745.png │ ├── 1568107080376.png │ ├── 1568107440350.png │ ├── 1568107563592.png │ ├── 1568108084038.png │ ├── 1568108838000.png │ ├── 1568109324979.png │ ├── 1568109516700.png │ ├── 1568109550756.png │ ├── 1568110010714.png │ ├── 1568111157524.png │ ├── 1568111496212.png │ ├── 1568113927803.png │ ├── 1568114022613.png │ ├── 1568114187166.png │ └── GIF.gif ├── 用 Cocos Creator 制作坦克大战游戏(一).md └── 用 Cocos Creator 制作坦克大战游戏(一).pdf └── 用 Cocos Creator 制作坦克大战游戏(二) ├── CocosCreator开发坦克大战游戏(二).md ├── CocosCreator开发坦克大战游戏(二).pdf └── images ├── 1571134226766.png ├── 1571135093072.png ├── 1571135630608.png ├── 1571135988842.png ├── 1571136089188.png ├── 1571136183310.png ├── 1571139257986.png ├── 1571139479954.png ├── 1571139651485.png ├── 1571142694979.png ├── 1571142724512.png ├── 1571209420292.png ├── 1571212037751.png ├── 1571212575077.png ├── 1571213607552.png ├── 1571217426613.png ├── 1571218274828.png ├── 1571220278417.png ├── 1571220427137.png ├── 1571227326639.png ├── 1571227581285.png ├── 1571227962953.png ├── 1571228602680.png ├── 1571229153093.png ├── 1571229170529.png ├── 20191015.gif ├── 20191016.gif ├── 20191017.gif ├── 20191018.gif └── 20191019.gif /.gitattributes: -------------------------------------------------------------------------------- 1 | mouseHit_教程/ 2 | mouseHit_tutorials/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CocosCreator-game-tutorials 2 | -------------------------------------------------------------------------------- /mouseHit_tutorials/core-play -design/Let’s Build Our Own Wack-A-Mole Game with Cocos Creator.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/mouseHit_tutorials/core-play -design/Let’s Build Our Own Wack-A-Mole Game with Cocos Creator.pdf -------------------------------------------------------------------------------- /mouseHit_tutorials/game-periphery-design/Let’s Build Our Own Wack-A-Mole Game with Cocos Creator(Second).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/mouseHit_tutorials/game-periphery-design/Let’s Build Our Own Wack-A-Mole Game with Cocos Creator(Second).pdf -------------------------------------------------------------------------------- /mouseHit_教程/核心玩法设计/用CocosCreator快速制作打地鼠游戏.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/mouseHit_教程/核心玩法设计/用CocosCreator快速制作打地鼠游戏.pdf -------------------------------------------------------------------------------- /mouseHit_教程/游戏外围设计/用CocosCreator快速制作打地鼠游戏(二).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/mouseHit_教程/游戏外围设计/用CocosCreator快速制作打地鼠游戏(二).pdf -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103250049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103250049.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103350497.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103350497.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103544022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103544022.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103811813.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568103811813.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104166126.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104166126.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104441230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104441230.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104592244.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104592244.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104613897.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568104613897.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568105116383.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568105116383.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568105273056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568105273056.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568106338745.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568106338745.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107080376.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107080376.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107440350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107440350.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107563592.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568107563592.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568108084038.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568108084038.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568108838000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568108838000.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109324979.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109324979.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109516700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109516700.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109550756.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568109550756.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568110010714.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568110010714.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568111157524.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568111157524.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568111496212.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568111496212.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568113927803.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568113927803.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568114022613.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568114022613.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568114187166.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/1568114187166.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/GIF.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/images/GIF.gif -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/用 Cocos Creator 制作坦克大战游戏(一).md: -------------------------------------------------------------------------------- 1 | # 用 Cocos Creator 制作坦克大战游戏(一) 2 | 3 | 4 | 5 | ## *前言* 6 | 7 | 欢迎大家到[CocosCreator](https://discuss.cocos2d-x.org/)论坛发帖,将你在开发过程中遇到的任何问题发出来与大家一起讨论。本篇文章不教学任何代码的编辑,而是带领大家学习制作TiledMap资源,因为这是制作坦克大战游戏的关键。开始学习教程之前,请准备好开发环境。 8 | 9 | 如果你在我们的教程中遇到麻烦,请学习一下文档: 10 | 11 | - 准备开发环境 12 | - [Cocos Creator 2.1.2](http://cocos2d-x.org/filedown/CocosCreator_v2.1.2_win) 13 | - [Tiled Map Editor 0.10.2](https://github.com/Jno1995/TiledMapEditor) 14 | - [文档](https://docs.cocos.com/creator/manual/en/) 15 | - [TiledMap Component Reference](https://docs.cocos.com/creator/manual/en/components/tiledmap.html?h=tiledmap) 16 | 17 | ------ 18 | 19 | 20 | 21 | ## *我们开始吧!* 22 | 23 | 目前CocosCreator最新版本只支持1.0.0版本及以下版本的TiledMap资源。 24 | 25 | ### 1、了解并使用TiledMapEditor 26 | 27 | 当你下载并解压我提供的TiledMapEditor安装包之后,请找到`tiled.exe`应用程序,双击它。这时候在windows系统下会出现如下界面: 28 | 29 | ![1568103250049](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568103250049.png) 30 | 31 | 选择菜单File出现如下菜单选项: 32 | 33 | ![1568103350497](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568103350497.png) 34 | 35 | 选择New...出现如下窗口: 36 | 37 | ![1568103544022](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568103544022.png) 38 | 39 | 我们解读一下该界面的各个属性的作用: 40 | 41 | * Map 42 | * Orientation 43 | * ![1568103811813](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568103811813.png) 44 | * Orthogonal:(90度角地图)可以用于RPG游戏地图,也可考虑用于类似超级玛丽一样的横版过关游戏 45 | * Isometric:(45度角)可用于RPG游戏地图,也可以考虑战棋类游戏 46 | * Isometric(Staggered):(45度交错)地图呈现为四边形,边界位置使用1/2的三角形地图块呈现 47 | * Tile layer format 48 | * ![1568104166126](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568104166126.png) 49 | * 图层保存格式:XML、Base64(无压缩、gzip、zlib)、CSV 50 | * Tile render order 51 | * ![1568104441230](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568104441230.png) 52 | * 地图坐标方向:默认是Right Down(右 下)也就是说左上角为顶点向右为X轴,向下为Y轴 53 | * Map size 54 | * ![1568104592244](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568104592244.png) 55 | * 地图大小,也就是创建的地图中拥有 Width * Height 个地图块 56 | * Tile size 57 | * ![1568104613897](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568104613897.png) 58 | * 块大小,此处对应的是像素点,也就是每个图块所占的宽高 59 | 60 | 了解每个属性的作用之后,点击`OK`创建TMX地图资源。按住`Ctrl + S`保存资源,这时候我们将它命名为`tankWarMap0`。 61 | 62 | 我们继续为地图添加图块资源: 63 | 64 | 点击Tilesets进入图集管理窗口 65 | 66 | ![1568105273056](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568105273056.png) 67 | 68 | 点击New Tileset,出现如下窗口 69 | 70 | ![1568106338745](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568106338745.png) 71 | 72 | * Name: 73 | * 图集名称 74 | * Type: 75 | * Based on Tileset Image 76 | * 基于图集本身尺寸的模式 77 | * Collection of Images 78 | * 可以导入任意图片 79 | * Source: 80 | * 图集路径 81 | * Use transparent color: 82 | * 将图集上的透明区域替换成指定颜色 83 | * Tile width / Tile height: 84 | * 图块大小 85 | * Margin: 86 | * 图块边缘像素填充 87 | * Spacing: 88 | * 图块间隔像素填充 89 | 90 | 一切确定之后,点击`OK`,导入图集。 91 | 92 | ![1568107080376](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568107080376.png) 93 | 94 | 每一个图块,都有它对应的Tile ID,这对于判断图块的类型非常有用: 95 | 96 | ![1568108838000](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568108838000.png) 97 | 98 | 接着,我们得为地图添加Tile Layer和Object Layer。首先我们找到Tile Layers区域: 99 | 100 | ![1568107440350](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568107440350.png) 101 | 102 | 添加如下图所示的Tile Layer和Object Layer(这里要注意每个Layer的上下层级关系,建议与下图保持一致): 103 | 104 | ![1568107563592](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568107563592.png) 105 | 106 | 为什么这里要注意上下层级关系呢?因为当TiledMap资源导入到CocosCreator编辑器中,并加入到场景中时,它的层级结构会出现颠倒: 107 | 108 | ![1568108084038](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568108084038.png) 109 | 110 | 并且在CocosCreator的UI系统中,下层节点会掩盖上层节点,所以我们需要注意这一点,避免出现问题。 111 | 112 | 选择如下图所示的区域,之后在layer画布中点击鼠标左键不放,然后拖动一段距离,之后松开。这样就完成了第一次的地图绘制: 113 | 114 | ![1568109324979](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568109324979.png) 115 | 116 | 最终,我的完成品是这样的: 117 | 118 | ![1568109516700](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568109516700.png) 119 | 120 | ![1568109550756](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568109550756.png) 121 | 122 | 关于TiledMapEditor的基础操作基本介绍完了,其它的可以自行探索。 123 | 124 | --- 125 | 126 | 127 | 128 | ### 2、在CocosCreator中使用TiledMap资源 129 | 130 | 本节将指导大家导入TiledMap资源到CocosCreator中,以及熟悉CocosCreator的CCTiledMap组件。 131 | 132 | #### 2.1、导入TileMap资源到CocosCreator中 133 | 134 | 找到已经保存在本地的TileMap资源: 135 | 136 | ![1568111157524](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568111157524.png) 137 | 138 | 全选它们,然后拖入CocosCreator编辑器的assets/res/maps目录下: 139 | 140 | ![1568111496212](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568111496212.png) 141 | 142 | 这样就成功导入资源了。 143 | 144 | #### 2.2、让TiledMap资源在场景中显示 145 | 146 | 两种方式可以让TiledMap资源在场景中显示: 147 | 148 | * 添加TiledMap组件,并将TiledMap资源的.tmx资源拖入到Tmx Asset属性框中: 149 | * ![1568113927803](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568113927803.png) 150 | * 将TiledMap资源中的.tmx资源拖入到场景中: 151 | 152 | 以上两种方法最后都能正确加载并显示TiledMap资源,效果如下: 153 | 154 | ![1568114022613](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568114022613.png) 155 | 156 | 最后,我们需要将Canvas的尺寸调整为和TiledMap组件的尺寸一致,这样能够让游戏看起来更美观。 157 | 158 | ![1568114187166](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/1568114187166.png) 159 | 160 | --- 161 | 162 | ### 3、结尾 163 | 164 | 本篇教程是对坦克大战游戏教程的热身教程。当你熟练掌握TiledMapEditor之后,也就能够制作出很多有趣的地图了。 165 | 166 | 展示一下完整demo的效果图: 167 | 168 | ![](https://github.com/Jno1995/CocosCreator-game-tutorials/blob/master/tankWar_%E6%95%99%E7%A8%8B/%E7%94%A8%20Cocos%20Creator%20%E5%88%B6%E4%BD%9C%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%B8%B8%E6%88%8F(%E4%B8%80)/images/GIF.gif) 169 | 170 | --- 171 | 172 | 谢谢大家,下面是完整项目的链接,请你使用CocosCreator2.1.2版本打开。 173 | 174 | [Complete Demo](https://github.com/Jno1995/Tank-War) 175 | 176 | -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/用 Cocos Creator 制作坦克大战游戏(一).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(一)/用 Cocos Creator 制作坦克大战游戏(一).pdf -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/CocosCreator开发坦克大战游戏(二).md: -------------------------------------------------------------------------------- 1 | # 用 Cocos Creator 制作坦克大战游戏(二) 2 | 3 | 4 | 5 | ## *前言* 6 | 7 | 欢迎大家到[CocosCreator](https://discuss.cocos2d-x.org/)论坛发帖,将你在开发过程中遇到的任何问题发出来与大家一起讨论。在上一篇文章中我们学习了如何使用TiledMap制作地图资源,并在CocosCreator中使用地图资源。在本篇教程,我们开始学习编写一个相对完整的坦克大战游戏。我们已经为大家准备好了新工程:[Tank-War-New](https://github.com/Jno1995/Tank-War-New),你可以在 CocosCreator2.1.2 中打开它并跟着我的教程学习。 8 | 9 | 如果你在我们的教程中遇到麻烦,请学习一下文档: 10 | 11 | - 准备开发环境 12 | - [Cocos Creator 2.1.2](http://cocos2d-x.org/filedown/CocosCreator_v2.1.2_win) 13 | - [Tiled Map Editor 0.10.2](https://github.com/Jno1995/TiledMapEditor) 14 | - [文档](https://docs.cocos.com/creator/manual/en/) 15 | - [TiledMap Component Reference](https://docs.cocos.com/creator/manual/en/components/tiledmap.html?h=tiledmap) 16 | 17 | ------ 18 | 19 | 20 | 21 | ## *我们开始吧!* 22 | 23 | ### 1、编写游戏数据脚本 24 | 25 | 游戏的各种表现,其过程都是在对游戏数据执行读写操作。通过读取游戏数据,我们可以知道当前的游戏进度、角色状态等等,而写入数据,我们可以操控角色执行任务、保存游戏进度等等。首先在 ./assets/scripts/ 目录下创建 gameData 文件夹,主要用于保存游戏数据脚本。在 gameData 文件夹下创建 GameConfig.js 脚本,主要用于记录游戏配置数据,参考以下代码: 26 | 27 | ``` 28 | var GameConfig = { 29 | PlayerNum: 1, //玩家数量 30 | }; 31 | 32 | module.exports = GameConfig; 33 | ``` 34 | 35 | module.exports 语句是 JS 语言的模块化脚本代码,可以让其它脚本对模块化后的数据脚本中的数据进行读写操作。详细请阅读文档:[Modularize Script](https://docs.cocos.com/creator/manual/en/scripting/modular-script.html)。 36 | 37 | 在 gameData 文件夹下创建 GameConst.js 脚本,主要用于记录游戏中的各种常量数据,参考以下代码: 38 | 39 | ``` 40 | var GameEnum = require("./GameEnum"); 41 | var GameConst = { 42 | GidToTileType:[ 43 | GameEnum.TileType.tileNone, 44 | 45 | GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileGrass, GameEnum.TileType.tileGrass, GameEnum.TileType.tileSteel, GameEnum.TileType.tileSteel, 46 | GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileGrass, GameEnum.TileType.tileGrass, GameEnum.TileType.tileSteel, GameEnum.TileType.tileSteel, 47 | 48 | GameEnum.TileType.tileWall, GameEnum.TileType.tileWall, GameEnum.TileType.tileRiver, GameEnum.TileType.tileRiver, GameEnum.TileType.tileKing, GameEnum.TileType.tileKing, 49 | GameEnum.TileType.tileWall, GameEnum.TileType.tileWall, GameEnum.TileType.tileRiver, GameEnum.TileType.tileRiver, GameEnum.TileType.tileKing, GameEnum.TileType.tileKing, 50 | 51 | GameEnum.TileType.tileKing, GameEnum.TileType.tileKing, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, 52 | GameEnum.TileType.tileKing, GameEnum.TileType.tileKing, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone, GameEnum.TileType.tileNone 53 | ], 54 | Dirction: ["up","left","down","right"], 55 | DirctionRex: [/up/,/left/,/down/,/right/], 56 | EnemyTankTypes: [ 57 | { 58 | name: "armor", 59 | score: 500, 60 | speed: 0.4 61 | }, 62 | { 63 | name: "fast", 64 | score: 250, 65 | speed: 0.2 66 | }, 67 | { 68 | name: "normal", 69 | score: 100, 70 | speed: 0.4 71 | } 72 | ], 73 | armorTankNum: 4, 74 | fastTankNum: 3, 75 | normalTankNum: 2, 76 | PlayerTankReviveTimes: 5, 77 | EnemyTankAmount: 20 78 | }; 79 | module.exports = GameConst; 80 | ``` 81 | 82 | 在 gameData 文件夹下创建 GameEnum.js 脚本,主要用于记录游戏中的各种枚举数据,参考以下代码: 83 | 84 | ``` 85 | var GameEnum = { 86 | TankFlag: cc.Enum({ 87 | Player: 0, 88 | Enemy: 1 89 | }), 90 | TileType: cc.Enum({ 91 | tileNone: 0, 92 | tileGrass: 1, 93 | tileSteel: 2, 94 | tileWall: 3, 95 | tileRiver: 4, 96 | tileKing: 5 97 | }), 98 | TileGroup: cc.Enum({ 99 | default: 0, 100 | playerBullet: 1, 101 | playerTank: 2, 102 | enemyTank: 3, 103 | enemyBullet: 4 104 | }) 105 | }; 106 | 107 | module.exports = GameEnum; 108 | ``` 109 | 110 | 打开 CocosCreator 游戏引擎的编辑器,打开菜单 Project -> Project Settings...,选择 Group Manager 界面,对游戏的 Group 进行如下设置,并点击 Save 保存设置: 111 | 112 | ![1571218274828](./images/1571218274828.png) 113 | 114 | cc.game.groupList 负责记录着当前游戏的 group 分组数据,我们需要用到它。 115 | 116 | --- 117 | 118 | 119 | 120 | ### 2、布置游戏开始界面 121 | 122 | 首先预览一下我布置好的游戏开始界面: 123 | 124 | ![1571134226766](./images/1571134226766.png) 125 | 126 | 参考下图设置Canvas节点的Canvas组件: 127 | 128 | ![1571135093072](./images/1571135093072.png) 129 | 130 | 根据设计分辨率,搭建游戏开始场景。参考下图的节点树添加节点: 131 | 132 | ![1571135630608](./images/1571135630608.png) 133 | 134 | 该界面所需要的图集资源名称为 start。 135 | 136 | 在 ./assets/ 目录下创建 Start.js 脚本,并添加到 Canvas 节点中。该脚本主要负责处理游戏开始界面的用户操作。参考如下代码: 137 | 138 | ``` 139 | var GameConfig = require("./gameData/GameConfig"); 140 | cc.Class({ 141 | extends: cc.Component, 142 | 143 | properties: { 144 | gamePlayerCount: { 145 | default: null, 146 | type: cc.ToggleContainer 147 | }, 148 | }, 149 | 150 | start () { 151 | this.initGameLoginView(); 152 | }, 153 | 154 | //初始化游戏登录开始界面 155 | initGameLoginView () { 156 | switch (GameConfig.PlayerNum) { 157 | case 1: 158 | this.gamePlayerCount.node.getChildByName("Toggle OnePlayer").getComponent(cc.Toggle).isChecked = true; 159 | break; 160 | case 2: 161 | console.log(this.gamePlayerCount.node); 162 | this.gamePlayerCount.node.getChildByName("Toggle DoublePlayer").getComponent(cc.Toggle).isChecked = true; 163 | break; 164 | } 165 | }, 166 | 167 | //选择玩家人数的回调 168 | onGamePlayerNumToggleChecked (event, CoustomEventData) { 169 | switch (CoustomEventData) { 170 | case "onePlayer": 171 | GameConfig.PlayerNum = 1; 172 | break; 173 | case "doublePlayer": 174 | GameConfig.PlayerNum = 2; 175 | break; 176 | } 177 | }, 178 | }); 179 | ``` 180 | 181 | 该用户组件的属性检查器界面绑定情况如下: 182 | 183 | ![1571139651485](./images/1571139651485.png) 184 | 185 | Button PlayGame 节点的 Button 组件的属性检查器界面绑定情况如下,此处绑定的 Game.js 脚本将在第 4 节中讲解: 186 | 187 | ![1571135988842](./images/1571135988842.png) 188 | 189 | Toggle OnePlayer 节点的 Toggle 组件的属性检查器界面的绑定情况如下: 190 | 191 | ![1571136089188](./images/1571136089188.png) 192 | 193 | Toggle DoublePlayer 节点的属性检查器界面的绑定情况如下: 194 | 195 | ![1571136183310](./images/1571136183310.png) 196 | 197 | 为 Nodes Login Game 节点添加 CCBlockInputEvents 组件,可以防止误触到游戏战斗界面。属性检查器面板如下所示: 198 | 199 | ![1571227581285](./images/1571227581285.png) 200 | 201 | 完成上述界面布局与组件数据绑定之后,就完成了游戏开始界面的搭建。 202 | 203 | --- 204 | 205 | 206 | 207 | ### 3、编写对象池管理脚本 208 | 209 | 坦克大战游戏过程中,会不断有节点销毁和创建的需求,比如子弹的发射与销毁。因为节点的创建和销毁都有一系列的子逻辑需要执行,为了能够彻底清除节点对象的数据,执行这些代码都需要消耗游戏性能。当大量节点都重复创建和销毁时,就会出现游戏性能下降的问题。在 CocosCreator 中,提供了 CCNodePool 对象池模块来优化这个问题,当你使用它,节点的创建和销毁将不会彻底的执行,在将节点移除出场景树的同时,也将失效的节点缓存在节点池中,下次使用的时候再取出来,整个过程的性能消耗比普通方案来得更低,速度更快。在 ./assets/scripts/components 目录下创建 NodePoolManager.js ,可以参考下面代码使用 CCNodePool 来优化你的项目。 210 | 211 | ``` 212 | let NodePoolManager = { 213 | _nodePools:[], 214 | _nodePoolNames:["player_bullet","player_tank","enemy_tank","enemy_bullet"], 215 | 216 | initNoedPools: function () { 217 | for (let i = 0; i < this._nodePoolNames.length; i++) { 218 | this.createNodePool(this._nodePoolNames[i]); 219 | } 220 | }, 221 | 222 | createNodePool: function (name){ 223 | if (!this.getNodePool(name) && !this.getNodeElement(name)) { 224 | let nodePool = new cc.NodePool(name); 225 | this._nodePools.push(nodePool); 226 | return nodePool; 227 | } 228 | else { 229 | return null; 230 | } 231 | }, 232 | 233 | getNodePool: function (name) { 234 | if (this._nodePools.length > 0) { 235 | for (let i = 0; i < this._nodePools.length; i++) { 236 | if (this._nodePools[i].poolHandlerComp === name) { 237 | return this._nodePools[i]; 238 | } 239 | } 240 | return null; 241 | } 242 | }, 243 | 244 | getNodeElement (name) { 245 | let nodePool = this.getNodePool(name); 246 | if (nodePool) { 247 | let nodeElement = nodePool.get(); 248 | return nodeElement; 249 | } 250 | else { 251 | return null; 252 | } 253 | }, 254 | 255 | putNodeElemenet (name, element) { 256 | let nodePool = this.getNodePool(name); 257 | if (nodePool) { 258 | nodePool.put(element); 259 | } 260 | }, 261 | }; 262 | 263 | module.exports = NodePoolManager; 264 | ``` 265 | 266 | --- 267 | 268 | 269 | 270 | ### 4、初始化战斗场景 271 | 272 | 在 Canvas 节点下创建 Nodes Play Game 节点,主要负责渲染坦克大战核心战斗界面。对应的页面布局以及该节点的节点树参考如下: 273 | 274 | ![1571139257986](./images/1571139257986.png) 275 | 276 | 创建完节点并调整界面布局之后,在 ./assets/ 目录下创建 Game.js ,并添加到 Canvas 节点下。该脚本主要用于执行游戏初始化、处理游戏流程、处理玩家输入输出等操作。代码参考如下,我们将项目即将使用到的属性参数也写在脚本上。 277 | 278 | ``` 279 | var GameEnum = require("./gameData/GameEnum"); 280 | var GameConst = require("./gameData/GameConst"); 281 | var GameConfig = require("./gameData/GameConfig"); 282 | var NodePoolManager = require("./components/NodePoolManager"); 283 | cc.Class({ 284 | extends: cc.Component, 285 | 286 | properties: { 287 | loginGame: { 288 | default: null, 289 | type: cc.Node 290 | }, 291 | playGame: { 292 | default: null, 293 | type: cc.Node 294 | }, 295 | tankWarMap:{ 296 | default: null, 297 | type: cc.TiledMap 298 | }, 299 | tankSpriteAtlas: { 300 | default: null, 301 | type: cc.SpriteAtlas 302 | }, 303 | anyTank: { 304 | default: null, 305 | type: cc.Prefab 306 | }, 307 | bullet: { 308 | default: null, 309 | type: cc.Prefab 310 | }, 311 | gameMenu: { 312 | default: null, 313 | type: cc.Node 314 | }, 315 | enemyTankBornPosition: { 316 | default: [], 317 | type: cc.Vec2 318 | }, 319 | playerTankBornPosition: { 320 | default: [], 321 | type: cc.Vec2 322 | }, 323 | _initialRound: 1, 324 | _enemyTankAmount: 0, 325 | _playerTankReviveTimes: 0, 326 | _playing: false, 327 | _playerTank: [], 328 | _gameScore: 0, 329 | }, 330 | }); 331 | ``` 332 | 333 | 组件属性检查器面板的绑定情况如下: 334 | 335 | ![1571139479954](./images/1571139479954.png) 336 | 337 | Node AnyTank 的资源路径为 . /assets/res/prefab/Node AnyTank.prefab,布局与 CCSprite 组件的属性检查器面板如下: 338 | 339 | ![1571142694979](./images/1571142694979.png) 340 | 341 | Node Buttle 的资源路径为 . /assets/res/prefab/Node Buttle.prefab,布局与 CCSprite 组件的属性检查器面板如下: 342 | 343 | ![1571142724512](./images/1571142724512.png) 344 | 345 | 在 Game.js 中添加 onPlayGameButtonClicked 函数,用于开始界面的 Button PlayGame 按钮的点击回调。代码参考如下: 346 | 347 | ``` 348 | onPlayGameButtonClicked () { 349 | //隐藏游戏开始界面 350 | this.loginGame.opacity = false; 351 | this.loginGame.y += this.node.height; 352 | //显示游戏战斗界面 353 | this.playGame.opacity = 255; 354 | //播放游戏开始音效, SoundManager.js 的编写将在第5部分介绍 355 | this.node.getComponent("SoundManager").playStartGameEffectSound(); 356 | //执行游戏初始化 357 | this.initGame(); 358 | //执行游戏开始 359 | this.startGame(); 360 | }, 361 | ``` 362 | 363 | initGame 函数的代码如下: 364 | 365 | ``` 366 | initGame() { 367 | //执行对象池初始化 368 | NodePoolManager.initNoedPools(); 369 | }, 370 | ``` 371 | 372 | startGame 函数的代码如下: 373 | 374 | ``` 375 | startGame () { 376 | //标记游戏开始战斗 377 | this._playing = true; 378 | //初始化游戏菜单信息 379 | this.initGameMenuInfo(); 380 | //清空坦克 381 | this.clearTanks(); 382 | //根据 EnemyTankAmount 的大小生成相应数量的敌方玩家坦克 383 | for (let i = 0; i < GameConst.EnemyTankAmount; i++) { 384 | //每次只生成两个敌方坦克 385 | if (i < 2) { 386 | //在指定位置生成敌方坦克 387 | this.createEnemyTank(this.enemyTankBornPosition[i]); 388 | } 389 | } 390 | //根据 PlayerNum 的大小生成相应数量的玩家坦克 391 | for (let i = 0; i < GameConfig.PlayerNum; i++) { 392 | //在指定位置生成玩家坦克 393 | let playerTank = this.createPlayerTank(this.playerTankBornPosition[i]); 394 | //将玩家坦克的对象数据保存到 _playerTank 中 395 | this._playerTank.push(playerTank); 396 | } 397 | //初始化游戏监听 398 | this.initListenHandlers(); 399 | }, 400 | ``` 401 | 402 | initGameMenuInfo 的代码如下: 403 | 404 | ``` 405 | initGameMenuInfo() { 406 | this.gameMenu.getChildByName("Label Tank Remaining Number").getComponent(cc.Label).string = this._enemyTankAmount = GameConst.EnemyTankAmount; 407 | this.gameMenu.getChildByName("Label Revive Times Number").getComponent(cc.Label).string = this._playerTankReviveTimes = GameConst.PlayerTankReviveTimes; 408 | }, 409 | ``` 410 | 411 | clearTanks 的代码如下: 412 | 413 | ``` 414 | clearTanks () { 415 | this._playerTank = []; 416 | for (let i = 0; i < this.tankWarMap.node.getChildByName("tank").childrenCount; i++) { 417 | NodePoolManager.putNodeElemenet(this.tankWarMap.node.getChildByName("tank").children[i].group, this.tankWarMap.node.getChildByName("tank").children[i]); 418 | } 419 | } 420 | ``` 421 | 422 | createEnemyTank 的代码如下: 423 | 424 | ``` 425 | createEnemyTank (position) { 426 | //判断游戏是否处于战斗流程 427 | if (this.node.getComponent("Game")._playing) { 428 | //从对象池中获取缓存中的坦克节点对象 429 | this.enemyTank = NodePoolManager.getNodeElement(cc.game.groupList[3]); 430 | //当缓存中不存在可用的坦克节点对象时创建一个新的坦克节点对象 431 | if (!this.enemyTank) { 432 | this.enemyTank = cc.instantiate(this.anyTank); 433 | } 434 | //将节点放置在指定的坐标 435 | this.enemyTank.setPosition(position); 436 | //将坦克节点添加到地图中 437 | this.tankWarMap.node.getChildByName("tank").addChild(this.enemyTank); 438 | } 439 | }, 440 | ``` 441 | 442 | createPlayerTank 的代码如下: 443 | 444 | ``` 445 | createPlayerTank (position) { 446 | //判断游戏是否处于战斗流程 447 | if (this.node.getComponent("Game")._playing) { 448 | //从对象池中获取缓存中的坦克节点对象 449 | this.playerTank = NodePoolManager.getNodeElement(cc.game.groupList[2]); 450 | //当缓存中不存在可用的坦克节点对象时创建一个新的坦克节点对象 451 | if (!this.playerTank) { 452 | this.playerTank = cc.instantiate(this.anyTank); 453 | } 454 | //将节点放置在指定的坐标 455 | this.playerTank.setPosition(position); 456 | //将坦克节点添加到地图中 457 | this.tankWarMap.node.getChildByName("tank").addChild(this.playerTank); 458 | //将创建成功的坦克节点对象抛出 459 | return this.playerTank; 460 | } 461 | }, 462 | ``` 463 | 464 | initListenHandlers 的代码如下: 465 | 466 | ``` 467 | initListenHandlers () { 468 | cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onPlayerKeyDownCallback, this); 469 | }, 470 | ``` 471 | 472 | onPlayerKeyDownCallback 的代码暂时不完全补充,将在第5节中完善,暂定代码如下: 473 | 474 | ``` 475 | onPlayerKeyDownCallback () {}, 476 | ``` 477 | 478 | 在完善玩家对坦克的控制逻辑之前,执行以上的代码之后,游戏运行效果如下: 479 | 480 | ![20191015](./images/20191015.gif) 481 | 482 | 游戏战斗界面正确渲染的同时,坦克们也出现在了指定的位置。 483 | 484 | --- 485 | 486 | 487 | 488 | ### 5、坦克的初始化和管理 489 | 490 | 在坦克大战游戏中,在同一时刻需要生成不同类型的坦克。所以我们将一个基础类型的坦克节点制作成了 Prefab 资源,然后我们给这个 Prefab 增加能够随时变换类型和样式的能力。首先我们在 ./assets/scripts/components/tank 目录下创建 TankManager.js 脚本,代码参考如下: 491 | 492 | ``` 493 | var GameEnum = require("../../gameData/GameEnum"); 494 | var GameConst = require("../../gameData/GameConst"); 495 | var NodePoolManager = require("../NodePoolManager"); 496 | cc.Class({ 497 | extends: cc.Component, 498 | 499 | editor:{ 500 | // executeInEditMode: true 501 | }, 502 | 503 | properties: { 504 | isAuto: false, 505 | isCanMove: true, 506 | tankSpriteAtlas: { 507 | default: null, 508 | type: cc.SpriteAtlas 509 | }, 510 | tankFlag: { 511 | default: GameEnum.TankFlag.Player, 512 | type: GameEnum.TankFlag, 513 | notify: function () { 514 | this.updateTank(this.tankFlag); 515 | } 516 | }, 517 | enemyTankSpriteFrames: { 518 | default: [], 519 | type: cc.SpriteFrame 520 | }, 521 | playerTankSpriteFrames: { 522 | default: [], 523 | type: cc.SpriteFrame 524 | }, 525 | tankDirection: { 526 | default: GameConst.Dirction[0], 527 | notify: function () { 528 | this.updateTankSpriteFrame(this.tankDirection); 529 | } 530 | }, 531 | actionSpeed: { 532 | default: 0.05, 533 | type: cc.Float, 534 | range: [0,3,0.01] 535 | }, 536 | changeDirectionStep: { 537 | default: 10, 538 | type: cc.Integer, 539 | range: [0,100,1] 540 | }, 541 | bullet: { 542 | default: null, 543 | type: cc.Prefab 544 | }, 545 | _bornPosition: null, 546 | }, 547 | 548 | // LIFE-CYCLE CALLBACKS: 549 | 550 | // onLoad () {}, 551 | 552 | start () { 553 | if (!CC_EDITOR) { 554 | //初始化坦克的自动行走 555 | this.initTankAutoActionManager(); 556 | } 557 | }, 558 | 559 | onEnable () { 560 | if (this.node.group === cc.game.groupList[2]) { 561 | //播放坦克的开场动画 562 | this.node.getComponent(cc.Animation).play(); 563 | } 564 | }, 565 | 566 | //初始化坦克的各种参数 567 | initTank(tankFlag, direction, group, auto, position) { 568 | //设置坦克标识(依据GameEnum.TankFlag) 569 | this.tankFlag = tankFlag; 570 | //设置坦克风向 571 | this.tankDirection = direction; 572 | //设置坦克节点分组 573 | this.node.group = group; 574 | //设置是否允许自动行为 575 | this.isAuto = auto; 576 | //记录节点出生的初始坐标 577 | this._bornPosition = position; 578 | //设置节点坐标 579 | this.node.setPosition(position); 580 | //根据节点方向改变节点精灵贴图 581 | this.updateTankSpriteFrame(direction); 582 | }, 583 | 584 | //更新坦克所绑定的数据 585 | updateTank (type) { 586 | //创建新变量用于接收新的精灵贴图对象 587 | var newSpriteFrame = null; 588 | //只有类型为 Enemy 的坦克需要更换不同的贴图 589 | if (type === GameEnum.TankFlag.Enemy) { 590 | //随机取得新贴图的序号 591 | var spriteFrameIndex = Math.floor(Math.random() * this.enemyTankSpriteFrames.length); 592 | //取得随机的贴图 593 | newSpriteFrame = this.enemyTankSpriteFrames[spriteFrameIndex]; 594 | //从当前坦克类型中获取与贴图名称匹配的坦克配置 595 | for (let i = 0; i < GameConst.EnemyTankTypes.length; i++) { 596 | //匹配过程 597 | if (newSpriteFrame.name.indexOf(GameConst.EnemyTankTypes[i].name) !== -1) { 598 | //取得分数数据 599 | this._score = GameConst.EnemyTankTypes[i].score; 600 | //取得速度数据 601 | this.actionSpeed = GameConst.EnemyTankTypes[i].speed; 602 | } 603 | } 604 | } 605 | else { 606 | //设置为默认坦克精灵贴图 607 | newSpriteFrame = this.playerTankSpriteFrames[0]; 608 | } 609 | //让CCSprite组件将新贴图渲染出来 610 | this.node.getComponent(cc.Sprite).spriteFrame = newSpriteFrame; 611 | }, 612 | 613 | //更新坦克精灵的贴图 614 | updateTankSpriteFrame (newDirection) { 615 | //获取渲染组件 616 | var tankSprite = this.node.getComponent(cc.Sprite); 617 | //记录旧贴图的 name 618 | var oldSpriteFrameName = tankSprite.spriteFrame.name; 619 | //新建一个变量用于记录新贴图的 name 620 | var newSpriteFrameName = null; 621 | //遍历贴图名称数组 622 | for (let i = 0; i < GameConst.DirctionRex.length; i++) { 623 | //从贴图名称数组中找到与旧贴图相吻合的一项并返回一个新的贴图 name 624 | newSpriteFrameName = oldSpriteFrameName.replace(GameConst.DirctionRex[i], newDirection); 625 | //如果新旧贴图的名称不一样,则跳出本次循环 626 | if (newSpriteFrameName !== oldSpriteFrameName) { 627 | break; 628 | } 629 | } 630 | //根据新贴图的 name 获取图集中相对应的贴图资源 631 | if (this.tankSpriteAtlas.getSpriteFrame(newSpriteFrameName)) { 632 | tankSprite.spriteFrame = this.tankSpriteAtlas.getSpriteFrame(newSpriteFrameName); 633 | } 634 | }, 635 | 636 | //初始化坦克自动行为 637 | initTankAutoActionManager() { 638 | //开启定时器 639 | this.schedule(this.timerCallBack, this.actionSpeed); 640 | }, 641 | 642 | //定时器回调 643 | timerCallBack () { 644 | //判断是否允许自动行为 645 | if (this.isAuto) { 646 | //每走n步之后改变方向 647 | if (!this._changeDirectionStep || this._changeDirectionStep < 0) { 648 | //改变方向 649 | this.changeTankDirection(); 650 | //更新当前步数 651 | this._changeDirectionStep = this.changeDirectionStep; 652 | } 653 | else { 654 | //步数只剩一半时自动发射子弹 655 | if (this._changeDirectionStep === Math.floor(this.changeDirectionStep / 2)) { 656 | //发射子弹 657 | this.lauchBullet(cc.game.groupList[4]); 658 | } 659 | //如果坦克在地图中遇到障碍物 660 | if (!cc.find("Canvas").getComponent("TiledMapManager").onTileMovedEvent(this.node)) { 661 | //改变坦克方向 662 | this.changeTankDirection(); 663 | } 664 | //步数自动减一 665 | this._changeDirectionStep--; 666 | } 667 | //让坦克在地图中移动 668 | cc.find("Canvas").getComponent("TiledMapManager").onTileMovedEvent(this.node); 669 | } 670 | }, 671 | //改变坦克自身的方向 672 | changeTankDirection () { 673 | //获取一个随机序号 674 | var newDircetionIndex = Math.floor(Math.random() * GameConst.Dirction.length); 675 | //设置坦克的方向 676 | this.node.getComponent("TankManager").tankDirection = GameConst.Dirction[newDircetionIndex]; 677 | }, 678 | 679 | //发射子弹 680 | lauchBullet (group) { 681 | //从对象池中获取子弹对象缓存 682 | var bullet = NodePoolManager.getNodeElement(group); 683 | //如果没有子弹对象缓存 684 | if (!bullet) { 685 | //实例化一个子弹节点 686 | bullet = cc.instantiate(this.bullet); 687 | } 688 | //设置子弹的方向 689 | bullet._direction = this.node.getComponent("TankManager").tankDirection; 690 | //添加子弹到场景中 691 | cc.find("Canvas").getComponent("Game").tankWarMap.node.getChildByName("bullet").addChild(bullet); 692 | //执行子弹节点的初始化 693 | bullet.getComponent("BulletManager").initBullet(this.node, group); 694 | //播放音效,这部分将在第9节中讲解 695 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("shoot", false); 696 | }, 697 | 698 | //停止当前组件的计时器 699 | onUnschedule () { 700 | this.unschedule(this.timerCallBack); 701 | }, 702 | 703 | onDisable () { 704 | //关闭当前节点在 ColliderManager 组件中的监听事件 705 | this.node.targetOff(this.node.getComponent("ColliderManager")); 706 | } 707 | }); 708 | ``` 709 | 710 | 将该脚本组件添加到 Node AnyTank 预制体的 Node AnyTank 节点上,它的属性检查器界面的绑定情况如下: 711 | 712 | ![1571209420292](./images/1571209420292.png) 713 | 714 | 此外,我们可以给玩家坦克的出生添加一个入场动画: 715 | 716 | 首先在 Node AnyTank 节点下创建一个子节点 Sp Shield ,添加 CCSprite 组件,在 ./assets/res/texture/ 目录下找到 shield_0 贴图,将它添加到 CCSprite 组件的 SpriteFrame 属性框中,此时节点的渲染情况如下: 717 | 718 | ![1571212037751](./images/1571212037751.png) 719 | 720 | 之后,将 Sprite Shield 节点的 active 勾选去掉,回到 Node AnyTank 节点,给它添加 CCAnimation 组件,并且在 ./assets/res/anima/ 目录下创建一个 animationClip 资源,命名为 start,主要用于播放坦克入场动画。CCAnimation 组件的属性检查器面板如下: 721 | 722 | ![1571212575077](./images/1571212575077.png) 723 | 724 | start 序列帧动画在动画编辑器中的设置如下,不懂得怎么使用动画编辑器的可以参考这篇文档:[Animation system](https://docs.cocos.com/creator/manual/en/animation/): 725 | 726 | ![1571213607552](./images/1571213607552.png) 727 | 728 | 操作完成上述内容之后,游戏的表现如下: 729 | 730 | ![20191016](./images/20191016.gif) 731 | 732 | --- 733 | 734 | ### 6、控制坦克在地图中移动 735 | 736 | 我们需要使用 CocosCreator 引擎的全局系统事件模块来控制玩家的输入输出操作。 全局系统事件是指与节点树不相关的各种全局事件,由 `cc.systemEvent` 来统一派发,目前支持了以下几种事件:键盘事件、设备重力传感事件。在本项目中,玩家1通过按下键盘中的 w、a、s、d 来控制坦克往上、往左、往下、往右移动,并通过按下键盘中的 Space 键来发射子弹。玩家2通过按下键盘中的方向键来控制坦克向四个方向移动,并通过按下 PgUp 键发射子弹。分配完每个键位在游戏中对应的功能之后,我们就可以开始写代码了,参考如下: 737 | 738 | ``` 739 | onPlayerKeyDownCallback (event) { 740 | switch (event.keyCode) { 741 | case cc.macro.KEY.w: 742 | //这是属于玩家1的监听事件 743 | if (!this._playerTank[0]) return; 744 | //设置玩家1的坦克的转向 745 | this._playerTank[0].getComponent("TankManager").tankDirection = GameConst.Dirction[0]; 746 | //将状态改变后的坦克对象传递到坦克地图中 747 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[0]); 748 | break; 749 | case cc.macro.KEY.a: 750 | if (!this._playerTank[0]) return; 751 | this._playerTank[0].getComponent("TankManager").tankDirection = GameConst.Dirction[1]; 752 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[0]); 753 | break; 754 | case cc.macro.KEY.s: 755 | if (!this._playerTank[0]) return; 756 | this._playerTank[0].getComponent("TankManager").tankDirection = GameConst.Dirction[2]; 757 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[0]); 758 | break; 759 | case cc.macro.KEY.d: 760 | if (!this._playerTank[0]) return; 761 | this._playerTank[0].getComponent("TankManager").tankDirection = GameConst.Dirction[3]; 762 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[0]); 763 | break; 764 | case cc.macro.KEY.up : 765 | //这是属于玩家2的监听事件 766 | if (!this._playerTank[1]) return; 767 | //设置玩家2的坦克的转向 768 | this._playerTank[1].getComponent("TankManager").tankDirection = GameConst.Dirction[0]; 769 | //将状态改变后的坦克对象传递到坦克地图中 770 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[1]); 771 | break; 772 | case cc.macro.KEY.left: 773 | if (!this._playerTank[1]) return; 774 | this._playerTank[1].getComponent("TankManager").tankDirection = GameConst.Dirction[1]; 775 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[1]); 776 | break; 777 | case cc.macro.KEY.down: 778 | if (!this._playerTank[1]) return; 779 | this._playerTank[1].getComponent("TankManager").tankDirection = GameConst.Dirction[2]; 780 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[1]); 781 | break; 782 | case cc.macro.KEY.right: 783 | if (!this._playerTank[1]) return; 784 | this._playerTank[1].getComponent("TankManager").tankDirection = GameConst.Dirction[3]; 785 | this.node.getComponent("TiledMapManager").onTileMovedEvent(this._playerTank[1]); 786 | break; 787 | case cc.macro.KEY.space: 788 | if (!this._playerTank[0]) return; 789 | //玩家1发射子弹 790 | this._playerTank[0].getComponent("TankManager").lauchBullet(cc.game.groupList[1]); 791 | break; 792 | case cc.macro.KEY.pageup: 793 | if (!this._playerTank[1]) return; 794 | //玩家2发射子弹 795 | this._playerTank[1].getComponent("TankManager").lauchBullet(cc.game.groupList[1]); 796 | break; 797 | } 798 | }, 799 | ``` 800 | 801 | 为游戏中的子弹编写脚本 BulletManager.js,代码参考如下: 802 | 803 | ``` 804 | var NodePoolManager = require("../NodePoolManager"); 805 | cc.Class({ 806 | extends: cc.Component, 807 | 808 | properties: { 809 | lauchStep: { 810 | default: 1, 811 | type: cc.Float, 812 | range: [0,1,0.01] 813 | } 814 | }, 815 | 816 | // LIFE-CYCLE CALLBACKS: 817 | 818 | // onLoad () {}, 819 | 820 | start () { 821 | 822 | }, 823 | 824 | //初始化子弹 825 | initBullet (tank, group) { 826 | //设置节点分组 827 | this.node.group = group; 828 | //设置节点坐标 829 | this.node.position = tank.position; 830 | //启动定时器 831 | this.schedule(this.timerCallBack, this.lauchStep); 832 | 833 | }, 834 | 835 | timerCallBack (direction) { 836 | //设置节点活动边界 837 | if (this.node.position.x === -208 || this.node.position.x === 204 || this.node.position.y === -204 || this.node.position.y === 208) { 838 | //将节点从节点树中移除,并将节点对象缓存到对象池中 839 | NodePoolManager.putNodeElemenet(this.node.group, this.node); 840 | return; 841 | } 842 | else { 843 | //让子弹在地图中移动 844 | cc.find("Canvas").getComponent("TiledMapManager").onTileMovedEvent(this.node); 845 | } 846 | }, 847 | 848 | onDisable () { 849 | //关闭定时器 850 | this.unschedule(this.timerCallBack); 851 | } 852 | // update (dt) {}, 853 | }); 854 | 855 | ``` 856 | 857 | 接下来,就是让坦克在地图中行动。我们需要在 ./assets/scripts/components/ 目录下创建一个地图管理脚本:TiledMapManager.js。该脚本主要负责将节点在节点坐标轴上的行为转化到地图中,请参考下方的代码: 858 | 859 | ``` 860 | var NodePoolManager = require("./NodePoolManager"); 861 | var GameEnum = require("./gameData/GameEnum"); 862 | var GameConst = require("../gameData/GameConst"); 863 | cc.Class({ 864 | extends: cc.Component, 865 | 866 | properties: { 867 | mainTiledMap: { 868 | default: null, 869 | type: cc.TiledMap 870 | }, 871 | 872 | tiledMapAssetSet: { 873 | default: [], 874 | type: cc.TiledMapAsset 875 | }, 876 | 877 | tiledMapAssets: { 878 | default: [], 879 | type: cc.TiledMapAsset 880 | }, 881 | _interimPos:[], 882 | 883 | }, 884 | 885 | start () { 886 | //初始化地图数据 887 | this.initTiledMapData(); 888 | }, 889 | 890 | initTiledMapData () { 891 | //获取 layer_0、layer_1 地图层 892 | this.mainLayer = this.mainTiledMap.getLayer("layer_0"); 893 | this.secondaryLayer = this.mainTiledMap.getLayer("layer_1"); 894 | }, 895 | 896 | //用于将节点在节点坐标中的移动转化为地图坐标移动 897 | onTileMovedEvent (tileNode, callback) { 898 | //如果坦克不允许移动,则不执行内部逻辑 899 | if (tileNode.getComponent("TankManager") && !tileNode.getComponent("TankManager").isCanMove) { 900 | return; 901 | } 902 | //创建一个变量用于缓存节点在节点坐标轴下的初始坐标 903 | var startPos = cc.v2(tileNode.position.x, tileNode.position.y); 904 | //创建一个变量用于缓存坦克方向 905 | var tankDirection = null; 906 | //如果节点不是坦克 907 | if (!tileNode.getComponent("TankManager")) { 908 | //设置方向 909 | tankDirection = tileNode._direction; 910 | } 911 | //如果节点是坦克 912 | else { 913 | //设置方向 914 | tankDirection = tileNode.getComponent("TankManager").tankDirection; 915 | } 916 | //根据得到的方向重新设置节点的坐标 917 | if (tankDirection === GameConst.Dirction[0]) { 918 | startPos.y += tileNode.height; 919 | } 920 | else if(tankDirection === GameConst.Dirction[2]){ 921 | startPos.y -= tileNode.height; 922 | } 923 | else if (tankDirection === GameConst.Dirction[1]) { 924 | startPos.x -= tileNode.width; 925 | } 926 | else if (tankDirection === GameConst.Dirction[3]) { 927 | startPos.x += tileNode.width; 928 | } 929 | //将节点坐标转化为地图坐标 930 | var tilePos = this.getTilePositionAt(tileNode, startPos); 931 | //设置地图边界 932 | if (tilePos.y <= this.mainLayer.getLayerSize().height - 1 && tilePos.x <= this.mainLayer.getLayerSize().width - 1 933 | && tilePos.y >= 0 && tilePos.x >= 0) { 934 | //获取当前地图坐标所对应的图块ID 935 | var tileGID = this.mainLayer.getTileGIDAt(tilePos); 936 | //根据GameConst.GidToTileType取得当前图块对应的类型,再与GameEnum.TileType比较,不同类型的图块对应的变化不同 937 | //这里处理tileWall类型图块 938 | if (GameConst.GidToTileType[tileGID] === GameEnum.TileType.tileWall) { 939 | //根据节点的分组执行不同的逻辑,此处节点分组是tankBullet 940 | if (tileNode.group === cc.game.groupList[1] || tileNode.group === cc.game.groupList[4]) { 941 | //重新设置图块 942 | this.mainLayer.setTileGIDAt(0, tilePos.x, tilePos.y); 943 | //将坦克从节点树中移除,并将节点对象放到对象池中 944 | NodePoolManager.putNodeElemenet(tileNode.group, tileNode); 945 | } 946 | //tank 947 | else if (tileNode.group === cc.game.groupList[2] || tileNode.group === cc.game.groupList[3]) { 948 | return false; 949 | } 950 | } 951 | //这里处理tileSteel类型图块 952 | else if (GameConst.GidToTileType[tileGID] === GameEnum.TileType.tileSteel) { 953 | if (tileNode.group === cc.game.groupList[1] || tileNode.group === cc.game.groupList[4]) { 954 | //播放steel音效,这部分在第9节中讲解 955 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("steel", false); 956 | NodePoolManager.putNodeElemenet(tileNode.group, tileNode); 957 | } 958 | //tank 959 | else if (tileNode.group === cc.game.groupList[2] || tileNode.group === cc.game.groupList[3]) { 960 | return false; 961 | } 962 | } 963 | //这里处理tileRiver类型图块 964 | else if (GameConst.GidToTileType[tileGID] === GameEnum.TileType.tileRiver) { 965 | if (tileNode.group === cc.game.groupList[2] || tileNode.group === cc.game.groupList[3]) { 966 | return false; 967 | } 968 | } 969 | //这里处理tileKing类型图块 970 | else if (GameConst.GidToTileType[tileGID] === GameEnum.TileType.tileKing) { 971 | if (tileNode.group === cc.game.groupList[1] || tileNode.group === cc.game.groupList[4]) { 972 | //执行游戏结束逻辑 973 | cc.find("Canvas").getComponent("Game").onGameOverEvent(); 974 | NodePoolManager.putNodeElemenet(tileNode.group, tileNode); 975 | } 976 | //tank 977 | else if (tileNode.group === cc.game.groupList[2] || tileNode.group === cc.game.groupList[3]) { 978 | return false; 979 | } 980 | } 981 | //将转化过后的节点坐标设置给节点 982 | tileNode.position = startPos; 983 | if (typeof callback === "function") { 984 | //执行回调函数 985 | callback(); 986 | } 987 | //抛出节点对象 988 | return tileNode; 989 | } 990 | else { 991 | return false; 992 | } 993 | }, 994 | 995 | getTilePositionAt (tileNode, position) { 996 | //将节点的节点坐标转化为世界坐标 997 | var worldPosition = tileNode.parent.convertToWorldSpaceAR(position); 998 | //获取地图节点的宽高数据 999 | var mapSize = this.node.getContentSize(); 1000 | //或者地图的宽高数据 1001 | var tileSize = this.mainTiledMap.getTileSize(); 1002 | //计算节点在地图中的坐标,并向下取整 1003 | var x = Math.floor(worldPosition.x / tileSize.width); 1004 | var y = Math.floor((mapSize.height - worldPosition.y) / tileSize.height); 1005 | return cc.v2(x, y); 1006 | }, 1007 | 1008 | // update (dt) {}, 1009 | }); 1010 | ``` 1011 | 1012 | 将该组件添加到 Canvas 节点上,下面是该组件的属性检查器面板, TiledMapAsset 资源在 ./assets/res/map 目录下: 1013 | 1014 | ![1571217426613](./images/1571217426613.png) 1015 | 1016 | 完成这部分操作之后,游戏的表现如下所示: 1017 | 1018 | ![20191017](./images/20191017.gif) 1019 | 1020 | --- 1021 | 1022 | 1023 | 1024 | ### 7、添加子弹和坦克的碰撞逻辑 1025 | 1026 | 我们借助 CocosCreator 引擎的 [Collision System](https://docs.cocos.com/creator/manual/en/physics/collision/) 来处理子弹与坦克之间的碰撞关系。因为我们在第一节已经设置好了 group 分组,所以我们可以直接编写分组管理的脚本 ColliderManager.js,代码参考如下: 1027 | 1028 | ``` 1029 | var GameEnum = require("../gameData/GameEnum"); 1030 | var NodePoolManager = require("../components/NodePoolManager"); 1031 | cc.Class({ 1032 | extends: cc.Component, 1033 | 1034 | properties: { 1035 | }, 1036 | 1037 | onLoad () { 1038 | //获取游戏全局的碰撞系统管理对象 1039 | var colliderManager = cc.director.getCollisionManager(); 1040 | //开启碰撞管理 1041 | colliderManager.enabled = true; 1042 | //绘制碰撞盒的边框 1043 | // colliderManager.enabledDebugDraw = true; 1044 | }, 1045 | 1046 | //触发碰撞时的回调 1047 | onCollisionEnter (other, self) { 1048 | //将节点从节点树中移除,并将节点对象缓存到对象池中 1049 | NodePoolManager.putNodeElemenet(this.node.group, this.node); 1050 | //分组不同处理不同的逻辑 1051 | if (this.node.group === cc.game.groupList[2]) { 1052 | //玩家坦克的重生次数减一 1053 | --cc.find("Canvas").getComponent("Game")._playerTankReviveTimes; 1054 | //更新战斗界面右侧的游戏信息 1055 | cc.find("Canvas").getComponent("Game").updateGameMenuInfo(this.node, GameEnum.TankFlag.Player); 1056 | //播放 playerTankBoom 音效,音效系统在第9节中讲解 1057 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("playerTankBoom", false); 1058 | } 1059 | else if (this.node.group === cc.game.groupList[3]) { 1060 | //敌方坦克数量减一 1061 | --cc.find("Canvas").getComponent("Game")._enemyTankAmount; 1062 | //更新战斗界面右侧的游戏信息 1063 | cc.find("Canvas").getComponent("Game").updateGameMenuInfo(this.node, GameEnum.TankFlag.Enemy); 1064 | //计算玩家在游戏中获得的分数 1065 | cc.find("Canvas").getComponent("Game").updateScore(this.node.getComponent("TankManager")._score); 1066 | //播放 enemyTankBoom 音效 1067 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("enemyTankBoom", false); 1068 | } 1069 | }, 1070 | 1071 | //碰撞结束时执行的回调 1072 | onCollisionExit (other, self) { 1073 | if (this.node.group === cc.game.groupList[0]) { 1074 | 1075 | } 1076 | else if (this.node.group === cc.game.groupList[0]) { 1077 | 1078 | } 1079 | }, 1080 | 1081 | initGroup () {} 1082 | // update (dt) {}, 1083 | }); 1084 | ``` 1085 | 1086 | 我们只需要将这个组件,添加到 Node AnyTank 预制体的 Node AnyTank 节点、Node Buttle 预制体的 Node Buttle 节点。并且给带有 ColliderManager.js 脚本组件的节点添加 CCBoxCollider 组件。属性检查器界面如下: 1087 | 1088 | ![1571220278417](./images/1571220278417.png) 1089 | 1090 | ![1571220427137](./images/1571220427137.png) 1091 | 1092 | 完成上述操作后,子弹和坦克之间就能发生碰撞了,我们看下效果: 1093 | 1094 | ![20191018](./images/20191018.gif) 1095 | 1096 | --- 1097 | 1098 | 1099 | 1100 | ### 8、游戏结算处理 1101 | 1102 | 在坦克发生碰撞之后,更新游戏战斗界面右侧数据时会进行游戏结算。我们在 Game.js 中添加了以下函数:updateGameMenuInfo 函数,代码参考如下: 1103 | 1104 | ``` 1105 | updateGameMenuInfo (targetNode, tankTag) { 1106 | //更新战斗界面右侧游戏信息 1107 | if (cc.find("Canvas").getComponent("Game")._enemyTankAmount > 0 && cc.find("Canvas").getComponent("Game")._playerTankReviveTimes > 0) { 1108 | //创建新的坦克 1109 | this.createNewTank(targetNode, tankTag); 1110 | } 1111 | else if (cc.find("Canvas").getComponent("Game")._enemyTankAmount > 0 && cc.find("Canvas").getComponent("Game")._playerTankReviveTimes === 0){ 1112 | //执行游戏失败逻辑 1113 | this.onGameOverEvent("lose"); 1114 | } 1115 | else if (cc.find("Canvas").getComponent("Game")._enemyTankAmount === 0 && cc.find("Canvas").getComponent("Game")._playerTankReviveTimes > 0) { 1116 | //进入下一关卡 1117 | this.onNextRoundEvent(); 1118 | } 1119 | else if (cc.find("Canvas").getComponent("Game")._enemyTankAmount === 0 && cc.find("Canvas").getComponent("Game")._playerTankReviveTimes === 0){ 1120 | //进入下一关卡 1121 | this.onNextRoundEvent(); 1122 | } 1123 | }, 1124 | ``` 1125 | 1126 | createNewTank 函数的代码如下: 1127 | 1128 | ``` 1129 | createNewTank (targetNode, tankTag) { 1130 | //根据类型创建不同的坦克 1131 | if (tankTag === GameEnum.TankFlag.Enemy) { 1132 | cc.find("Canvas").getComponent("Game").gameMenu.getChildByName("Label Tank Remaining Number").getComponent(cc.Label).string = cc.find("Canvas").getComponent("Game")._enemyTankAmount; 1133 | cc.find("Canvas").getComponent("Game").createEnemyTank(targetNode.getComponent("TankManager")._bornPosition); 1134 | } 1135 | else if (tankTag === GameEnum.TankFlag.Player) { 1136 | cc.find("Canvas").getComponent("Game").gameMenu.getChildByName("Label Revive Times Number").getComponent(cc.Label).string = cc.find("Canvas").getComponent("Game")._playerTankReviveTimes; 1137 | cc.find("Canvas").getComponent("Game").createPlayerTank(targetNode.getComponent("TankManager")._bornPosition); 1138 | } 1139 | }, 1140 | ``` 1141 | 1142 | onGameOverEvent 函数代码如下: 1143 | 1144 | ``` 1145 | //游戏结束处理 1146 | onGameOverEvent (command) { 1147 | //更新游戏状态 1148 | this._playing = false; 1149 | //根据指令执行不同的逻辑 1150 | if (command === "win") { 1151 | //播放 begin 音效 1152 | this.node.getComponent("SoundManager").playEffectSound("begin", false); 1153 | console.log("[Game Win]"); 1154 | } 1155 | else if (command === "lose") { 1156 | //播放 gameOver 音效 1157 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("gameOver", false); 1158 | console.log("[Game Lose]"); 1159 | } 1160 | //重启游戏 1161 | this.restartGame(); 1162 | }, 1163 | ``` 1164 | 1165 | onNextRoundEvent 函数代码如下: 1166 | 1167 | ``` 1168 | //进入下一关卡 1169 | onNextRoundEvent () { 1170 | //更新关卡值 1171 | ++this._initialRound; 1172 | //关卡值不能大于游戏内置的地图数量 1173 | if (this._initialRound <= this.node.getComponent("TiledMapManager").tiledMapAssets.length) { 1174 | //替换地图资源 1175 | this.tankWarMap.tmxAsset = this.node.getComponent("TiledMapManager").tiledMapAssets[this._initialRound - 1]; 1176 | //更新关卡值文本信息 1177 | this.gameMenu.getChildByName("Label Round Number").getComponent(cc.Label).string = this._initialRound; 1178 | //初始化地图数据 1179 | this.node.getComponent("TiledMapManager").initTiledMapData(); 1180 | //播放游戏开始音效 1181 | this.node.getComponent("SoundManager").playStartGameEffectSound(); 1182 | //执行游戏开始逻辑 1183 | this.startGame(); 1184 | } 1185 | else { 1186 | this.onGameOverEvent("win"); 1187 | } 1188 | }, 1189 | ``` 1190 | 1191 | restartGame 函数代码如下: 1192 | 1193 | ``` 1194 | //重启游戏 1195 | restartGame () { 1196 | //更新游戏状态 1197 | this._playing = false; 1198 | //注销监听事件 1199 | this.unListenHandlers(); 1200 | //清空玩家坦克数组缓存 1201 | this._playerTank = []; 1202 | //关闭游戏所有音效 1203 | this.node.getComponent("SoundManager").stopAll(); 1204 | //载入 game 场景 1205 | cc.director.loadScene("game"); 1206 | }, 1207 | ``` 1208 | 1209 | 1210 | 1211 | 添加以上函数之后,游戏就能在游戏失败的时候回到游戏开始界面,并在游戏当前关卡胜利的时候进入下一关卡。 1212 | 1213 | --- 1214 | 1215 | 1216 | 1217 | 9、添加游戏背景音乐和音效管理 1218 | 1219 | 我们通过 SoundManager.js 脚本组件来控制游戏的各种音频播放操作。 1220 | 1221 | ``` 1222 | cc.Class({ 1223 | extends: cc.Component, 1224 | editor: { 1225 | menu:"CustomComponent/AudioControl", 1226 | }, 1227 | properties: { 1228 | backGroupSound: { 1229 | default: null, 1230 | type: cc.AudioClip 1231 | }, 1232 | 1233 | loop: true, 1234 | 1235 | soundsVolume: { 1236 | default: 1, 1237 | range: [0,1,0.01], 1238 | notify: function() { 1239 | this.setSoundsVolume(); 1240 | } 1241 | }, 1242 | 1243 | effectsVolume: { 1244 | default: 1, 1245 | range: [0,1,0.01], 1246 | notify: function () { 1247 | this.setEffectsVolume(); 1248 | } 1249 | }, 1250 | 1251 | audioClipPool: { 1252 | default: [], 1253 | type: cc.AudioClip 1254 | }, 1255 | 1256 | _isPlaying: false, 1257 | _audioId: null, 1258 | _effectId: null, 1259 | }, 1260 | 1261 | //播放背景音乐 1262 | playBackGroupSound (callback) { 1263 | if (this.backGroupSound) { 1264 | //暂停正在播放的音乐 1265 | cc.audioEngine.stopAll(); 1266 | //播放音乐 1267 | this._audioId = cc.audioEngine.play(this.backGroupSound, this.loop, this.soundsVolume); 1268 | //播放完成时执行回调 1269 | if (callback && typeof callback === "function") { 1270 | cc.audioEngine.setFinishCallback(this._audioId, callback); 1271 | } 1272 | } 1273 | }, 1274 | 1275 | //根据不同的指令播放不同的音效 1276 | playEffectSound (command, loop = this.loop, callback) { 1277 | if (command !== null && command !== undefined || this.audioClipPool.length > 0) { 1278 | switch (command) { 1279 | case "begin": 1280 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[0], loop); 1281 | break; 1282 | case "nmoving": 1283 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[1], loop); 1284 | break; 1285 | case "moving": 1286 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[2], loop); 1287 | break; 1288 | case "shoot": 1289 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[3], loop); 1290 | break; 1291 | case "steel": 1292 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[4], loop); 1293 | break; 1294 | case "enemyTankBoom": 1295 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[5], loop); 1296 | break; 1297 | case "playerTankBoom": 1298 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[6], loop); 1299 | break; 1300 | case "gameOver": 1301 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[7], loop); 1302 | break; 1303 | case "pause": 1304 | case "resume": 1305 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[8], loop); 1306 | break; 1307 | case "bouns": 1308 | this._effectId = cc.audioEngine.playEffect(this.audioClipPool[9], loop); 1309 | break; 1310 | default: 1311 | console.error("Command is invalid"); 1312 | } 1313 | } 1314 | if (typeof callback === "function") { 1315 | //播放完成时执行回调 1316 | cc.audioEngine.setFinishCallback(this._effectId, callback); 1317 | } 1318 | }, 1319 | 1320 | //暂停音乐 1321 | pauseMusic () { 1322 | cc.audioEngine.pauseAll(); 1323 | }, 1324 | 1325 | //恢复音乐 1326 | resumeMusic () { 1327 | cc.audioEngine.resumeAll(); 1328 | }, 1329 | 1330 | //设置背景音乐音量 1331 | setSoundsVolume() { 1332 | if (this._audioId) { 1333 | cc.audioEngine.setVolume(this.soundsVolume); 1334 | } 1335 | }, 1336 | 1337 | //设置音效音量 1338 | setEffectsVolume () { 1339 | if (this._effectId) { 1340 | cc.audioEngine.setEffectsVolume(this.effectsVolume); 1341 | } 1342 | }, 1343 | 1344 | //停止所有音乐 1345 | stopAll () { 1346 | cc.audioEngine.stopAll(); 1347 | this._audioId = null; 1348 | this._effectId = null; 1349 | }, 1350 | 1351 | //播放开始游戏音乐 1352 | playStartGameEffectSound () { 1353 | this.playEffectSound("begin", false, ()=>{ 1354 | this.playEffectSound("nmoving", true); 1355 | }); 1356 | }, 1357 | }); 1358 | ``` 1359 | 1360 | 将它添加到 Canvas 节点中,属性检查器面板如下: 1361 | 1362 | ![1571227326639](./images/1571227326639.png) 1363 | 1364 | 为 Slider BGM Volume 、Slider Effect Volume 这两个 CCSlider 组件添加滑动回调,让它们每次滑动都能调节音量。在 Game.js 脚本中添加 onSliderSwitchEvent 函数,代码如下: 1365 | 1366 | ``` 1367 | //音量控制滑块 1368 | onSliderSwitchEvent (slider, CustomEventData) { 1369 | //新建一个变量缓存滑块对应的数值 1370 | let volume = slider.progress; 1371 | //根据滑块的自定义参数执行不同的逻辑 1372 | if (CustomEventData === "bgm") { 1373 | //设置背景音乐音量 1374 | this.node.getComponent("SoundManager").soundsVolume = volume; 1375 | } 1376 | else if (CustomEventData === "effect") { 1377 | //设置音效音量 1378 | this.node.getComponent("SoundManager").effectsVolume = volume; 1379 | } 1380 | }, 1381 | ``` 1382 | 1383 | 将该脚本绑定为 Slider BGM Volume 、Slider Effect Volume 这两个组件的滑动回调,属性检查器界面的绑定情况如下: 1384 | 1385 | ![1571229153093](./images/1571229153093.png) 1386 | 1387 | ![1571229170529](./images/1571229170529.png) 1388 | 1389 | 这样就完成了游戏的音频控制操作。 1390 | 1391 | --- 1392 | 1393 | 1394 | 1395 | ### 10、添加游戏暂停、恢复功能以及重玩功能 1396 | 1397 | 在 Game.js 脚本中添加 onPauseOrResumeGameEvent 函数来控制游戏的进程,代码如下: 1398 | 1399 | ``` 1400 | //暂停或恢复游戏 1401 | onPauseOrResumeGameEvent () { 1402 | //改变游戏战斗进行中的标签 1403 | this._playing = !this._playing; 1404 | //非战斗进行时 1405 | if (!this._playing) { 1406 | //播放暂停音效 1407 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("pause", false); 1408 | //暂停所有坦克 1409 | for (let i = 0; i< this.tankWarMap.node.getChildByName("tank").childrenCount; i++) { 1410 | //禁止坦克移动 1411 | this.tankWarMap.node.getChildByName("tank").children[i].getComponent("TankManager").isCanMove = false; 1412 | //暂停定时器 1413 | cc.director.getScheduler().pauseTarget(this.tankWarMap.node.getChildByName("tank").children[i].getComponent("TankManager")); 1414 | } 1415 | //改变按钮文本 1416 | this.gameMenu.getChildByName("Button Game Pause").getChildByName("Label Button").getComponent(cc.Label).string = "resume"; 1417 | console.log("[Game Pause]"); 1418 | } 1419 | else { 1420 | //播放恢复音效 1421 | cc.find("Canvas").getComponent("SoundManager").playEffectSound("resume", false); 1422 | //恢复所有坦克 1423 | for (let i = 0; i< this.tankWarMap.node.getChildByName("tank").childrenCount; i++) { 1424 | //允许坦克移动 1425 | this.tankWarMap.node.getChildByName("tank").children[i].getComponent("TankManager").isCanMove = true; 1426 | //恢复定时器 1427 | cc.director.getScheduler().resumeTarget(this.tankWarMap.node.getChildByName("tank").children[i].getComponent("TankManager")); 1428 | } 1429 | //改变按钮文本 1430 | this.gameMenu.getChildByName("Button Game Pause").getChildByName("Label Button").getComponent(cc.Label).string = "pause"; 1431 | console.log("[Game Resume]"); 1432 | } 1433 | 1434 | }, 1435 | ``` 1436 | 1437 | 将 onPauseOrResumeGameEvent 设置为 Button Game Pause 按钮的点击回调,属性检查器界面绑定情况如下: 1438 | 1439 | ![1571227962953](./images/1571227962953.png) 1440 | 1441 | 新建一个 CCButton 组件节点命名为 Button Game Restart,为它绑定 Game.js 中的 restartGame 函数为点击结束的回调,属性检查器界面如下: 1442 | 1443 | ![1571228602680](./images/1571228602680.png) 1444 | 1445 | 这样就完成了游戏的一些进程控制。 1446 | 1447 | --- 1448 | 1449 | 1450 | 1451 | ### 11、结语 1452 | 1453 | TankWar 的游戏开发教程在本篇完成了,看一下游戏表现(此处为了方便测试将敌方坦克的数量调整为5个): 1454 | 1455 | ![20191019](./images/20191019.gif) 1456 | 1457 | 目前游戏依然存在很多的优化空间。等你完全掌握教程中所使用的工具 以及编程语言时,你就可以再进一步的在原来的基础上创造出更多有意思的内容。感谢大家对 CocosCreator 游戏引擎的热爱,本篇教程由 Cocos技术顾问团队提供。再次感谢。 1458 | 1459 | --- 1460 | 1461 | [complete project](https://github.com/Jno1995/Tank-War) 1462 | 1463 | [new project](https://github.com/Jno1995/Tank-War-New) 1464 | 1465 | -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/CocosCreator开发坦克大战游戏(二).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/CocosCreator开发坦克大战游戏(二).pdf -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571134226766.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571134226766.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135093072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135093072.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135630608.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135630608.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135988842.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571135988842.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571136089188.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571136089188.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571136183310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571136183310.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139257986.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139257986.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139479954.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139479954.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139651485.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571139651485.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571142694979.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571142694979.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571142724512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571142724512.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571209420292.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571209420292.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571212037751.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571212037751.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571212575077.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571212575077.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571213607552.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571213607552.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571217426613.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571217426613.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571218274828.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571218274828.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571220278417.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571220278417.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571220427137.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571220427137.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227326639.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227326639.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227581285.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227581285.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227962953.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571227962953.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571228602680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571228602680.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571229153093.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571229153093.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571229170529.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/1571229170529.png -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191015.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191015.gif -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191016.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191016.gif -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191017.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191017.gif -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191018.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191018.gif -------------------------------------------------------------------------------- /tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191019.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhefengzhang/CocosCreator-game-tutorials/f0e7e34de397f99b46a8ee81fd94b3af4bf85b0c/tankWar_教程/用 Cocos Creator 制作坦克大战游戏(二)/images/20191019.gif --------------------------------------------------------------------------------