一起來做webgame,《Javascript蜘蛛紙牌》


不得不說,做游戲是會上癮的,這次帶來的是win系統上的經典游戲《蜘蛛紙牌》,不能完美,但求一玩

DEMO:

http://colorgamer.com/demo/webgame/spider/

關於蜘蛛紙牌

規則請打開win系統的蜘蛛紙牌,然后點擊幫助

這里要實現的

  • 同樣是兩副牌,一共104張
  • 同一種花色的低難度游戲

需要解決的問題

  • 1、洗牌
  • 2、判斷點擊牌所在序列是否符合可移動條件
  • 3、判斷目標位置是否符合可移動條件
  • 4、移動符合條件的紙牌序列到目標位置
  • 5、完成一個完整序列時的清除
  • 6、發牌

綜合起來,《蜘蛛紙牌》基本上就這么6個問題,解決了,也就完成了。下面一個一個來實現

1、洗牌

光洗牌,不難。如果要做到每次洗牌都有解就不是我能解決的問題了(win系統里的蜘蛛紙牌是不是每次都有解,我確實不知道)。這里就隨便洗洗,沒解也沒辦法,即使有解,你也不一定能解完,是吧。

這里是同色,所以不用去考慮4個花色,那一副牌,從A-K,是13張,有4組,就是13*4=52張牌。兩副就是104張。先初始化一組牌

var _cards_init=['1','2','3','4','5','6','7','8','9','10','J','Q','K'];

 

跟着把它變成1副牌

_cards_init=_cards_init.concat(_cards_init,_cards_init,_cards_init);  //使用concat來鏈接數組

 

這里自己鏈接自己3次,就變成了4組,一副牌。再接着鏈接自己一次,就變成兩副牌

_cards_init=_cards_init.concat(_cards_init);

 

兩副牌有了,接着就洗牌,這里簡單的使用隨機數來洗。

//洗牌
function shuffle(){
    var len=_cards_init.length;
    if(len>0){
        var i=random(len);
        _cards.push(_cards_init[i]);
        _cards_init.splice(i,1);
        shuffle();
    }
}

 

這是一個遞歸,每次從初始化的剩余牌序列里隨機取一個,放到新牌的數組里,然后將取走的牌從初始化的數組里移除,重計長度,只要長度不小於1,那么重復這個操作,至到全部取完為止。這樣生成的新牌數組里的牌基本上就是亂序了,達到洗牌的效果。

牌洗好之后,就得將最開始的牌面放到界面上。win7的蜘蛛紙牌是10列,前4列5張扣牌,1張明牌,后6列4張扣牌,1張明牌。這里也按這樣的方式開始。

因為是按列為基礎進行擺牌,所以程序在確定牌所在位置的時候,需要分別記錄,每一列等於是一個序列,有牌移進來,要增加它的長度,有牌移走的時候,要減少它的長度。所以這里使用了一個數組來分別記錄牌的信息

var _cards_table=new Array();

 

接着確定位置,按照初始化的界面,一共要放54張牌到牌面上,其中44張是扣牌,10張是明牌,所以,先從新牌數組里取54張牌出來,其中前10張,也就是0-9,是個位數,直接將下標做了牌的參數

for(var i=0;i<10;i++){
    _cards_table[i]=new Array();
}
var _html_cards_table='';

for(var i=0;i<54;i++){
    if(i<=9){
        j=i;
        _html_cards_table+="<div class='cardbg cardbg"+j+"' action-t='' action-line='"+j+"'></div>";
    }else{
        var s=i.toString();
        j=s.substring(s.length-1);
    }
    j=parseInt(j);
    var num=cardNum(_cards[i]);
    var back='';
    //背面牌
    if(i>=0&&i<44){
        back='back';
    }
    var l=_cards_table[j].length;
    _html_cards_table+="<div class='card cardv"+num+" card"+j+" "+back+"' action-t='"+back+"' action-line='"+j+"' action-index='"+l+"' style='z-index:1;position:absolute;left:"+_cardsPostion[0]+"px;top:"+_cardsPostion[1]+"px;'>"+_cards[i]+"</div>";
    _cards_table[j].push(num);
}

 

其實,這里固定牌的位置,直接使用了CSS樣式,不太好,因為有時候你不知道到底一列會出現多少個紙牌,要是CSS樣式寫少了,那多出來的紙牌放的位置就會出現問題。最好的辦法是JS直接判斷索引值,根據索引值*固定數來確定位置。

這些牌放出去后,自然得將它們從新牌的數組里移除,以后發牌,就是數組里剩下的牌了

_cards.splice(0,54);
_cards_table+='<div id="post">發牌<span id="postnum">5</span></div>';  //順便添加一個發牌的按鈕
$("#game_map").html(_cards_table);  //將生成的牌放到游戲地圖上

 

這里除了這些初始牌面外,還有一個東西,那就是隱藏的一個牌,因為每列的牌都有可能完全的移出,這時候符合條件的牌序列又可以移到這個空列里來,所以,得在那個位置放一個看不見的牌,但這個牌只有列號,沒有其它的東西。

if(i<=9){
    j=i;
    _cards_table+="<div class='cardbg cardbg"+j+"' action-t='' action-line='"+j+"'></div>";
}

 

2、判斷點擊牌所在序列是否符合可移動條件。3、判斷目標位置是否符合可移動條件

首先,得為各牌添加單擊事件。然后第一次點的牌要記錄下它的3個東西:1、所在列。2、列上的索引值。3、牌面值(A-K)。再次點擊其它牌的時候,進行判斷,它是不是符合移動條件,如:被點擊牌及之后的牌序列是不是符合條件(遞減),目標牌是不是比第一次點擊牌大1,如果是,移動牌到新位置,如果不是,給出提示,不符合條件

