
jQuery版坦克游戏,缺陷面向对象重构版!
一款jQuery版tank游戏,画面美观、逼真,可双人游戏,其效果堪与flash媲美。支持浏览器:ie6+,firefox,opera,safari,在ie9或其他非ie浏览器,可获得更加流畅的游戏速度。
下载地址:
.0.zip 诚邀各位志士组团(HTML5+ANDROID):38155026(欢迎入群)
此文精辟点在第七页“fch415”大哥的回复里面! 此版本经过精心重构,面向接口设计,模仿类式继承和多继承(掺元类),多处使用闭包优化实现,使用单体工厂模式降低代码间耦合,添加图片及地图的预加载等等;重构版用新算法替代了大量DOM相关的操作,大大提高了游戏性能,即使在ie6下玩,效果也差强人意。
源码说明: 1.tank.main.js 定义了基本的接口及其实现,如图:
Javascript代码
- // Interfaces.
- var Tank = new Interface('Tank', ['explode','clear','die','fire','isShot','move','stopMoving','isBlocked','attachEvents','init']);
- var Bullet = new Interface('Bullet',['explode','clear','die','fire','init']);
- var Block = new Interface('Block', ['explode','clear','die','isShot','display']);
-
- // Abstract tank, impl base methods.
- var AbstractTank = function(opt) { // Constructor
- this.id = opt.id;
- this.isAlive = true;
- this.speed = opt.speed;
- this.top = opt.pos.y;
- this.left = opt.pos.x;
- this.movingToward = 'up';
- this.init();
- this.attachEvents();
- };
-
- AbstractTank.prototype = { // Public methods
- move: function(_d) {
- ...
- },
- stopMoving: function() {
- var _d = this.movingToward, thisTank = $('div#' + this.id);
- clearInterval(this.moveTimr);
- veClass('moving' + _d);
- },
- isBlocked: function() {
- ...
- },
- die: function() {
- this.isAlive = false;
- this.explode('mapbomb', 11);
- },
- fire: function() {
- ateBullet(this);
- return this;
- },
- isShot: function() {
- throw new Error('isShot function is undefined.');
- },
- clear: function() {
- throw new Error('clear function is undefined.');
- },
- attachEvents: function() {
- throw new Error('attachEvents function is undefined.');
- },
- init: function() {
- throw new Error('init function is undefined.');
- }
- };
// Interfaces.
var Tank = new Interface('Tank', ['explode','clear','die','fire','isShot','move','stopMoving','isBlocked','attachEvents','init']);
var Bullet = new Interface('Bullet',['explode','clear','die','fire','init']);
var Block = new Interface('Block', ['explode','clear','die','isShot','display']);// Abstract tank, impl base methods.
var AbstractTank = function(opt) { // Constructorthis.id = opt.id;this.isAlive = true;this.speed = opt.p = opt.pos.y;this.left = opt.pos.vingToward = 'up';this.init();this.attachEvents();
};AbstractTank.prototype = { // Public methodsmove: function(_d) {...},stopMoving: function() {var _d = vingToward, thisTank = $('div#' + this.id);veTimr);veClass('moving' + _d);},isBlocked: function() {...},die: function() {this.isAlive = plode('mapbomb', 11);},fire: function() {ateBullet(this);return this;},isShot: function() {throw new Error('isShot function is undefined.');},clear: function() {throw new Error('clear function is undefined.');},attachEvents: function() {throw new Error('attachEvents function is undefined.');},init: function() {throw new Error('init function is undefined.');}
};
2.tank.factory.js 实例化坦克、block、子弹等。
Javascript代码
- var TankWarFactory = {
- createPlayerTank: function() {
- var tank = new PlayerTank();
- sureImplements(tank, Tank);
- TankWar.barrier.players.push(tank);
- TankWarMng.setTankCount(tank.id, --tank.lives);
- TankWarMng.setScore(tank, 0);
- },
- createEnemyTank: (function() {
- // Private static check type of enemies.
- function checkType(type) {
- var types = pes.clone();
- if (!type) type = 'r';
- if (ies[type].leftNum > 0) return type;
- ve(type);
- for (var i = 0, len = types.length; i < len; i++) {
- if (ies[types[0]].leftNum === 0) {
- ve(types[0]);
- } else {
- return types[0];
- }
- }
- return false;
- }
- return function(type) { // return constructor
- var tank;
- type = checkType(type);
- if (!type) throw new Error('No enemies alive.');
- switch(type) {
- case 'r': tank = new EnemyRTank(); break;
- case 'b': tank = new EnemyBTank(); break;
- case 'y': tank = new EnemyYTank(); break;
- case 'g': tank = new EnemyGTank(); break;
- }
- sureImplements(tank, Tank);
- ies.push(tank);
- TankWarMng.setTankCount(tank.id, --ies[type].leftNum);
- }
- })(),
- createBullet: function(tank) {
- var bullet;
- if (tank instanceof PlayerTank) {
- bullet = new PlayerBullet(tank);
- } else {
- bullet = new EnemyBullet(tank);
- }
- sureImplements(bullet, Bullet);
- },
- createBlock: function(param) {
- var block;
- switch(pe) {
- case 'e': block = new BrickBlock(param); alBlocks.push(block);break;
- case 'h': block = new StoneBlock(param); alBlocks.push(block);break;
- case 'k': block = new KingBlock(param); alBlocks.push(block);break;
- case 'w': block = new WaterBlock(param); TankWar.barrier.waterBlocks.push(block);break;
- case 'b': block = new BornBlock(param); ies.posBorn.push({x:block.left,p,avaliable:true});break;
- case 'l': block = new LawnBlock(param);break;
- }
- sureImplements(block, Block);
- }
- };
var TankWarFactory = {createPlayerTank: function() {var tank = new PlayerTank();sureImplements(tank, Tank);TankWar.barrier.players.push(tank);TankWarMng.setTankCount(tank.id, --tank.lives);TankWarMng.setScore(tank, 0);},createEnemyTank: (function() {// Private static check type of enemies.function checkType(type) {var types = pes.clone();if (!type) type = 'r';if (ies[type].leftNum > 0) return ve(type);for (var i = 0, len = types.length; i < len; i++) {if (ies[types[0]].leftNum === 0) {ve(types[0]);} else {return types[0];}}return false;}return function(type) { // return constructorvar tank;type = checkType(type);if (!type) throw new Error('No enemies alive.');switch(type) {case 'r': tank = new EnemyRTank(); break;case 'b': tank = new EnemyBTank(); break;case 'y': tank = new EnemyYTank(); break;case 'g': tank = new EnemyGTank(); break;}sureImplements(tank, Tank);ies.push(tank);TankWarMng.setTankCount(tank.id, --ies[type].leftNum);}})(),createBullet: function(tank) {var bullet;if (tank instanceof PlayerTank) {bullet = new PlayerBullet(tank);} else {bullet = new EnemyBullet(tank);}sureImplements(bullet, Bullet);},createBlock: function(param) {var block;pe) {case 'e': block = new BrickBlock(param); alBlocks.push(block);break;case 'h': block = new StoneBlock(param); alBlocks.push(block);break;case 'k': block = new KingBlock(param); alBlocks.push(block);break;case 'w': block = new WaterBlock(param); TankWar.barrier.waterBlocks.push(block);break;case 'b': block = new BornBlock(param); ies.posBorn.push({x:block.left,p,avaliable:true});break;case 'l': block = new LawnBlock(param);break;}sureImplements(block, Block);}
};
3.tankwar.js 将页面切换、游戏初始化、事件绑定等封装为TankWarMng对象的方法。
4.tank.progress.js 图片及地图预加载。
Javascript代码
- var PreLoad = (function() {
- // 私有静态方法
- function obj2array(givenObj) {
- var urllist = [], patrn = /1-d{1,2}.(png|json)$/, level = 0, levelArr = [];
- if (Site) levelArr[level++] = Site;
- (function(obj) { // 解析对象,将结果填进urllist数组
- for (var prop in obj) {
- if (prop === 'urls') {
- for (var i = 0, n = obj[prop].length; i < n; i++) {
- if (st(obj[prop][i])) {
- var tmp = obj[prop][i].split('.')[0].split('-'), suffix = (obj[prop][i])[1];
- for (var j = tmp[0], m = tmp[1]; j <= m; j++) {
- urllist.push(levelArr.join('/') + '/' + j + '.' + suffix);
- }
- } else {
- urllist.push(levelArr.join('/') + '/' + obj[prop][i]);
- }
- }
- levelArr.splice(--level, 1);
- } else {
- levelArr[level++] = prop;
- arguments.callee(obj[prop]);
- }
- }
- })(givenObj);
- return urllist;
- };
- // 构造器
- return function(urlObj, callback) {
- this.callback = callback;
- if (!Site) { // 如果没有启动预加载,直接进入回调
- this.progressBar(100);
- return;
- }
- this.urlList = obj2array(urlObj);
- this.total = this.urlList.length;
- this.succeedcount = 0;
- this.errorcount = 0;
- this.init();
- }
- })();
-
- PreLoad.prototype = {
- loadImg: function(url) {
- var img = new Image(), that = this;
- load = function() {
- thatplete(url, '图片');
- }
- r = function() {
- (url);
- }
- img.src = url;
- },
- loadMap: function(url) {
- var that = this;
- $.getJSON(url, function(map) {
- TankWar.maps.push(map);
- thatplete(url, '地图');
- });
- },
- complete: function(url, type) {
- this.und(++this.succeedcount*100/this.total), url, type);
- },
- error: function(url) {
- throw new Error('load '+ url +' failed.');
- },
- progressBar: function(percent, url, type) {
- if (url && type) {
- $('#percent span').text(percent);
- $('#loading span').text(type + ': ' + url.substr(url.lastIndexOf('/') + 1, url.length));
- }
- $('#bar').stop().animate({left: 550 - 550*percent/100}, 200);
- if (percent === 100) this.over();
- },
- over: function() {
- var that = this;
- setTimeout(function() {
- that.callback();
- }, 500);
- },
- init: function() {
- $('#percent, #loading').show();
- for (var i = 0; i < this.total; i++) {
- if (/.json$/.test(this.urlList[i]))
- this.loadMap(this.urlList[i]);
- else
- this.loadImg(this.urlList[i]);
- }
- }
- };
var PreLoad = (function() {// 私有静态方法function obj2array(givenObj) {var urllist = [], patrn = /1-d{1,2}.(png|json)$/, level = 0, levelArr = [];if (Site) levelArr[level++] = Site;(function(obj) { // 解析对象,将结果填进urllist数组for (var prop in obj) {if (prop === 'urls') {for (var i = 0, n = obj[prop].length; i < n; i++) {if (st(obj[prop][i])) {var tmp = obj[prop][i].split('.')[0].split('-'), suffix = (obj[prop][i])[1];for (var j = tmp[0], m = tmp[1]; j <= m; j++) {urllist.push(levelArr.join('/') + '/' + j + '.' + suffix);}} else {urllist.push(levelArr.join('/') + '/' + obj[prop][i]);}}levelArr.splice(--level, 1);} else {levelArr[level++] = prop;arguments.callee(obj[prop]);}}})(givenObj);return urllist;};// 构造器return function(urlObj, callback) {this.callback = callback;if (!Site) { // 如果没有启动预加载,直接进入回调this.progressBar(100);return;}this.urlList = obj2array(urlObj);al = this.urlList.length;this.succeedcount = ount = 0;this.init();}
})();PreLoad.prototype = {loadImg: function(url) {var img = new Image(), that = load = function() {thatplete(url, '图片');}r = function() {(url);}img.src = url;},loadMap: function(url) {var that = this;$.getJSON(url, function(map) {TankWar.maps.push(map);thatplete(url, '地图');});},complete: function(url, type) {this.und(++this.succeedcount*al), url, type);},error: function(url) {throw new Error('load '+ url +' failed.');},progressBar: function(percent, url, type) {if (url && type) {$('#percent span').text(percent);$('#loading span').text(type + ': ' + url.substr(url.lastIndexOf('/') + 1, url.length));}$('#bar').stop().animate({left: 550 - 550*percent/100}, 200);if (percent === 100) this.over();},over: function() {var that = this;setTimeout(function() {that.callback();}, 500);},init: function() {$('#percent, #loading').show();for (var i = 0; i < al; i++) {if (/.json$/.test(this.urlList[i]))this.loadMap(this.urlList[i]);elsethis.loadImg(this.urlList[i]);}}
};
5.util.js 接口、接口检查、继承等的实现。
6.tank.namespace.js & fig.js 命名空间及常用参数。
Javascript代码
- var config = {};
<_site = ''; // 如果将此游戏放在您网站上,请配置网址如_site = '',将会自动启用预加载技术,以获得更好的游戏体验 -
- config.develop_model = 'product'; // develop|test|product 如果是product,将不进行接口检查,以提高游戏速度
-
<_number_of_level = [{r:5,b:3,y:2,g:1},{r:10,b:5,y:3,g:2},{r:15,b:5,y:5,g:5}]; // 每一关的敌方坦克数量,目前有三关 -
- config.default_scene = 'lawn'; // 默认场景
-
- // 游戏参数
- config.player1_lives = 4;
- config.player1_speed = 2;
- config.player1_move_keys = { 37: 'left', 38: 'up', 39: 'right', 40: 'down'};
- config.player1_fire_key = 32;
-
- config.player2_lives = 4;
- config.player2_speed = 2;
- config.player2_move_keys = { 65: 'left', 87: 'up', 68: 'right', 83: 'down'};
- config.player2_fire_key = 71;
-
<_red_speed = 1; <_blue_speed = 1.5; <_yellow_speed = 2; <_green_speed = 2.5; - config.bullet_speed = 10;
var config = {};
_site = ''; // 如果将此游戏放在您网站上,请配置网址如_site = '',将会自动启用预加载技术,以获得更好的游戏体验config.develop_model = 'product'; // develop|test|product 如果是product,将不进行接口检查,以提高游戏速度_number_of_level = [{r:5,b:3,y:2,g:1},{r:10,b:5,y:3,g:2},{r:15,b:5,y:5,g:5}]; // 每一关的敌方坦克数量,目前有三关config.default_scene = 'lawn'; // 默认场景// 游戏参数
config.player1_lives = 4;
config.player1_speed = 2;
config.player1_move_keys = { 37: 'left', 38: 'up', 39: 'right', 40: 'down'};
config.player1_fire_key = 32;config.player2_lives = 4;
config.player2_speed = 2;
config.player2_move_keys = { 65: 'left', 87: 'up', 68: 'right', 83: 'down'};
config.player2_fire_key = _red_speed = 1;
_blue_speed = 1.5;
_yellow_speed = 2;
_green_speed = 2.5;
config.bullet_speed = 10;
7.1-3.json 地图
Javascript代码
- [{
- "type": "b", // b为敌方坦克出生地,你可以添加/减少b的个数,调节敌方坦克数量
- "y": 10,
- "x": 9
- }, {
- "type": "b",
- "y": 9,
- "x": 332
- }, {
- "type": "b",
- "y": 9,
- "x": 653
- },
-
- {
- "type": "h", // 子弹打不破的石头
- "y": 172,
- "x": 10
- },
-
- {
- "type": "l", // 草地
- "y": 212,
- "x": 43
- }, {
- "type": "e", // 子弹两次可以打破的砖头
- "y": 212,
- "x": 79
- }]
[{"type": "b", // b为敌方坦克出生地,你可以添加/减少b的个数,调节敌方坦克数量"y": 10,"x": 9
}, {"type": "b","y": 9,"x": 332
}, {"type": "b","y": 9,"x": 653
},{"type": "h", // 子弹打不破的石头"y": 172,"x": 10
},{"type": "l", // 草地"y": 212,"x": 43
}, {"type": "e", // 子弹两次可以打破的砖头"y": 212,"x": 79
}]
更多精彩,请下载源码:
.0.zip 游戏效果截图: 主页--游戏设置
游戏中..
暂停/退出
任务结束
此文供大家交流,共同学习,可以随便转载!
转载于:.html