今日目標,即時顯示自己的手牌、別人的手牌數。
前面有提過手牌會透過 WebSocket 的單播來發給各個玩家,其他人的手牌數則透過對該房間的所有玩家群播來實現。
自己的手牌,我們讓 Client 訂閱 /my-hands
;其他人的手牌數,則讓 Client 訂閱 /hands-info
。
getHandsByPlayerName()
用於取得指定玩家的手牌、sendHandsInfo()
用於發送各玩家手牌數,加入的片段程式碼為:
public ArrayList<Card> getHandsByPlayerName(String name) {
return gameStatus.getHandsByPlayerName(name);
}
public void sendHandsInfo(String roomId) {
Player[] players = this.gameStatus.getPlayers(roomId);
Map<String, Integer> handsNumber = new HashMap<>();
for (Player player : players) {
handsNumber.put(player.getName(), player.countHands());
}
this.roomService.sendMessageToRoom(roomId, "/queue/hands-info", handsNumber);
}
getMyHands()
取得自己的手牌、getHandsInfo()
取得其他人的手牌數,完整內容為:
package com.example.game;
import com.example.card.Card;
import com.example.room.UserStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import java.security.Principal;
import java.util.ArrayList;
@Controller
public class GameWsController {
@Autowired
private UserStatus userStatus;
@Autowired
private GameService gameService;
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hands-info")
public void getHandsInfo(Principal principal) {
String name = principal.getName();
String roomId = userStatus.getUserRoomId(name);
this.gameService.sendHandsInfo(roomId);
}
@MessageMapping("/my-hands")
public void getMyHands(Principal principal) {
String name = principal.getName();
ArrayList<Card> myHands = gameService.getHandsByPlayerName(name);
simpMessagingTemplate.convertAndSendToUser(name, "/queue/my-hands", myHands);
}
}
再來,我們要藉由發送過來的訊息將手牌顯示出來,並根據其他人的手牌數顯示同等數量的牌。
game.js
,加入 WebSocket 連線方式以及相關方法 subscribeMyHands()
,但我們先不撰寫函數怎麼運行,我們先單純把資料印出來,完整內容為:
var websocket = new WebSocket();
var myUsername = $("#my-username").val();
$(document).ready(() => {
websocket.connect('/connect', () => {
subscribeMyHands();
websocket.send("/my-hands", {});
});
relocatePlayedCards();
})
function subscribeMyHands() {
websocket.subscribe("/user/queue/my-hands", (response) => {
response = JSON.parse(response.body);
console.log(response); // 注意這邊的輸出
});
}
function relocateMyHands() {
let newLocationX = ($(".game-window").width() - $(".my-hands").width()) / 2;
$(".my-hands").css("left", newLocationX);
}
function relocatePlayedCards() {
let newLocationX = ($(".game-window").width() - $(".card-type").width()) / 2;
$(".card-type").css("left", newLocationX);
}
const SUITS = {
SPADE : "♠️",
HEART : "♥",
DIAMOND : "♦",
CLUB : "♣",
};
const NUMBERS = {
ACE : "1",
TWO : "2",
THREE : "3",
FOUR : "4",
FIVE : "5",
SIX : "6",
SEVEN : "7",
EIGHT : "8",
NINE : "9",
TEN : "10",
JACK : "J",
QUEEN : "Q",
KING : "K",
};
function convertCard(card) {
return `${SUITS[card.suit]}-${NUMBERS[card.number]}`;
}
var websocket = new WebSocket();
var myUsername = $("#my-username").val();
$(document).ready(() => {
websocket.connect('/connect', () => {
subscribeMyHands();
websocket.send("/my-hands", {});
});
relocateMyHands();
relocatePlayedCards();
})
const SUITS = {
SPADE : "♠️",
HEART : "♥",
DIAMOND : "♦",
CLUB : "♣",
};
const NUMBERS = {
ACE : "1",
TWO : "2",
THREE : "3",
FOUR : "4",
FIVE : "5",
SIX : "6",
SEVEN : "7",
EIGHT : "8",
NINE : "9",
TEN : "10",
JACK : "J",
QUEEN : "Q",
KING : "K",
};
function subscribeMyHands() {
websocket.subscribe("/user/queue/my-hands", (response) => {
response = JSON.parse(response.body);
let myHands = [];
for (let card of response) {
myHands.push(convertCard(card));
}
generateMyHands(myHands);
});
}
function generateMyHands(myHands) {
$(".my-hands").empty();
let index = 0;
for (let cards of myHands) {
let tmp = cards.split("-");
let color = (tmp[0] == SUITS.SPADE || tmp[0] == SUITS.CLUB) ? "#000000" : "#FF0000";
$(".my-hands").append(`
<div class="m-card text-center" style="color: ${color}" id="card-${tmp[0]}-${tmp[1]}" tabindex="${index++}">
<div>
${tmp[0]}
<br>
${tmp[1]}
</div>
</div>
`);
}
relocateMyHands();
}
function convertCard(card) {
return `${SUITS[card.suit]}-${NUMBERS[card.number]}`;
}
function relocateMyHands() {
let newLocationX = ($(".game-window").width() - $(".my-hands").width()) / 2;
$(".my-hands").css("left", newLocationX);
}
function relocatePlayedCards() {
let newLocationX = ($(".game-window").width() - $(".card-type").width()) / 2;
$(".card-type").css("left", newLocationX);
}
subscribeHandsInfo()
、generateOtherHands()
,修改後的完整內容為:
var websocket = new WebSocket();
var myUsername = $("#my-username").val();
var selectedCards = new Set();
$(document).ready(() => {
websocket.connect('/connect', () => {
subscribeMyHands();
subscribeHandsInfo();
websocket.send("/my-hands", {});
websocket.send("/hands-info", {});
});
relocatePlayedCards();
})
const SUITS = {
SPADE : "♠️",
HEART : "♥",
DIAMOND : "♦",
CLUB : "♣",
};
const NUMBERS = {
ACE : "1",
TWO : "2",
THREE : "3",
FOUR : "4",
FIVE : "5",
SIX : "6",
SEVEN : "7",
EIGHT : "8",
NINE : "9",
TEN : "10",
JACK : "J",
QUEEN : "Q",
KING : "K",
};
function subscribeMyHands() {
websocket.subscribe("/user/queue/my-hands", (response) => {
response = JSON.parse(response.body);
let myHands = [];
for (let card of response) {
myHands.push(convertCard(card));
}
generateMyHands(myHands);
});
}
function subscribeHandsInfo() {
websocket.subscribe("/user/queue/hands-info", (response) => {
response = JSON.parse(response.body);
let allUsers = Object.keys(response);
let index = 0;
let userIndex = 1;
let count = 1;
while (count < 4) {
if (allUsers[index] === myUsername) {
userIndex = 2;
}
if (userIndex > 1) {
generateOtherHands(userIndex, response[allUsers[index]]);
userIndex++;
count++;
}
index = (index + 1) % 4;
}
})
}
function generateMyHands(myHands) {
$(".my-hands").empty();
let index = 0;
for (let cards of myHands) {
let tmp = cards.split("-");
let color = (tmp[0] == SUITS.SPADE || tmp[0] == SUITS.CLUB) ? "#000000" : "#FF0000";
$(".my-hands").append(`
<div class="m-card text-center" style="color: ${color}" id="card-${tmp[0]}-${tmp[1]}" tabindex="${index++}">
<div>
${tmp[0]}
<br>
${tmp[1]}
</div>
</div>
`);
}
relocateMyHands();
}
function generateOtherHands(who, numbers) {
$(`#user-${who}`).empty();
for (let i=0; i<numbers; i++) {
$(`#user-${who}`).append(`
<div class="m-card text-center"></div>
`);
}
}
function convertCard(card) {
return `${SUITS[card.suit]}-${NUMBERS[card.number]}`;
}
function relocateMyHands() {
let newLocationX = ($(".game-window").width() - $(".my-hands").width()) / 2;
$(".my-hands").css("left", newLocationX);
}
function relocatePlayedCards() {
let newLocationX = ($(".game-window").width() - $(".card-type").width()) / 2;
$(".card-type").css("left", newLocationX);
}
GENERAL_LEVEL
、compareByGeneral()
,修改 subscribeMyHands()
:
// 新增 - 取得他們之間的比較關係
const GENERAL_LEVEL = {
SPADE : 4,
HEART : 3,
DIAMOND : 2,
CLUB : 1,
ACE : 1,
TWO : 2,
THREE : 3,
FOUR : 4,
FIVE : 5,
SIX : 6,
SEVEN : 7,
EIGHT : 8,
NINE : 9,
TEN : 10,
JACK : 11,
QUEEN : 12,
KING : 13,
};
// 修改 - 多一個延遲執行,先讓使用者看一下之後再做排序
function subscribeMyHands() {
websocket.subscribe("/user/queue/my-hands", (response) => {
response = JSON.parse(response.body);
let myHands = [];
for (let card of response) {
myHands.push(convertCard(card));
}
generateMyHands(myHands);
// 多了這邊~~
setTimeout(() => {
let sortedHands = response.sort(compareByGeneral);
generateMyHands(sortedHands.map((card) => convertCard(card)));
}, 1000);
});
}
// 新增 - 比較兩個牌
function compareByGeneral(a, b) {
if (GENERAL_LEVEL[a.suit] > GENERAL_LEVEL[b.suit]) {
return -1;
}
else if (GENERAL_LEVEL[a.suit] < GENERAL_LEVEL[b.suit]) {
return 1;
}
else {
return GENERAL_LEVEL[a.number] - GENERAL_LEVEL[b.number];
}
}
老樣子,我們再去開 4 個帳號之後開始遊戲看看吧,應該會看到自己的牌產生,並重新排列了!