炸弹人的炸弹怎么可以移动的宽带怎么样?

(快去救列宁)
(Dark Gray)
第三方登录:sponsored links
炸弹人游戏开发系列(4):炸弹人显示与移动
在上文中,我已经介绍了如何测试、如何重构测试,并且通过实验掌握了地图显示的技术。本文会将地图显示的技术用到炸弹人显示中,并且让我们的炸弹人动起来。
注:为了提升博文质量和把重点放在记录开发和迭代的思想实践,本文及后续博文将不再记录测试过程。
实现炸弹人的显示和移动
本文主要内容
实现左右移动
绘制地图和炸弹人
本文最终领域模型
本文参考资料
回顾上文更新后的领域模型
对领域模型进行思考
ShowMap类是负责显示地图,包含了游戏逻辑。而Game类职责是负责游戏逻辑,因此ShowMap和Game在职责上是有重复的。况且显示地图这部分逻辑并不是很复杂,可以不需要专门的类来负责这部分逻辑,而是直接放到Game中。
现在来回头看看ShowMap类的显示地图实现:
drawMap: function () {
var i = 0,
map = bomberConfig.map,
bitmap = null,
mapData = mapDataOperate.getMapData(),
img = null;
this._createLayer();
for (i = 0; i & map.ROW; i++) {
//y为纵向height,x为横向width
y = i * map.HEIGHT;
for (j = 0; j & map.COL; j++) {
x = j * map.WIDTH;
img = this._getMapImg(i, j, mapData);
bitmap = bitmapFactory.createBitmap({ img: img, width: map.WIDTH, height: map.HEIGHT, x: x, y: y });
this.layer.appendChild(bitmap);
this.layer.draw();
ShowMap将显示地图的具体实现委托给了Layer,自己负责操作Layer,这个职责也可以移到Game中。且考虑到ShowMap类是用作实验(见上文的开发策略)的,现在&显示地图&的功能已经实现,ShowMap没有存在的必要了。
因此,我去掉ShowMap类,将其移到Game中。
重构后的领域模型
重构后Game类代码
(function () {
var Game = YYC.Class({
Init: function(){
Private: {
_pattern: null,
_ground: null,
_createLayer: function () {
this.layer = new Layer(this.createCanvas());
_getMapImg: function (i, j, mapData) {
var img = null;
switch (mapData[i][j]) {
img = main.imgLoader.get("ground");
img = main.imgLoader.get("wall");
layer: null,
onload: function () {
$("#progressBar").css("display", "none");
this.drawMap();
createCanvas: function (id) {
var canvas = document.createElement("canvas");
canvas.width = 600;
canvas.height = 400;
canvas.id =
document.body.appendChild(canvas);
drawMap: function () {
var i = 0,
map = bomberConfig.map,
bitmap = null,
mapData = mapDataOperate.getMapData(),
img = null;
this._createLayer();
for (i = 0; i & map.ROW; i++) {
//y为纵向height,x为横向width
y = i * map.HEIGHT;
for (j = 0; j & map.COL; j++) {
x = j * map.WIDTH;
img = this._getMapImg(i, j, mapData);
bitmap = bitmapFactory.createBitmap({img: img, width: map.WIDTH, height: map.HEIGHT, x: x, y: y});
this.layer.appendChild(bitmap);
this.layer.draw();
window.Game = G
Javascript设计模式之我见:迭代器模式。
将原Layer重命名为MapLayer
再来看看之前第3篇博文中创建的Layer类。这个类负责地图图片的渲染,应该将其重命名为MapLayer地图层。
提出父类Layer
现在有了PlayerLayer和MapLayer类后,需要将其通用操作提出来形成父类Layer类,然后由Layer类来继承Collection类。这样PlayerLayer和MapLayer类也就具有集合类的功能了。
  增加change 状态
&在上面的实现中,在游戏主循环中每次循环都会绘制一遍地图和炸弹人。考虑到地图是没有变化的,没必要重复的绘制相同的地图;而且如果炸弹人在画布上站到不动时,也是没有必要重复绘制炸弹人。
所以为了提升画布的性能,当只有画布内容发生变化时(如改变地图、炸弹人移动),才绘制画布。
因此,在Layer中增加state属性,该属性有两个枚举值:change、normal,用来标记画布改变和没有改变的状态。
在绘制画布时先判断Layer的state状态,如果为change,则绘制;否则则不绘制。
  在哪里判断?
应该在绘制画布的地方判断状态。那么应该是在Game的游戏主循环中判断,还是在Layer的render中判断呢?
还是从职责上分析。
Layer的职责:负责层内元素的统一管理。
Game的职责:负责游戏逻辑。
显然判断状态的职责应该属于Layer的职责,且与Layer的render方法最相关。所以应该在Layer的render中判断。
  什么时候改变state状态为change,什么时候为normal?
应该在画布内容发生改变时,画布需要重绘的时候改变state为change,然后在重绘完后,再状态为normal。
(function () {
var Layer = YYC.AClass(Collection, {
Init: function () {
Private: {
__state: bomberConfig.layer.state.NORMAL,
__getContext: function () {
this.P__context = this.P__canvas.getContext("2d");
Protected: {
//*子类使用的变量(可读、写)
P__canvas: null,
P__context: null,
P__isChange: function(){
return this.__state === bomberConfig.layer.state.CHANGE;
P__isNormal: function () {
return this.__state === bomberConfig.layer.state.NORMAL;
P__setStateNormal: function () {
this.__state = bomberConfig.layer.state.NORMAL;
P__setStateChange: function () {
this.__state = bomberConfig.layer.state.CHANGE;
Abstract: {
P__createCanvas: function () { }
//更改状态
change: function () {
this.__state = bomberConfig.layer.state.CHANGE;
setCanvas: function (canvas) {
if (canvas) {
if (!YYC.Tool.canvas.isCanvas(canvas)) {
throw new Error("参数必须为canvas元素");
this.P__canvas =
//子类实现
this.P__createCanvas();
clear: function () {
this.P__context.clearRect(0, 0, bomberConfig.canvas.WIDTH, bomberConfig.canvas.HEIGHT);
Virtual: {
init: function () {
this.__getContext();
Abstract: {
//统一绘制
draw: function () { },
//渲染到画布上
render: function () { }
window.Layer = L
(function () {
var MapLayer = YYC.Class(Layer, {
Init: function () {
Protected: {
//实现父类的抽象保护方法
P__createCanvas: function () {
var canvas = $("&canvas/&", {
width: bomberConfig.canvas.WIDTH.toString(),
height: bomberConfig.canvas.HEIGHT.toString(),
"position": "absolute",
"top": bomberConfig.canvas.TOP,
"left": bomberConfig.canvas.LEFT,
"border": "1px solid blue",
"z-index": 0
$("body").append(canvas);
this.P__canvas = canvas[0];
draw: function () {
var i = 0,
imgs = null;
imgs = this.getChilds();
for (i = 0, len = imgs. i & i++) {
this.P__context.drawImage(imgs[i].img, imgs[i].x, imgs[i].y, imgs[i].width, imgs[i].height);
render: function () {
if (this.P__isChange()) {
this.clear();
this.draw();
this.P__setStateNormal();
window.MapLayer = MapL
PlayerLayer
(function () {
var PlayerLayer = YYC.Class(Layer, {
Init: function (deltaTime) {
this.___deltaTime = deltaT
Private: {
___deltaTime: 0,
___iterator: function (handler) {
var args = Array.prototype.slice.call(arguments, 1),
nextElement = null;
while (this.hasNext()) {
nextElement = this.next();
nextElement[handler].apply(nextElement, args);
//要指向nextElement
this.resetCursor();
___update: function (deltaTime) {
this.___iterator("update", deltaTime);
___handleNext: function () {
this.___iterator("handleNext");
Protected: {
//实现父类的抽象保护方法
P__createCanvas: function () {
var canvas = $("&canvas/&", {
width: bomberConfig.canvas.WIDTH.toString(),
height: bomberConfig.canvas.HEIGHT.toString(),
"position": "absolute",
"top": bomberConfig.canvas.TOP,
"left": bomberConfig.canvas.LEFT,
"border": "1px solid red",
"z-index": 1
$("body").append(canvas);
this.P__canvas = canvas[0];
draw: function (context) {
this.___iterator("draw", context);
render: function () {
if (this.P__isChange()) {
this.clear();
this.___update(this.___deltaTime);
this.draw(this.P__context);
this.___handleNext();
this.P__setStateNormal();
window.PlayerLayer = PlayerL
增加LayerFactory
增加LayerFactory工厂,负责创建PlayerLayer和MapLayer类的实例。
LayerFactory
(function () {
var layerFactory = {
createMap: function () {
return new MapLayer();
createPlayer: function (deltaTime) {
return new PlayerLayer(deltaTime);
window.layerFactory = layerF
分离出了LayerManager类
回顾Game类,它做的事情太多了。
精灵类、Bitmap都是属于层的集合元素,因此由层来负责创建他们。
但是根据之前的分析,层的职责是负责统一管理层内元素,不应该给它增加创建元素的职责。
而且,现在Game中负责创建和管理两个层,这两个层在Game中的行为相似。
基于以上分析和参照了网上资料,我提出层管理类的概念。
  层管理类的职责
负责层的逻辑
  与层的区别
调用层面不一样。层是处理精灵的逻辑,它的元素为精灵。层管理是处理层的逻辑,它的元素为层。一个层对应一个层管理类,再把每一个层管理类中的通用行为提取出来,形成层管理类的父类。
因此,我提出了PlayerLayerManager、MapLayerManager、LayerManager类。
  领域模型
  相关代码
LayerManager
var LayerManager = YYC.AClass({
Init: function (layer) {
this.layer =
Private: {
layer: null,
addElement: function (element) {
var i = 0,
for (i = 0, len = element. i & i++) {
this.layer.appendChild(element[i]);
initLayer: function () {
this.layer.setCanvas();
this.layer.init();& & & & & & & & this.layer.change();
render: function () {
this.layer.render();
Abstract: {
createElement: function () {
PlayerLayerManager
var PlayerLayerManager = YYC.Class(LayerManager, {
Init: function (layer) {
this.base(layer);
Private: {
createElement: function () {
var element = [],
player = spriteFactory.createPlayer();
player.setAnim("walk_right");
element.push(player);
MapLayerManager
var MapLayerManager = YYC.Class(LayerManager, {
Init: function (layer) {
this.base(layer);
Private: {
__getMapImg: function (i, j, mapData) {
var img = null;
switch (mapData[i][j]) {
img = window.imgLoader.get("ground");
img = window.imgLoader.get("wall");
createElement: function () {
var i = 0,
map = bomberConfig.map,
element = [],
mapData = mapDataOperate.getMapData(),
img = null;
for (i = 0; i & map.ROW; i++) {
//y为纵向height,x为横向width
y = i * bomberConfig.HEIGHT;
for (j = 0; j & map.COL; j++) {
x = j * bomberConfig.WIDTH;
img = this.__getMapImg(i, j, mapData);
element.push(bitmapFactory.createBitmap({ img: img, width: bomberConfig.WIDTH, height: bomberConfig.HEIGHT, x: x, y: y }));
(function () {
var Game = YYC.Class({
Init: function () {
Private: {
_layerManager: [],
_createLayer: function () {
this.mapLayer = layerFactory.createMap();
this.playerLayer = layerFactory.createPlayer(this.sleep);
_createLayerManager: function () {
this._layerManager.push(new MapLayerManager(this.mapLayer));
this._layerManager.push(new PlayerLayerManager(this.playerLayer));
_initLayer: function () {
var i = 0,
for (i = 0, len = this._layerManager. i & i++) {
this._layerManager[i].addElement(this._layerManager[i].createElement());
this._layerManager[i].initLayer();
context: null,
mapLayer: null,
playerLayer: null,
init: function () {
this.sleep = Math.floor(1 / bomberConfig.FPS);
this._createLayer();
this._createLayerManager();
this._initLayer();
start: function () {
var self = this;
var mainLoop = window.setInterval(function () {
self.run();
}, this.sleep);
run: function () {
var i = 0,
for (i = 0, len = this._layerManager. i & i++) {
this._layerManager[i].render();
window.Game = G
本文最终领域模型
经过本文的开发后,实际的概念层次结构为:
其中,入口对应用户交互层,主逻辑、层管理、层、精灵对应业务逻辑层,数据操作对应数据操作层,数据对应数据层。
受此启发,可以将业务逻辑层细化为主逻辑、层管理、层、精灵四个层。
另外,领域模型中的工厂类属于业务逻辑层,它与其它四个层中的层管理和层有关联,且不属于其它四个层。因此,在业务逻辑层中提出负责通用操作的辅助逻辑层,将工厂类放到该层中。
重构后的层
层、领域模型
包和组件的设计原则
重用发布等价原则(REP)&
重用的粒度就是发布的粒度:一个包中的软件要么都是可重用的,要么都是不可重用的。
共同重用原则(CRP)
一个包中所有类应该是共同重用的。如果重用了包中的一个类,那么就重用包中的所有类。
共同封闭原则(CCP)
包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对包中的所有类产生影响,而对于其他的包不造成任何影响。
无环依赖原则(ADP)&
在包的依赖图中,不允许存在环。
稳定依赖原则(SDP)
朝着稳定的方向进行依赖。
稳定抽象原则(SAP)
包的抽象程度应该和其稳定程度一致。
本文包划分
对应领域模型
辅助操作层
控件包PreLoadImg
配置包Config
用户交互层
入口包Main
业务逻辑层
工厂包BitmapFactory、LayerFactory、SpriteFactory
游戏主逻辑
主逻辑包Game
层管理实现包PlayerLayerManager、MapLayerManager
层管理抽象包
LayerManager
层实现包PlayerLayer、MapLayer
层抽象包Layer
集合包Collection
精灵包PlayerSprite
动画包Animation、GetSpriteData、SpriteData、GetFrames、FrameData
数据操作层
地图数据操作包MapDataOperate
路径数据操作包GetPath
图片数据操作包Bitmap
地图包MapData
图片路径包ImgPathData
Animation为什么与GetSpriteData、SpriteData、GetFrames、FrameData放在一起?
虽然从封闭性上分析,GetSpriteData、SpriteData、GetFrames、FrameData对于精灵数据的变化会一起变化,而Animation不会一起变化,Animation应该对于动画逻辑的变化而变化。因此,Animation与GetSpriteData、SpriteData、GetFrames、FrameData不满足共同封闭原则。
但是,因为Animation与其它四个类紧密相关,可以一起重用。
因此还是将Animation和GetSpriteData、SpriteData、GetFrames、FrameData都一起放到动画包中。
本文参考资料
《敏捷软件开发:原则、模式与实践》&
欢迎浏览上一篇博文:炸弹人游戏开发系列(3):显示地图
欢迎浏览下一篇博文:炸弹人游戏开发系列(5):控制炸弹人移动,引入状态模式
前言 大家好!本系列博文记录了我的炸弹人游戏迭代开发的过程.在开发的过程中,代码会不断重构,领域模型会不断演变,高层划分也会不断变化. 博文重点在于记录面向对象思想运用.重构.迭代开发的过程,对于游戏的实现细节和原理不会深入讨论. 如果您对RPG游戏的基本概念不熟悉,我推荐您可以先看看HTML5研究小组第二期技术讲座&手把手制作HTML5游戏&, ...
前言 上文中我们加入了1个敌人,使用A*算法寻路.本文会给我们的炸弹人增加放炸弹的能力. 说明 名词解释 xx类族是指以xx为基类的继承树上的所有类. 本文目的 实现“放炸弹”功能 增加1个敌人,即一共有2个敌人追踪炸弹人 本文主要内容
开发策略 显示炸弹和火焰 使用观察者模式 重构 炸弹可以炸死炸弹人和敌人 移动时放炸弹 放置多个炸弹 改变地图 小结
前言 上文中我们实现了炸弹人与墙的碰撞检测,以及设置移动步长来解决发现的问题.本文会加入1个AI敌人,敌人使用A*算法追踪炸弹人. 本文目的 加入敌人,追踪炸弹人 本文主要内容 开发策略 加入敌人 实现 寻路算法 重构 本文最终领域模型 高层划分 演示 本文参考资料 回顾上文更新后的领域模型 炸弹人游戏开发系列(4):炸弹人显示与移动“中的实现,可以初步分析 ...
前言 上文中我们实现了“玩家控制炸弹人”的功能,本文将实现碰撞检测,让炸弹人不能穿过墙.在实现的过程中会发现炸弹人移动的问题,然后会通过设置移动步长来解决. 说明 名词解释 具体状态类指应用于炸弹人移动状态的状态模式的ConcreState角色的类.这里具体包括WalkLeftState.WalkRightState.WalkUpState.WalkDown ...
前言 上文中我们实现了炸弹人显示和左右移动.本文开始监听键盘事件,使玩家能控制炸弹人移动.然后会在重构的过程中会引入状态模式.大家会看到我是如何在开发的过程中通过重构来提出设计模式,而不是在初步设计阶段提出设计模式的. 本文目的 实现“使用键盘控制玩家移动” 完善炸弹人移动,增加上下方向的移动 本文主要内容 开发策略 性能优化 控制炸弹人移动 引入状态模式炸弹人~~点右下角“start”开始游戏。上下左右方向键控制移动,回车键放炸弹,P键暂停。
从论坛获得的筹码:
注册时间:
游戏中阶达人
贡献546, 距离下一级还需54贡献
注册时间:
自动加载图片
楼主 电梯直达 楼
回帖后跳转到最后一页
您需要登录后才可以发帖&&(ERROR:15) & 访客不能直接访问更多频道内容在这里查看
爱奇艺用户将能永久保存播放记录
过滤短视频
暂无长视频(电视剧、纪录片、动漫、综艺、电影)播放记录,
按住视频可进行拖动
&正在加载...
收藏成功,可进入
查看所有收藏列表
当前浏览器仅支持手动复制代码
视频地址:
flash地址:
html代码:
通用代码:
通用代码可同时支持电脑和移动设备的分享播放
用爱奇艺APP或微信扫一扫,在手机上继续观看
当前播放时间:
一键下载至手机
限爱奇艺安卓6.0以上版本
使用微信扫一扫,扫描左侧二维码,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
设备搜寻中...
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
连接失败!
请确保您要连接的设备(仅限安卓)登录了同一爱奇艺账号 且安装并开启不低于V6.0以上版本的爱奇艺客户端
部安卓(Android)设备,请点击进行选择
请您在手机端下载爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
其他安装方式:手机浏览器输入短链接http://71.am/udn
下载安装包到本机:
爱奇艺云推送
请您在手机端登录爱奇艺移动APP(仅支持安卓客户端)
使用微信扫一扫,下载爱奇艺移动APP
180秒后更新
打开爱奇艺移动APP,点击“我的-扫一扫”,扫描左侧二维码进行登录
没有安装爱奇艺视频最新客户端?
FC游戏《炸弹人》,炸过门的出去罚站,炸
正在检测客户端...
您尚未安装客户端,正在为您下载...安装完成后点击按钮即可下载
30秒后自动关闭
FC游戏《炸弹人》,炸过门的出去罚站,炸">FC游戏《炸弹人》,炸过门的出去罚站,炸
请选择打赏金额:
播放量12.7万
播放量数据:快去看看谁在和你一起看视频吧~
更多数据:
Copyright (C) 2018 & All Rights Reserved
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制
正在为您下载爱奇艺客户端安装后即可快速下载海量视频
正在为您下载爱奇艺客户端安装后即可免费观看1080P视频
&li data-elem="tabtitle" data-seq="{{seq}}"& &a href="javascript:void(0);"& &span>{{start}}-{{end}}&/span& &/a& &/li&
&li data-downloadSelect-elem="item" data-downloadSelect-selected="false" data-downloadSelect-tvid="{{tvid}}"& &a href="javascript:void(0);"&{{pd}}&/a&
选择您要下载的《
色情低俗内容
血腥暴力内容
广告或欺诈内容
侵犯了我的权力
还可以输入
您使用浏览器不支持直接复制的功能,建议您使用Ctrl+C或右键全选进行地址复制

我要回帖

更多关于 中国移动的宽带怎么样 的文章

 

随机推荐