function clickCard(){
    $(".card").unbind('click').click(function(){
        var line=$(this).attr('action-line');
        var back=$(this).attr('action-t');
        if(back){
            return false;
        }
        var index=parseInt($(this).attr('action-index'));
        var cards_num;
        line=parseInt(line);
        cards_num=_cards_table[line][index];
        if(_cards_selected.length==1){
            if((cards_num-1)==_cards_selected[0][2]){
                var _index=index+1;
                moveCard(line,_index,_cards_selected[0][2]);
            }else{
                alert('不能移動到那個位置2_'+cards_num+'_'+_cards_selected[0][2]);
            }
            css_remove();
            _cards_selected.shift();
            clickCard();
        }else{
            if(getCards(line,index)==0){
                _cards_selected[0]=[];
                _cards_selected[0][0]=line;
                _cards_selected[0][1]=index;
                _cards_selected[0][2]=cards_num;
            }else{
                css_remove();
            }
        }
    });
}

 

4、移動符合條件的紙牌序列到目標位置

移走了,也就得把它從該列的數組里清除掉,這里使用splice(),只需要傳入起始索引值,將它和它之后的所有牌都清除。然后創建新的牌加入到目標列的數組里

function moveCard(line,index,cards_num){
    line=parseInt(line);
    var len=_cards_table[_cards_selected[0][0]].length;
    _cards_table[_cards_selected[0][0]].splice(_cards_selected[0][1],len);
    var html='';
    var moveCardIndex=index;
    _moveCardNum=len-_cards_selected[0][1];
    for(var i=_cards_selected[0][1];i<len;i++){
        var v=$(".card"+_cards_selected[0][0]).eq(_cards_selected[0][1]).html();
        var o=$(".card"+_cards_selected[0][0]).eq(_cards_selected[0][1]);
        var num=cardNum(o.html());
        _cards_table[line].push(num);
        var cardline=o.attr('action-line');
        o.removeClass('card'+cardline);
        o.addClass('card'+line);
        o.attr('action-line',line);
        o.attr('action-index',moveCardIndex);
        move_animation(o,line,moveCardIndex,1);
        moveCardIndex++;
    }
    $(".card"+_cards_selected[0][0]).eq(_cards_selected[0][1]-1).removeClass('back');
    $(".card"+_cards_selected[0][0]).eq(_cards_selected[0][1]-1).attr('action-t','');
    $("#scores").html(parseInt($("#scores").html())+1);
    
}

 

checkComplate(line);用於判斷是否已經實現A-K,如果是將它清除

5、完成一個完整序列時的清除

首先判斷該列的紙牌數是否超過13張,因為如果連13張都沒有,又怎么會有完整的A-K呢。之后再判斷明牌是不是有13張,而且明顯的大小是不是從大到小減1的。如果都符合,那將它們全部清除,並從該列的數組里將它們清除。

function checkComplate(line){
    var obj=$(".card"+line)
    var len=obj.length;
    var preNum=0;
    var error=0;
    var comNum=[];
    if(len>=13){
        for(var i=0;i<len;i++){
            if(obj.eq(i).attr('action-t')==''){
                if(preNum>0){
                    if(parseInt(cardNum(obj.eq(i).html()))+1==preNum){
                    }else{
                        comNum=[];
                    }
                    comNum.push(i);
                }else{
                    comNum.push(i);
                }
                preNum=parseInt(cardNum(obj.eq(i).html()));
            }
        }
        if(comNum.length>=13){
            for(var i in comNum){
                obj.eq(comNum[i]).remove();
                if(i==0){
                    obj.eq(comNum[i]-1).removeClass('back');
                    obj.eq(comNum[i]-1).attr('action-t','');
                    var len=_cards_table[line].length;
                    _cards_table[line].splice(comNum[i],len);
                }
            }
            _left_group--;
            if(_left_group==0){
                alert('你贏了,共移動'+$('#scores').html()+'次');
                $("#re").click();
            }
        }
    }
}

 

6、發牌

發牌其實和初始化牌面沒什么區別,只是每次只發10張,也就是向0-9列分別增加一張牌,發出去后,剩於牌就減去這些牌

function post(){
    $("#post").click(function(){
        if(_cards.length<=0){
            alert('無牌可發了');
            return false;
        }
        var _html_cards_table='';
        for(var i=0;i<10;i++){;
            var num=cardNum(_cards[i]);
            var l=_cards_table[i].length;
            _html_cards_table+="<div class='card cardv"+num+" card"+i+"' action-t='' action-index='"+l+"' action-line='"+i+"' style='z-index:1;position:absolute;left:"+_cardsPostion[0]+"px;top:"+_cardsPostion[1]+"px;'>"+_cards[i]+"</div>";
            _cards_table[i].push(num);
        }
        _cards.splice(0,10);
        var cardbenum=$(".card").length;
        $("#game_map").append(_html_cards_table);
        var _i=cardbenum;
        var _this=this;
        this.move_animation=function(){
            var line=$(".card").eq(_i).attr('action-line');
            var index=$(".card").eq(_i).attr('action-index');
            move_animation($(".card").eq(_i),line,index);
            _i++;
            if(_i<cardbenum+10){
                setTimeout(_this.move_animation,100);
            }
        }
        this.move_animation();
        $("#postnum").html(parseInt($("#postnum").html())-1);
        clickCard();
    });
}

 

以上6點,就是《蜘蛛紙牌》的基本內容,代碼里還有一些方法,是為了增加一些方便,比如返回J-K的值等等,這里就不說了。直接編輯源代碼,還是很累的。

里面還有關於動畫的內容,暫時就不講了,全部代碼也不帖了,可以查看試玩頁面的源文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM