jQuery版坦克游戏,缺陷面向对象重构版!

 一款jQuery版tank游戏,画面美观、逼真,可双人游戏,其效果堪与flash媲美。支持浏览器:ie6+,firefox,opera,safari,在ie9或其他非ie浏览器,可获得更加流畅的游戏速度。
    下载地址:http://jtankwar.googlecode.com/files/tank%20war%203.0.zip
    诚邀各位志士组团(HTML5+ANDROID):38155026(欢迎入群)
    此文精辟点在第七页“fch415”大哥的回复里面!

    此版本经过精心重构,面向接口设计,模仿类式继承和多继承(掺元类),多处使用闭包优化实现,使用单体工厂模式降低代码间耦合,添加图片及地图的预加载等等;重构版用新算法替代了大量DOM相关的操作,大大提高了游戏性能,即使在ie6下玩,效果也差强人意。

源码说明:
1.tank.main.js 定义了基本的接口及其实现,如图:

Javascript代码  
  1. // Interfaces.   
  2. var Tank = new Interface('Tank', ['explode','clear','die','fire','isShot','move','stopMoving','isBlocked','attachEvents','init']);   
  3. var Bullet = new Interface('Bullet',['explode','clear','die','fire','init']);   
  4. var Block = new Interface('Block', ['explode','clear','die','isShot','display']);   
  5.   
  6. // Abstract tank, impl base methods.   
  7. var AbstractTank = function(opt) { // Constructor   
  8.     this.id = opt.id;   
  9.     this.isAlive = true;   
  10.     this.speed = opt.speed;   
  11.     this.top = opt.pos.y;   
  12.     this.left = opt.pos.x;   
  13.     this.movingToward = 'up';   
  14.     this.init();   
  15.     this.attachEvents();   
  16. };   
  17.   
  18. AbstractTank.prototype = { // Public methods   
  19.     move: function(_d) {   
  20.        ...   
  21.         },   
  22.     stopMoving: function() {   
  23.         var _d = this.movingToward, thisTank = $('div#' + this.id);   
  24.         clearInterval(this.moveTimr);   
  25.         thisTank.removeClass('moving' + _d);   
  26.     },   
  27.     isBlocked: function() {   
  28.             ...   
  29.     },   
  30.     die: function() {   
  31.         this.isAlive = false;   
  32.         this.explode('mapbomb', 11);   
  33.     },   
  34.     fire: function() {   
  35.         TankWarFactory.createBullet(this);   
  36.         return this;   
  37.     },   
  38.     isShot: function() {   
  39.         throw new Error('isShot function is undefined.');   
  40.     },   
  41.     clear: function() {   
  42.         throw new Error('clear function is undefined.');   
  43.     },   
  44.     attachEvents: function() {   
  45.         throw new Error('attachEvents function is undefined.');   
  46.     },   
  47.     init: function() {   
  48.         throw new Error('init function is undefined.');   
  49.     }   
  50. };  

