JS开发HTML5游戏《神奇的六边形》(一)
近期出现一款魔性的消除类HTML5游戏《神奇的六边形》,今天我们一起来看看如何通过开源免费的青瓷引擎(
www.zuoyouxi.com)来实现这款游戏。

(点击图片可进入游戏体验)
因内容太多,为方便大家阅读,所以分成四部分来讲解。
本文为第一部分,主要包括:
1. 功能分析
2. 创建工程与场景
3. 玩家分数管理
4. 棋盘设计与实现
5. 屏幕布局
若要一次性查看所有文档,也可点击这里。
一. 功能分析
首先分析游戏的功能点、算法和数据,然后依此制订代码组织结构。如下图:

主要功能点
- 棋盘的数据结构与绘制
- 3个形状的生成
- 形状拖拽填入棋盘
- 行消除判定与死亡判定
- 各种表现,例如消除动画、加分动画等
代码结构
将游戏逻辑(例如棋盘数据结构、死亡判定等)和界面逻辑分开,分别置于logic和ui界面。所有的UI界面交给UIManager脚本统一维护管理。
二. 创建工程与场景
创建工程Tetris和空的主场景Main,设置如下:

本工程中,画布背景(background)设置为透明
游戏入口与游戏初始化
在Scripts目录下创建文件:Tetris.js。代码如下:
/**
* 游戏入口
*/
window.Tetris = qc.Tetris = {
// 所有的操作指令集合
operation: {}
}; // 游戏逻辑初始化
qc.initGame = function(game) {
// 将游戏实例记录下来,便于访问
Tetris.game = game; // 帧率显示为60帧(满帧)
game.time.frameRate = 60;
};
设置此脚本为入口脚本:
此脚本首先定义了名字空间,将全局的数据都记录在qc.Tetris。游戏入口中,记录了game的实例并将帧率限定为60帧(默认在手机下为30帧)
三. 玩家分数管理
创建脚本:Scripts/logic/Score.js:
/**
* 维护分数信息
*/
var Score = qc.Tetris.Score = function() {
var self = this;
self._current = 0;
self._best = 0; // 将本地数据读取出来
var game = qc.Tetris.game;
var current = game.storage.get('current'),
best = game.storage.get('best');
if (current) self._current = current;
if (best) self._best = best;
};
Score.prototype = {};
Score.prototype.constructor = Score; Object.defineProperties(Score.prototype, {
current: {
get: function() { return this._current; },
set: function(v) {
this._current = v;
if (this.best < v) this.best = v;
}
}, best: {
get: function() { return this._best; },
set: function(v) {
this._best = v;
var storage = qc.Tetris.game.storage;
storage.set('best', v);
storage.save();
}
}
});Score类维护了两个数据:current(当前玩家的分数)、best(玩家的历史最高分)
实例化Score类
打开Tetris.js脚本,在initGame方法中,加入代码:qc.initGame = function(game) {
// 将游戏实例记录下来,便于访问
Tetris.game = game; // 帧率显示为60帧(满帧)
game.time.frameRate = 60; // 初始化分数信息
Tetris.score = new qc.Tetris.Score();
};
四. 棋盘设计与实现
棋盘为一边长为5的正六变形,为了方便计算,我们如下设定棋盘的坐标系(下文称为:格子逻辑坐标):

