软件工程--推箱子游戏

合作者:陈梅、周丹

 

 一、需求分析

   推箱子这个游戏是款古老的游戏,目的是在训练玩家的逻辑思维能力。在一个狭小的仓库里面,要求把几个木箱放在指定的位置,稍不小心就会出现箱子出现无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理的安排移动的次序和位置,才能顺利的完成任务。

 

二、分工

  周丹:游戏的设计与构思

     陈梅:代码的编写

 

三、游戏功能分析

  1、推箱子界面的设计(地图);

  2、关卡的设计;

  3、创建箱子;

  4、创建人物;

  5、操作人物的运动;

  3、碰撞检测;

 

四、编程语言

  html+css+javascript+jquery  网页游戏

 

五、游戏涉及的知识点

  1、JQ库的常见方法使用
  2、地图的设计思想  
  3、碰撞检测
  4、坐标系在布局中的实际应用
  5、键盘的事件操作
  6、如何判断箱子阻挡、如何判断是否过关
  7、设计通用的代码模式

 

六、步骤分析

  1、css模块

<style>
*{ margin:0; padding:0;}
#div1{ position:relative; margin:20px auto;}

.pos1{ width:50px; height:50px; background:#666; float:left;}
.pos2{ width:50px; height:50px; background:url(images/wall.png) no-repeat; float:left;}
.pos3{ width:50px; height:50px; background:red; float:left;}
.pos0{ width:50px; height:50px; background:blue; float:left;}

.box{ width:50px; height:50px; background:url(images/box.png) no-repeat; position:absolute;}
.person{ width:50px; height:50px; background:url(images/person.png) no-repeat; position:absolute;}


</style>

 

  2、关卡设计

gk : [   //关卡的数据
        {
            map : [
                1,1,2,2,2,2,1,1,
                1,1,2,3,3,2,1,1,
                1,2,2,0,3,2,2,1,
                1,2,0,0,0,3,2,1,
                2,2,0,0,0,0,2,2,
                2,0,0,2,0,0,0,2,
                2,0,0,0,0,0,0,2,
                2,2,2,2,2,2,2,2
            ],
            box : [
                {x:4,y:3},
                {x:3,y:4},
                {x:4,y:5},
                {x:5,y:5}
            ],
            person : {x:3,y:6}
        },
        {
            map : [
                1,1,1,1,2,2,2,2,2,2,2,1,
                1,1,1,1,2,0,0,2,0,0,2,1,
                1,1,1,1,2,0,0,0,0,0,2,1,
                2,2,2,2,2,0,0,2,0,0,2,1,
                3,3,3,2,2,2,0,2,0,0,2,2,
                3,0,0,2,0,0,0,0,2,0,0,2,
                3,0,0,0,0,0,0,0,0,0,0,2,
                3,0,0,2,0,0,0,0,2,0,0,2,
                3,3,3,2,2,2,0,2,0,0,2,2,
                2,2,2,2,2,0,0,0,0,0,2,1,
                1,1,1,1,2,0,0,2,0,0,2,1,
                1,1,1,1,2,2,2,2,2,2,2,1
            ],
            box : [
                {x : 5 , y : 6},
                {x : 6 , y : 3},
                {x : 6 , y : 5},
                {x : 6 , y : 7},
                {x : 6 , y : 9},
                {x : 7 , y : 2},
                {x : 8 , y : 2},
                {x : 9 , y : 6},
            ],
            person : { x : 5 , y : 9 }
        }
    ],

  

  3、创建地图

createMap : function(iNow){  //创建地图
    
        this.oParent.empty();
        
        document.title = '第'+(iNow+1)+'关';
    
        this.nowJson = this.gk[iNow];
        
        this.oParent.css('width',Math.sqrt(this.nowJson.map.length)*50);
        
        $.each( this.nowJson.map, $.proxy(function(i,elem){
            
            this.oParent.append('<div class="pos'+ elem +'"></div>');
            
        },this) );
        
        this.createBox();
        
        this.createPerson();
    
    },

 

  4、创建人物 

createPerson : function(){  //创建人物
        
        var oPerson = $('<div class="person"></div>');
        oPerson.css('left',this.nowJson.person.x*50);
        oPerson.css('top',this.nowJson.person.y*50);
        
        oPerson.data('x',this.nowJson.person.x);
        oPerson.data('y',this.nowJson.person.y);
        
        this.oParent.append( oPerson );
        
        this.bindPerson(oPerson);
        
    },

 

  

  5、创建箱子 

createBox : function(){  //创建箱子
        
        $.each(this.nowJson.box,$.proxy(function(i,elem){
            
            var oBox = $('<div class="box"></div>');
            oBox.css('left',elem.x*50);
            oBox.css('top',elem.y*50);
            this.oParent.append(oBox);
            
        },this));
        
    },

 

 

  

  6、键盘操作人物移动

bindPerson : function(oPerson){  //操作人物
    
        $(document).keydown($.proxy(function(ev){
            
            switch(ev.which){
                case 37:
                    oPerson.css('backgroundPosition','-150px 0');
                    this.movePerson(oPerson,{x:-1});
                    
                    
                break;
                case 38:
                    oPerson.css('backgroundPosition','0 0');
                    
                    this.movePerson(oPerson,{y:-1});
                    
                break;
                case 39:
                    oPerson.css('backgroundPosition','-50px 0');
                    
                    this.movePerson(oPerson,{x:1});
                    
                break;
                case 40:
                    oPerson.css('backgroundPosition','-100px 0');
                    this.movePerson(oPerson,{y:1});
                break;
            }
            
        },this));
    
    },

 

  

  7、人物移动 

movePerson : function(oPerson,opt){
        
        var xValue = opt.x || 0;
        var yValue = opt.y || 0;
        
        
        if( this.nowJson.map[ (oPerson.data('y') + yValue )*Math.sqrt(this.nowJson.map.length) + (oPerson.data('x') + xValue ) ] != 2 ){
            
            oPerson.data('x',oPerson.data('x') + xValue );
            oPerson.data('y',oPerson.data('y') + yValue );
            
            oPerson.css('left' , oPerson.data('x')*50 );
            oPerson.css('top' , oPerson.data('y')*50 );
            
            $('.box').each($.proxy(function(i,elem){
                
                if( this.pz( oPerson , $(elem) ) && this.nowJson.map[ (oPerson.data('y') + yValue )*Math.sqrt(this.nowJson.map.length) + (oPerson.data('x') + xValue ) ] != 2 ){
                    
                    $(elem).css('left' , (oPerson.data('x') + xValue)*50 );
                    $(elem).css('top' , (oPerson.data('y') + yValue)*50 );
                    
                    $('.box').each($.proxy(function(j,elem2){
                        
                        if( this.pz( $(elem) , $(elem2) ) && elem!=elem2 ){
                        
                        $(elem).css('left' , oPerson.data('x')*50 );
                        $(elem).css('top' , oPerson.data('y')*50 );
                        
                        oPerson.data('x',oPerson.data('x') - xValue );
                        oPerson.data('y',oPerson.data('y') - yValue );
                        
                        oPerson.css('left' , oPerson.data('x')*50 );
                        oPerson.css('top' , oPerson.data('y')*50 );    
                            
                        }
                        
                    },this));
                    
                    
                }
                else if( this.pz( oPerson , $(elem) ) ){
                    
                    oPerson.data('x',oPerson.data('x') - xValue );
                    oPerson.data('y',oPerson.data('y') - yValue );
                    
                    oPerson.css('left' , oPerson.data('x')*50 );
                    oPerson.css('top' , oPerson.data('y')*50 );
                    
                }
                
            },this));
            
        }
        
        this.nextShow();
        
    },

 

  

  8、碰撞检测

pz : function(obj1,obj2){  //碰撞检测
        var L1 = obj1.offset().left;
        var R1 = obj1.offset().left + obj1.width();
        var T1 = obj1.offset().top;
        var B1 = obj1.offset().top + obj1.height();
        
        var L2 = obj2.offset().left;
        var R2 = obj2.offset().left + obj2.width();
        var T2 = obj2.offset().top;
        var B2 = obj2.offset().top + obj2.height();
        
        if( R1<=L2 || L1>=R2 || T1>=B2 || B1<=T2 ){
            return false;
        }
        else{
            return true;
        }
        
    }

 

 

  9、下一关

nextShow : function(){  //下一关
        
        var iNum = 0;
        
        $('.box').each($.proxy(function(i,elem){
            
            $('.pos3').each($.proxy(function(j,elem2){
                
                if( this.pz( $(elem) , $(elem2) ) ){
                    iNum++;
                }
                
            },this));
            
        },this));
        
        if(iNum == this.nowJson.box.length){
            this.createMap(1);
        }
        
    },

 

 

七、完整代码

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style>
*{ margin:0; padding:0;}
#div1{ position:relative; margin:20px auto;}

.pos1{ width:50px; height:50px; background:#666; float:left;}
.pos2{ width:50px; height:50px; background:url(images/wall.png) no-repeat; float:left;}
.pos3{ width:50px; height:50px; background:red; float:left;}
.pos0{ width:50px; height:50px; background:blue; float:left;}

.box{ width:50px; height:50px; background:url(images/box.png) no-repeat; position:absolute;}
.person{ width:50px; height:50px; background:url(images/person.png) no-repeat; position:absolute;}


</style>
<script type="text/javascript" src="jquery-1.9.1.min.js"></script>
<script>

$(function(){
    
    Game.init( $('#div1') );
    
});

var Game = {
    
    gk : [   //关卡的数据
        {
            map : [
                1,1,2,2,2,2,1,1,
                1,1,2,3,3,2,1,1,
                1,2,2,0,3,2,2,1,
                1,2,0,0,0,3,2,1,
                2,2,0,0,0,0,2,2,
                2,0,0,2,0,0,0,2,
                2,0,0,0,0,0,0,2,
                2,2,2,2,2,2,2,2
            ],
            box : [
                {x:4,y:3},
                {x:3,y:4},
                {x:4,y:5},
                {x:5,y:5}
            ],
            person : {x:3,y:6}
        },
        {
            map : [
                1,1,1,1,2,2,2,2,2,2,2,1,
                1,1,1,1,2,0,0,2,0,0,2,1,
                1,1,1,1,2,0,0,0,0,0,2,1,
                2,2,2,2,2,0,0,2,0,0,2,1,
                3,3,3,2,2,2,0,2,0,0,2,2,
                3,0,0,2,0,0,0,0,2,0,0,2,
                3,0,0,0,0,0,0,0,0,0,0,2,
                3,0,0,2,0,0,0,0,2,0,0,2,
                3,3,3,2,2,2,0,2,0,0,2,2,
                2,2,2,2,2,0,0,0,0,0,2,1,
                1,1,1,1,2,0,0,2,0,0,2,1,
                1,1,1,1,2,2,2,2,2,2,2,1
            ],
            box : [
                {x : 5 , y : 6},
                {x : 6 , y : 3},
                {x : 6 , y : 5},
                {x : 6 , y : 7},
                {x : 6 , y : 9},
                {x : 7 , y : 2},
                {x : 8 , y : 2},
                {x : 9 , y : 6},
            ],
            person : { x : 5 , y : 9 }
        }
    ],
    
    init : function(oParent){  //初始化
    
        this.oParent = oParent;
        
        this.createMap(0);
    
    },
    createMap : function(iNow){  //创建地图
    
        this.oParent.empty();
        
        document.title = ''+(iNow+1)+'';
    
        this.nowJson = this.gk[iNow];
        
        this.oParent.css('width',Math.sqrt(this.nowJson.map.length)*50);
        
        $.each( this.nowJson.map, $.proxy(function(i,elem){
            
            this.oParent.append('<div class="pos'+ elem +'"></div>');
            
        },this) );
        
        this.createBox();
        
        this.createPerson();
    
    },
    createBox : function(){  //创建箱子
        
        $.each(this.nowJson.box,$.proxy(function(i,elem){
            
            var oBox = $('<div class="box"></div>');
            oBox.css('left',elem.x*50);
            oBox.css('top',elem.y*50);
            this.oParent.append(oBox);
            
        },this));
        
    },
    createPerson : function(){  //创建人物
        
        var oPerson = $('<div class="person"></div>');
        oPerson.css('left',this.nowJson.person.x*50);
        oPerson.css('top',this.nowJson.person.y*50);
        
        oPerson.data('x',this.nowJson.person.x);
        oPerson.data('y',this.nowJson.person.y);
        
        this.oParent.append( oPerson );
        
        this.bindPerson(oPerson);
        
    },
    bindPerson : function(oPerson){  //操作人物
    
        $(document).keydown($.proxy(function(ev){
            
            switch(ev.which){
                case 37:
                    oPerson.css('backgroundPosition','-150px 0');
                    this.movePerson(oPerson,{x:-1});
                    
                    
                break;
                case 38:
                    oPerson.css('backgroundPosition','0 0');
                    
                    this.movePerson(oPerson,{y:-1});
                    
                break;
                case 39:
                    oPerson.css('backgroundPosition','-50px 0');
                    
                    this.movePerson(oPerson,{x:1});
                    
                break;
                case 40:
                    oPerson.css('backgroundPosition','-100px 0');
                    this.movePerson(oPerson,{y:1});
                break;
            }
            
        },this));
    
    },
    movePerson : function(oPerson,opt){
        
        var xValue = opt.x || 0;
        var yValue = opt.y || 0;
        
        
        if( this.nowJson.map[ (oPerson.data('y') + yValue )*Math.sqrt(this.nowJson.map.length) + (oPerson.data('x') + xValue ) ] != 2 ){
            
            oPerson.data('x',oPerson.data('x') + xValue );
            oPerson.data('y',oPerson.data('y') + yValue );
            
            oPerson.css('left' , oPerson.data('x')*50 );
            oPerson.css('top' , oPerson.data('y')*50 );
            
            $('.box').each($.proxy(function(i,elem){
                
                if( this.pz( oPerson , $(elem) ) && this.nowJson.map[ (oPerson.data('y') + yValue )*Math.sqrt(this.nowJson.map.length) + (oPerson.data('x') + xValue ) ] != 2 ){
                    
                    $(elem).css('left' , (oPerson.data('x') + xValue)*50 );
                    $(elem).css('top' , (oPerson.data('y') + yValue)*50 );
                    
                    $('.box').each($.proxy(function(j,elem2){
                        
                        if( this.pz( $(elem) , $(elem2) ) && elem!=elem2 ){
                        
                        $(elem).css('left' , oPerson.data('x')*50 );
                        $(elem).css('top' , oPerson.data('y')*50 );
                        
                        oPerson.data('x',oPerson.data('x') - xValue );
                        oPerson.data('y',oPerson.data('y') - yValue );
                        
                        oPerson.css('left' , oPerson.data('x')*50 );
                        oPerson.css('top' , oPerson.data('y')*50 );    
                            
                        }
                        
                    },this));
                    
                    
                }
                else if( this.pz( oPerson , $(elem) ) ){
                    
                    oPerson.data('x',oPerson.data('x') - xValue );
                    oPerson.data('y',oPerson.data('y') - yValue );
                    
                    oPerson.css('left' , oPerson.data('x')*50 );
                    oPerson.css('top' , oPerson.data('y')*50 );
                    
                }
                
            },this));
            
        }
        
        this.nextShow();
        
    },
    nextShow : function(){  //下一关
        
        var iNum = 0;
        
        $('.box').each($.proxy(function(i,elem){
            
            $('.pos3').each($.proxy(function(j,elem2){
                
                if( this.pz( $(elem) , $(elem2) ) ){
                    iNum++;
                }
                
            },this));
            
        },this));
        
        if(iNum == this.nowJson.box.length){
            this.createMap(1);
        }
        
    },
    pz : function(obj1,obj2){  //碰撞检测
        var L1 = obj1.offset().left;
        var R1 = obj1.offset().left + obj1.width();
        var T1 = obj1.offset().top;
        var B1 = obj1.offset().top + obj1.height();
        
        var L2 = obj2.offset().left;
        var R2 = obj2.offset().left + obj2.width();
        var T2 = obj2.offset().top;
        var B2 = obj2.offset().top + obj2.height();
        
        if( R1<=L2 || L1>=R2 || T1>=B2 || B1<=T2 ){
            return false;
        }
        else{
            return true;
        }
        
    }
};

</script>
</head>

<body>
<div id="div1"></div>
</body>
</html>

 

 

 

 

八、游戏结果

 

   1、第一关

  

 

 

2、第二关

  

九、游戏总结

  1、javascript通过单体的形式来组织代码更加的形象,方便全局的应用。

  2、设计游戏重要的不是怎么写,重要的是思路是否清晰、需求分解过后,条理是否分明、代码组织方式是否利于维护、解决问题的方式是否通用稳妥。

  3、地图的设计思想,通过坐标的思想。

  4、键盘的事件来操作物体的运动。

  5、如何判断箱子的阻挡(碰撞检测)、判断过关。

  6、代码面向对象的思想。

 

十、不足之处

  1、关卡设计的不够随机,每一关都是同一个位置的箱子。

  2、由于时间比较急、只设计了2个关卡,关卡数量比较少。

  3、界面没有美工设计,页面比较丑。

 

posted @ 2014-11-20 09:05  嫣然玉茗  阅读(611)  评论(0)    收藏  举报