2.tank.factory.js 实例化坦克、block、子弹等。
Javascript代码  
  1. var TankWarFactory = {   
  2.     createPlayerTank: function() {   
  3.         var tank = new PlayerTank();   
  4.         Interface.ensureImplements(tank, Tank);   
  5.         TankWar.barrier.players.push(tank);   
  6.         TankWarMng.setTankCount(tank.id, --tank.lives);   
  7.         TankWarMng.setScore(tank, 0);   
  8.     },   
  9.     createEnemyTank: (function() {   
  10.         // Private static check type of enemies.   
  11.         function checkType(type) {   
  12.             var types = TankWar.enemies.types.clone();   
  13.             if (!type) type = 'r';   
  14.             if (TankWar.enemies[type].leftNum > 0) return type;   
  15.             types.remove(type);   
  16.             for (var i = 0, len = types.length; i < len; i++) {   
  17.                 if (TankWar.enemies[types[0]].leftNum === 0) {   
  18.                     types.remove(types[0]);   
  19.                 } else {   
  20.                     return types[0];   
  21.                 }   
  22.             }   
  23.             return false;   
  24.         }   
  25.         return function(type) { // return constructor   
  26.             var tank;   
  27.             type = checkType(type);   
  28.             if (!type) throw new Error('No enemies alive.');   
  29.             switch(type) {   
  30.                 case 'r': tank = new EnemyRTank(); break;   
  31.                 case 'b': tank = new EnemyBTank(); break;   
  32.                 case 'y': tank = new EnemyYTank(); break;   
  33.                 case 'g': tank = new EnemyGTank(); break;   
  34.             }   
  35.             Interface.ensureImplements(tank, Tank);   
  36.             TankWar.barrier.enemies.push(tank);   
  37.             TankWarMng.setTankCount(tank.id, --TankWar.enemies[type].leftNum);   
  38.         }   
  39.     })(),   
  40.     createBullet: function(tank) {   
  41.         var bullet;   
  42.         if (tank instanceof PlayerTank) {   
  43.             bullet = new PlayerBullet(tank);   
  44.         } else {   
  45.             bullet = new EnemyBullet(tank);   
  46.         }   
  47.         Interface.ensureImplements(bullet, Bullet);   
  48.     },   
  49.     createBlock: function(param) {   
  50.         var block;   
  51.         switch(param.type) {   
  52.             case 'e': block = new BrickBlock(param); TankWar.barrier.normalBlocks.push(block);break;   
  53.             case 'h': block = new StoneBlock(param); TankWar.barrier.normalBlocks.push(block);break;   
  54.             case 'k': block = new KingBlock(param); TankWar.barrier.normalBlocks.push(block);break;   
  55.             case 'w': block = new WaterBlock(param); TankWar.barrier.waterBlocks.push(block);break;   
  56.             case 'b': block = new BornBlock(param); TankWar.enemies.posBorn.push({x:block.left,y:block.top,avaliable:true});break;   
  57.             case 'l': block = new LawnBlock(param);break;   
  58.         }   
  59.         Interface.ensureImplements(block, Block);   
  60.     }   
  61. };  

3.tankwar.js 将页面切换、游戏初始化、事件绑定等封装为TankWarMng对象的方法。
4.tank.progress.js 图片及地图预加载。
Javascript代码  
  1. var PreLoad = (function() {   
  2.     // 私有静态方法   
  3.     function obj2array(givenObj) {   
  4.         var urllist = [], patrn = /1-\d{1,2}\.(png|json)$/, level = 0, levelArr = [];   
  5.         if (TankWar.mySite) levelArr[level++] = TankWar.mySite;   
  6.         (function(obj) { // 解析对象,将结果填进urllist数组   
  7.             for (var prop in obj) {   
  8.                 if (prop === 'urls') {   
  9.                     for (var i = 0, n = obj[prop].length; i < n; i++) {   
  10.                         if (patrn.test(obj[prop][i])) {   
  11.                             var tmp = obj[prop][i].split('.')[0].split('-'), suffix = patrn.exec(obj[prop][i])[1];   
  12.                             for (var j = tmp[0], m = tmp[1]; j <= m; j++) {   
  13.                                 urllist.push(levelArr.join('/') + '/' + j + '.' + suffix);   
  14.                             }   
  15.                         } else {   
  16.                             urllist.push(levelArr.join('/') + '/' + obj[prop][i]);   
  17.                         }   
  18.                     }   
  19.                     levelArr.splice(--level, 1);   
  20.                 } else {   
  21.                     levelArr[level++] = prop;   
  22.                     arguments.callee(obj[prop]);   
  23.                 }   
  24.             }   
  25.         })(givenObj);   
  26.         return urllist;   
  27.     };   
  28.     // 构造器   
  29.     return function(urlObj, callback) {   
  30.         this.callback = callback;   
  31.         if (!TankWar.mySite) { // 如果没有启动预加载,直接进入回调   
  32.             this.progressBar(100);   
  33.             return;   
  34.         }   
  35.         this.urlList = obj2array(urlObj);   
  36.         this.total = this.urlList.length;   
  37.         this.succeedcount = 0;   
  38.         this.errorcount = 0;   
  39.         this.init();   
  40.     }   
  41. })();   
  42.   
  43. PreLoad.prototype = {   
  44.     loadImg: function(url) {   
  45.         var img = new Image(), that = this;   
  46.         img.onload = function() {   
  47.             that.complete(url, '图片');   
  48.         }   
  49.         img.onerror = function() {   
  50.             that.error(url);   
  51.         }   
  52.         img.src = url;   
  53.     },   
  54.     loadMap: function(url) {   
  55.         var that = this;   
  56.         $.getJSON(url, function(map) {   
  57.             TankWar.maps.push(map);   
  58.             that.complete(url, '地图');   
  59.         });   
  60.     },   
  61.     complete: function(url, type) {   
  62.         this.progressBar(Math.round(++this.succeedcount*100/this.total), url, type);   
  63.     },   
  64.     error: function(url) {   
  65.         throw new Error('load '+ url +' failed.');   
  66.     },   
  67.     progressBar: function(percent, url, type) {   
  68.         if (url && type) {   
  69.             $('#percent span').text(percent);   
  70.             $('#loading span').text(type + ': ' + url.substr(url.lastIndexOf('/') + 1, url.length));   
  71.         }   
  72.         $('#bar').stop().animate({left: 550 - 550*percent/100}, 200);   
  73.         if (percent === 100) this.over();   
  74.     },   
  75.     over: function() {   
  76.         var that = this;   
  77.         setTimeout(function() {   
  78.             that.callback();   
  79.         }, 500);   
  80.     },   
  81.     init: function() {   
  82.         $('#percent, #loading').show();   
  83.         for (var i = 0; i < this.total; i++) {   
  84.             if (/\.json$/.test(this.urlList[i]))   
  85.                 this.loadMap(this.urlList[i]);   
  86.             else  
  87.                 this.loadImg(this.urlList[i]);   
  88.         }   
  89.     }   
  90. };  

