一款jQuery版tank游戏,画面美观、逼真,可双人游戏,其效果堪与flash媲美。支持浏览器:ie6+,firefox,opera,safari,在ie9或其他非ie浏览器,可获得更加流畅的游戏速度。
下载地址:
http://jtankwar.googlecode.com/files/tank%20war%203.0.zip
欢迎入群:38155026
此版本经过精心重构,面向接口设计,模仿类式继承和多继承(掺元类),多处使用闭包优化实现,使用单体工厂模式降低代码间耦合,添加图片及地图的预加载等等;重构版用新算法替代了大量DOM相关的操作,大大提高了游戏性能,即使在ie6下玩,效果也差强人意。
源码说明:
1.tank.main.js 定义了基本的接口及其实现,如图:
// 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);
thisTank.removeClass('moving' + _d);
},
isBlocked: function() {
...
},
die: function() {
this.isAlive = false;
this.explode('mapbomb', 11);
},
fire: function() {
TankWarFactory.createBullet(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、子弹等。
var TankWarFactory = {
createPlayerTank: function() {
var tank = new PlayerTank();
Interface.ensureImplements(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 = TankWar.enemies.types.clone();
if (!type) type = 'r';
if (TankWar.enemies[type].leftNum > 0) return type;
types.remove(type);
for (var i = 0, len = types.length; i < len; i++) {
if (TankWar.enemies[types[0]].leftNum === 0) {
types.remove(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;
}
Interface.ensureImplements(tank, Tank);
TankWar.barrier.enemies.push(tank);
TankWarMng.setTankCount(tank.id, --TankWar.enemies[type].leftNum);
}
})(),
createBullet: function(tank) {
var bullet;
if (tank instanceof PlayerTank) {
bullet = new PlayerBullet(tank);
} else {
bullet = new EnemyBullet(tank);
}
Interface.ensureImplements(bullet, Bullet);
},
createBlock: function(param) {
var block;
switch(param.type) {
case 'e': block = new BrickBlock(param); TankWar.barrier.normalBlocks.push(block);break;
case 'h': block = new StoneBlock(param); TankWar.barrier.normalBlocks.push(block);break;
case 'k': block = new KingBlock(param); TankWar.barrier.normalBlocks.push(block);break;
case 'w': block = new WaterBlock(param); TankWar.barrier.waterBlocks.push(block);break;
case 'b': block = new BornBlock(param); TankWar.enemies.posBorn.push({x:block.left,y:block.top,avaliable:true});break;
case 'l': block = new LawnBlock(param);break;
}
Interface.ensureImplements(block, Block);
}
};
3.tankwar.js 将页面切换、游戏初始化、事件绑定等封装为TankWarMng对象的方法。
4.tank.progress.js 图片及地图预加载。
var PreLoad = (function() {
// 私有静态方法
function obj2array(givenObj) {
var urllist = [], patrn = /1-\d{1,2}\.(png|json)$/, level = 0, levelArr = [];
if (TankWar.mySite) levelArr[level++] = TankWar.mySite;
(function(obj) { // 解析对象,将结果填进urllist数组
for (var prop in obj) {
if (prop === 'urls') {
for (var i = 0, n = obj[prop].length; i < n; i++) {
if (patrn.test(obj[prop][i])) {
var tmp = obj[prop][i].split('.')[0].split('-'), suffix = patrn.exec(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 (!TankWar.mySite) { // 如果没有启动预加载,直接进入回调
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;
img.onload = function() {
that.complete(url, '图片');
}
img.onerror = function() {
that.error(url);
}
img.src = url;
},
loadMap: function(url) {
var that = this;
$.getJSON(url, function(map) {
TankWar.maps.push(map);
that.complete(url, '地图');
});
},
complete: function(url, type) {
this.progressBar(Math.round(++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]);
}
}
};
5.util.js 接口、接口检查、继承等的实现。
6.tank.namespace.js & tank.config.js 命名空间及常用参数。
var config = {};
config.my_site = ''; // 如果将此游戏放在您网站上,请配置网址如:config.my_site = 'http://www.mysite.com/tank',将会自动启用预加载技术,以获得更好的游戏体验
config.develop_model = 'product'; // develop|test|product 如果是product,将不进行接口检查,以提高游戏速度
config.enemy_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;
config.enemy_red_speed = 1;
config.enemy_blue_speed = 1.5;
config.enemy_yellow_speed = 2;
config.enemy_green_speed = 2.5;
config.bullet_speed = 10;
7.1-3.json 地图
[{
"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
}]
更多精彩,请下载源码:
http://jtankwar.googlecode.com/files/tank%20war%203.0.zip
游戏效果截图:
主页--游戏设置
游戏中..
暂停/退出
任务结束