目錄
HTML+JS+websocket 實例阻课,聯(lián)機“游戲王”對戰(zhàn) 1
HTML+JS+websocket 實例赖阻,聯(lián)機“游戲王”對戰(zhàn) 2 - 聯(lián)機模式
HTML+JS+websocket 實例,聯(lián)機“游戲王”對戰(zhàn) 3 - 界面布局
HTML+JS+websocket 實例艳丛,聯(lián)機“游戲王”對戰(zhàn) 4 - 卡組系統(tǒng)
HTML+JS+websocket 實例,聯(lián)機“游戲王”對戰(zhàn) 5 - 卡片選中系統(tǒng)
HTML+JS+websocket 實例趟紊,聯(lián)機“游戲王”對戰(zhàn) 6 - 卡片放置,戰(zhàn)場更新
HTML+JS+websocket 實例碰酝,聯(lián)機“游戲王”對戰(zhàn) 7 - 墓地霎匈,副控制面板
HTML+JS+websocket 實例,聯(lián)機“游戲王”對戰(zhàn) 8 - 返回手卡送爸,卡組
HTML+JS+websocket 實例铛嘱,聯(lián)機“游戲王”對戰(zhàn) 9 - 實現(xiàn)簡單 websocket 通信
HTML+JS+websocket 實例,聯(lián)機“游戲王”對戰(zhàn) 10 - 搭建游戲服務(wù)端
HTML+JS+websocket 實例袭厂,聯(lián)機“游戲王”對戰(zhàn) 11 - 客戶端消息的收發(fā)
HTML+JS+websocket 實例墨吓,聯(lián)機“游戲王”對戰(zhàn) 12 - 消息發(fā)送具體場景
HTML+JS+websocket 實例,聯(lián)機“游戲王”對戰(zhàn) 13 - 實機演示
這章開始我們結(jié)合 js 代碼看看游戲具體功能的實現(xiàn)纹磺。大致的規(guī)劃是先介紹貫穿整個游戲?qū)值幕A(chǔ)功能帖烘,之后再針對不同的功能按鍵和功能板塊來逐一介紹。函數(shù)中涉及聯(lián)機的功能會放在實現(xiàn)聯(lián)機的章節(jié)具體介紹橄杨。
卡組系統(tǒng)
首先來介紹下整個游戲存放素材的主體秘症,卡組的實現(xiàn)。
1.卡組結(jié)構(gòu):
游戲的卡組本質(zhì)上是一個簡單的字符串?dāng)?shù)組式矫,在游戲初始化時就加載存儲了每一張卡牌圖片的路徑(或者URL)乡摹。卡組在結(jié)構(gòu)上是一個堆棧采转,遵循后進先出(LIFO)的原則聪廉,即每次送入牌組的卡片默認(rèn)放在牌組的最上方,若不進行洗牌故慈,那么最后被放入的卡片將在最近的一次抽卡中率先被抽到板熊,就像槍械彈匣一樣。
堆棧有兩種基本操作惯悠,POP(出棧)與 PUSH(入棧)邻邮。抽卡時我們執(zhí)行 POP 操作,將卡組最上方的卡片從卡組中剔除克婶,發(fā)到玩家手牌筒严。當(dāng)碰到某些效果需將手牌或場上的卡片放回卡組最上方時我們則執(zhí)行 PUSH 操作丹泉,將指定的卡片壓入卡組的最上方。如需要放回卡組后再切洗鸭蛙,則在執(zhí)行完 PUSH 操作后再執(zhí)行洗牌函數(shù)即可摹恨。
當(dāng)然,有時候我們會需要從卡組中選取指定卡牌并拿出的效果娶视,這時候被指定的卡片需要從卡組中剔除晒哄,如果只是單純的 POP 操作我們就得一張一張的將卡片取出直到想要的卡片為止,非常麻煩肪获。JS中提供了一個 splice() 方法寝凌,它允許我們直接刪除或替換數(shù)組中的一個或多個元素,只需提供元素的索引值以及需刪除元素的個數(shù)孝赫。在這個方法里我們可提供指定卡牌在卡組中的序號较木,并且只刪除一個元素,即被選中的那張卡牌會被剔除卡組青柄。剔除后該位置不會留空伐债,而是被后面的其他卡向上填補,這意味著卡組中部分卡牌的索引也會發(fā)生變化致开,這個功能我們也會在以后詳細(xì)說到峰锁。
2.卡組的加載:
在游戲?qū)珠_始前雙方玩家需要加載各自的卡組。
首先要用到幾個全局變量:
P1DeckName 用于指示我們此次對局要加載哪一副卡組的卡組名稱双戳。一個卡組名稱實質(zhì)上代表一個卡組文件夾虹蒋,我們可以有多個卡組文件夾,自行填寫本次對局要用的那個:
var P1DeckName = "Deck_KaiMa"; //我方牌組名
P1DeckNum 用于指示卡組中的卡牌數(shù)量(暫時還未實現(xiàn)自動讀取文件夾中的所有文件拣技,實現(xiàn)了可以不用這個變量):
var P1DeckNum = 50; //我方牌組卡片數(shù)量
P1Deck 用于存儲卡組所有圖片url的字符串?dāng)?shù)組:
var P1Deck = []; //我方牌組(儲存我方所有卡片src)
之后通過循環(huán)的方法將卡組文件夾中的每一個圖片路徑給push到字符串?dāng)?shù)組中:
//儲存P1卡組所有卡片路徑
for (var i=0; i<P1DeckNum; i++) {
var cardsrc = "image/cards/" + P1DeckName + "/" + i + ".jpg"
P1Deck.push(cardsrc);
}
當(dāng)然在這之前我們已經(jīng)將卡組文件夾中所有卡牌的文件名改成了數(shù)字:
加載完成后還要再執(zhí)行一下洗牌操作千诬,不然每次順序都是固定的:
/*生成隨機數(shù) */
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
/*克隆數(shù)組 */
function cloneArr(arr) {
// 從第一個字符就開始 copy
// slice(start,end) 方法可從已有的數(shù)組中返回選定的元素。
return arr.slice(0);
}
/*數(shù)組洗牌 */
function shuffle(arr) {
let newArr = [];
newArr = arr;
for (let i = 0; i < newArr.length; i++) {
let j = getRandom(0, i);
let temp = newArr[i];
newArr[i] = newArr[j];
newArr[j] = temp;
}
return newArr;
}
P1Deck = shuffle(cloneArr(P1Deck)); //牌組洗牌
3.卡組抽卡的實現(xiàn):
從卡組抽卡是將卡組數(shù)組中的卡牌url傳到手牌卡槽當(dāng)中膏斤,實現(xiàn)這個js函數(shù)之前我們先回顧下html文件中的手牌區(qū)域內(nèi)容:
<div class="item">
<img id="p1-hand0" class="card" onmouseover="showCardInfo('hand', this.src, 0, 'player1')" onclick="selectCard(this.id, 'hand', this.src, 0, 'player1')" src="">
</div>
我方手卡區(qū)中有8個這樣的img標(biāo)簽徐绑,分別對應(yīng)8個手卡卡槽,每個標(biāo)簽有獨立的id莫辨,且src屬性默認(rèn)是留空的傲茄,其他屬性暫且不管。
每次執(zhí)行抽卡函數(shù)時沮榜,我們需要確定一個空的手牌卡槽并且獲取它的id盘榨,之后給它的src屬性賦上抽出卡片的圖片url,賦值后網(wǎng)頁里才會顯示卡牌的圖片蟆融。
為確保即將賦值的卡槽是空卡槽草巡,我們需要對每個卡槽的src值進行逐一判斷。由于src屬性留空后它的值并不是“”或者null型酥,而是默認(rèn)為所屬html文件存放的路徑山憨,所以我這里又設(shè)置了一個全局變量 emptysrc查乒,用于存放此默認(rèn)路徑,并在html文件加載完成后從任意一個空的img元素中獲取該路徑用于其他函數(shù)對于空卡槽的判定郁竟。
//獲取空的img src路徑玛迄,方便其他函數(shù)判斷卡槽是否為空
//window.onload 使函數(shù)在html完全加載后執(zhí)行
var emptysrc;
window.onload = function() {
var handID = 'p1-field0'; //選取任意卡槽id
element = document.getElementById(handID);
emptysrc = element.src;
P1Deck = shuffle(cloneArr(P1Deck)); //洗牌
}
注:此處局部變量 handID 命名有誤,這里我選的是一個戰(zhàn)場卡槽的 id 而非手卡卡槽棚亩,但是不影響函數(shù)的運行效果蓖议,空src的默認(rèn)值是相同的。
接下來實現(xiàn)抽卡函數(shù) drawCard () :
遍歷我方所有8個手卡卡槽:
獲取當(dāng)前卡槽id讥蟆;
通過卡槽id獲取當(dāng)前卡槽對象勒虾;
如果(卡槽對象是空卡槽):
對卡組數(shù)組P1Deck執(zhí)行POP操作,將卡組最上方的圖片url推出并賦值給卡槽對象的src屬性瘸彤;
立刻停止遍歷捌归;
/*抽取牌組最上方一張卡至手卡 */
function drawCard() {
for (var i=0; i<8; i++) {
var handID = 'p1-hand' + i.toString();
element = document.getElementById(handID);
if (element.src == emptysrc) { //如果該卡槽為空
element.src = P1Deck.pop();
/*觸發(fā)抽卡音效 */
var snd = new Audio("sound/draw.wav");
snd.play();
/**
* 告知對手哪張手卡卡槽添加了一張卡
*/
messageHand('add', i);
break;
}
}
}
注:代碼中關(guān)于聯(lián)機的函數(shù)將放到實現(xiàn)聯(lián)機的章節(jié)一起匯總介紹胆筒。
最后一步,觸發(fā) drawCard() 的條件是玩家點擊了游戲界面卡組區(qū)的那個代表卡組的卡背圖片实柠,我們找到html中對應(yīng)的那個元素:
<div class="item deck">
<img id="deck_r" class="card" src="image/cards/cardback.jpg" alt="cardback" onclick="drawCard()">
</div>
這也是一個img標(biāo)簽婆翔,src設(shè)置了卡片背面圖片的url拯杠,onclick屬性設(shè)置我們寫好的抽卡函數(shù)drawCard(),這樣在點擊這個卡背圖片時就會向手牌區(qū)的空卡槽添加一張卡片了啃奴。
其他功能后面的章節(jié)來繼續(xù)介紹潭陪。