5.util.js 接口、接口检查、继承等的实现。
6.tank.namespace.js & tank.config.js 命名空间及常用参数。
Javascript代码  
  1. var config = {};   
  2. config.my_site = ''// 如果将此游戏放在您网站上,请配置网址如:config.my_site = 'http://www.mysite.com/tank',将会自动启用预加载技术,以获得更好的游戏体验   
  3.   
  4. config.develop_model = 'product'// develop|test|product 如果是product,将不进行接口检查,以提高游戏速度   
  5.   
  6. 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}]; // 每一关的敌方坦克数量,目前有三关   
  7.   
  8. config.default_scene = 'lawn'// 默认场景   
  9.   
  10. // 游戏参数   
  11. config.player1_lives = 4;   
  12. config.player1_speed = 2;   
  13. config.player1_move_keys = { 37: 'left', 38: 'up', 39: 'right', 40: 'down'};   
  14. config.player1_fire_key = 32;   
  15.   
  16. config.player2_lives = 4;   
  17. config.player2_speed = 2;   
  18. config.player2_move_keys = { 65: 'left', 87: 'up', 68: 'right', 83: 'down'};   
  19. config.player2_fire_key = 71;   
  20.   
  21. config.enemy_red_speed = 1;   
  22. config.enemy_blue_speed = 1.5;   
  23. config.enemy_yellow_speed = 2;   
  24. config.enemy_green_speed = 2.5;   
  25. config.bullet_speed = 10;  

7.1-3.json 地图
Javascript代码  
  1. [{   
  2.     "type""b"// b为敌方坦克出生地,你可以添加/减少b的个数,调节敌方坦克数量   
  3.     "y": 10,   
  4.     "x": 9   
  5. }, {   
  6.     "type""b",   
  7.     "y": 9,   
  8.     "x": 332   
  9. }, {   
  10.     "type""b",   
  11.     "y": 9,   
  12.     "x": 653   
  13. },   
  14.   
  15. {   
  16.     "type""h"// 子弹打不破的石头   
  17.     "y": 172,   
  18.     "x": 10   
  19. },   
  20.   
  21. {   
  22.     "type""l"// 草地   
  23.     "y": 212,   
  24.     "x": 43   
  25. }, {   
  26.     "type""e"// 子弹两次可以打破的砖头   
  27.     "y": 212,   
  28.     "x": 79   
  29. }]  
更多精彩,请下载源码:http://jtankwar.googlecode.com/files/tank%20war%203.0.zip

游戏效果截图:

主页--游戏设置

游戏中..

暂停/退出

任务结束

此文供大家交流,共同学习,可以随便转载!
原文地址:https://www.cnblogs.com/luoyaoquan/p/2046158.html