原点在六边形中心点,半径为4。
修改Tetris.js文件,增加棋盘的配置信息:
window.Tetris = qc.Tetris = {
// 棋盘的大小(半径)
SIZE: 4, // 棋盘中,每个格子的宽度和高度
BLOCK_W: 61,
BLOCK_H: 67, // 所有的操作指令集合
operation: {}
};棋盘格子的大小 = 格子图片的大小,后续导入资源后可以看到其大小为61*67。
在Scripts/logic下创建文件Board.js,维护棋盘的数据,代码如下:
var Board = qc.Tetris.Board = function() {
var self = this,
size = qc.Tetris.SIZE,
len = qc.Tetris.BLOCK_H; // 构建用来转换格子坐标的矩阵
var m = self.m = new qc.Matrix();
m.a = len;
m.c = len / 2;
m.d = len * (Math.sqrt(3) / 2); // 初始化棋盘数据
self.data = {};
for (var i = -size; i <= size; i++) {
for (var j = -size; j <= size; j++) {
// 这些格子落在六边形外,忽略掉
if (i * j > 0 && Math.abs(i + j) > size) continue;
if (i * j < 0 && (Math.abs(i) > size || Math.abs(j) > size)) continue; // 计算格子的坐标和对应屏幕上的偏移
var pos = Tetris.makePos(i, j);
var pt = self.toWorld(new qc.Point(i, j));
self.data[pos] = {
value: 0,
x: pt.x,
y: pt.y
};
}
}
};
Board.prototype = {};
Board.prototype.constructor = Board; Object.defineProperties(Board.prototype, {
/**
* @property {boolean} die - 当前是否已经死亡了
* @readonly
*/
die: {
get: function() {
// TODO: 等待实现
}
}
}); /**
* 清空棋盘
*/
Board.prototype.clear = function() {
for (var pos in this.data) {
this.data[pos].value = 0;
}
}; /**
* 重新开始游戏
*/
Board.prototype.restart = function() {
this.clear();
}; // 判定形状可以放进来不
// pos: 目标逻辑坐标
// list: 形状的信息
Board.prototype.checkPutIn = function(pos, list) {
// TODO: 等待实现
}; // 把某个形状放进来
Board.prototype.putIn = function(pos, list, value) {
// TODO: 等待实现
}; // 根据格子的逻辑坐标,算出所在的屏幕坐标
// distance: 两个格子中心点之间的距离
Board.prototype.toWorld = function(p, distance) {
if (!distance)
return this.m.apply(p); var m = new qc.Matrix();
m.a = distance;
m.c = distance * 0.5;
m.d = distance * (Math.sqrt(3) * 0.5);
return m.apply(p);
}; // 根据格子的屏幕坐标,反算格子的逻辑坐标
Board.prototype.toLocal = function(p) {
return this.m.applyInverse(p);
};修改Tetris.js,在qc.initGame方法中,实例化本对象:
qc.initGame = function(game) {
// 将游戏实例记录下来,便于访问
Tetris.game = game; // 帧率显示为60帧(满帧)
game.time.frameRate = 60; // 初始化分数信息
Tetris.score = new qc.Tetris.Score(); // 构建棋盘对象
Tetris.board = new qc.Tetris.Board();
};同时,在本文件中实现两个函数:makePos和readPos:
// 构建坐标
window.Tetris.makePos = function(x, y) {
return x + '_' + y;
}; // 获取坐标
window.Tetris.readPos = function(pos) {
var arr = pos.split('_');
return new qc.Point(arr[0]*1, arr[1]*1);
};
五. 屏幕布局
在美术设计时,以640*960分辨率(iPhone4)进行设计,其他分辨率的屏幕需要自适应。如下图:
- 整个界面分为标题栏(Top)、棋盘(Board)、3个形状(Shape)
- Top:高度在iPhone4上为130。这里有两个信息:当前分数与历史最高分数
- Board:棋盘,其大小为600*580
- Shape:3个形状,大小为600*230,距离底部20
- 自适应方案:
- 以 640*960为基准,等比缩放,确保所有内容都能全部显示
- 当分辨率比较瘦长时(即Height/Width > 960/640)时,Board和Shape保持和底部位置不变(方便单手操作)。Top高度自动增加
- 当分辨率比较宽时(即Height/Width < 960/640)时,Board和Shape保持居中,两边留白
导入资源
新建文件夹:Assets/atlas/ui@atlas,将以下文件拖入并打包图集(图片请在示例工程中查看)
blue.png、cyan.png、gray.png、green.png、lightyellow.png、red.png、shadow.png、white.png、yellow.png
darkblue.png、darkcyan.png、darkgreen.png、darklightyellow.png、darkred.png、darkyellow.png等,具体请参考示例工程
格子在没有数据时,显示gray.png。其他形状的格子颜色,有6种(blue、cyan、green、lightyellow、yellow、red)将以下文件拖入文件夹Assets/raw(raw目录下的资源都不会被打包,例如图片直接原样保留,适用于css样式表指定资源)
blue.png、cyan.png、gray.png、green.png、lightyellow.png、red.png、yellow.png等,具体请参考示例工程,各图片的用途在后续中会说明。
界面布局
1. 创建UIRoot,并设置Reference Resolution(参考分辨率)为 640*960,Manual Type为Expand

简单的理解:设置了以后,就可以认为屏幕的宽度>=640,高度>=960
2. 创建棋盘。棋盘大部分情况下是“静态”的,只是在有新的形状放入时才会变化。如果棋盘的每个格子作为UIImage进行贴图,则每帧都需要重绘几十个格子图片,对渲染效率会有所影响。这里我们适用DOM方案,里面每个格子使用div进行绘制。因此创建一个DOM节点,设置其大小为:600*580,同时由于棋盘距离底部的位置固定,因此在布局上:水平居中、垂直距离底部250,自身中心点在底部中心位置。如下图:

3. 添加一个Node节点,挂载3个形状。Node大小为 600*230,距离底部20。如下图:

4. 创建DOM节点显示历史最高分(不常变化,因此不用UIText,使用Dom更高效)。本节点大小为200*60,距离屏幕右边20,顶部20:

5. 创建DOM节点显示当前分(不常变化,因此不用UIText,使用Dom更高效)。本节点大小为200*80,水平居中,顶部顶部29:

JS开发HTML5游戏《神奇的六边形》(一)的更多相关文章
- JS开发HTML5游戏《神奇的六边形》(二)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- JS开发HTML5游戏《神奇的六边形》(四)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- JS开发HTML5游戏《神奇的六边形》(三)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- HTML5外包注意事项-开发HTML5游戏的九大坑与解决方法剖析
随着移动社区兴起,势必带动HTML5的革命.未来一两年内,HTML5移动游戏必将呈现大爆发趋势. 以下是整理的HTML5游戏研发.市场趋势以及渠道布局和技术解决方案的内容.希望大家能从本文中找到对HT ...
- JAVASCRIPT开发HTML5游戏--斗地主(网络对战PART4)
继之前用游戏引擎(青瓷引擎)做了斗地主单机版游戏之后,这里分享下使用socket.io来实现网络对战,代码可已放到github上,在此谈谈自己整个的开发思路吧. 客户端代码 服务端代码 (点击图片进入 ...
- javascript开发HTML5游戏--斗地主(单机模式part3)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 服务 ...
- javascript开发HTML5游戏--斗地主(单机模式part2)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 服务 ...
- 使用 video.js 开发 HTML5 视频页面
时间 2015-05-13 17:11:58 The GIS Guy 原文 http://thegisguy.tk/html5-video-using-video-js/ 主题 Video.js H ...
- javascript开发HTML5游戏--斗地主(单机模式part1)
最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 ...
随机推荐
- 一些特殊的URI编码字符
字符 URL编码值 space %20 " %22 # %23 % %25 & %26 ( %28 ) %29 + %2B , %2C / %2F : %3A ; %3B < ...
- Wampserver主机服务配置方法
一.更改根目录 1.左键”www目录”路径更改Wampserver安装好后,“www目录”默认为X:\wamp\www,也就是wampserver安装目录下的www文件夹.实际使用中,默认设置往往不 ...
- php自动加载
初學PHP時,最早會面對的問題之一就是require與include差別何在?require_once與include_once又是什麼?弄懂這些問題之後,如果不使用framework,直接開發,便常 ...
- [Linux]系统调用理解(1)
本文是Linux系统调用专栏系列文章的第一篇,对Linux系统调用的定义.基本原理.使用方法和注意事项大概作了一个介绍,以便读者对Linux系统调用建立一个大致的印象. 什么是系统调用? Linux内 ...
- C#动态创建和动态使用程序集、类、方法、字段等
C#动态创建和动态使用程序集.类.方法.字段等 分类:技术交流 (3204) (3) 首先需要知道动态创建这些类型是使用的一些什么技术呢?其实只要相关动态加载程序集呀,类呀,都是使用反射,那么动 ...
- sql单表中某一字段重复,取最近3条或几条数据
order by a.uid,a.id; sql查询语句,针对需求:一个表中某一字段是有重复的数据,针对该字段相同的值只取最近的3条或要求的几条: --记录铭心!
- 单词(bzoj 3172)
Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N ...
- iOS-OC-基本控件之UIPageControl
UIPageControl(页面控制器,就是桌面的那些小点点,每个点代表一个界面) 父类是 UIControl. iOS开发中常用的基本控件,主要和UIScrollView一起使用,比较常用的就是有些 ...
- MongoDB索引创建(5)
索引创建 1:索引提高查询速度,降低写入速度,权衡常用的查询字段,不必在太多列上建索引 2. 在mongodb中,索引可以按字段升序/降序来创建,便于排序 3. 默认是用btree来组织索引文件,2. ...
- python学习笔记(2)
1.for循环 用户按照顺序循环可迭代对象中的内容. li = [11,22,33,44] for i in li: print i for循环的else 此功能目前只有for循环里面有发现. 具体条 ...
