使用websocket實現“你畫我猜”
阿新 • • 發佈:2019-02-01
1,環境配置(nodejs)
檔案結構:
package.json:
{ "name": "websocket", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "node-websocket-server": "^1.1.4", "ws": "^6.1.0" } }
2,伺服器配置 (server.js)
//配置一些變量表達遊戲狀態 var LINE_SEGMENT = 0; var CHAT_MESSAGE = 1; var GAME_LOGIC = 2; var WAITING_TO_START = 0; var GAME_START = 1; var GAME_OVER = 2; var GAME_RESTART = 3; var playerTurn = 0; //配置遊戲中使用的關鍵詞 var wordsList = ["apple","pear","angry","happy","boat","desk"]; var currentGameState = WAITING_TO_START; var gameOverTimeout; //建立websocket連線 var WebSocketServer = require('ws').Server; var wss = new WebSocketServer({ port: 8181 }); //定義廣播函式 wss.broadcast = function broadcast(message) { wss.clients.forEach(function each(client) { client.send(message); }); }; //建立連線時向客戶端傳送一條msg wss.on('connection', function (ws) { var msg = "Welcome to join the party! Total connection: " + wss.clients.size; //定義傳送資料的型別,並廣播 var data = {}; data.dataType = CHAT_MESSAGE; data.name = "Server"; data.message = msg; wss.broadcast(JSON.stringify(data)); //定義控制遊戲邏輯的資料型別,並廣播 var gameLogicData = {}; gameLogicData.dataType = GAME_LOGIC; gameLogicData.gameState = WAITING_TO_START; wss.broadcast(JSON.stringify(gameLogicData)); //開始遊戲的條件 if(currentGameState == WAITING_TO_START && wss.clients.size >=2){ startGame(); } //廣播接收到的客戶端發來的訊息,並廣播 ws.on('message', function (message) { var obj = eval('(' + message + ')'); wss.broadcast(JSON.stringify(obj)); //如果判斷收到的訊息是聊天訊息 if(obj.dataType == CHAT_MESSAGE){ //如果接收到的訊息是正確答案,廣播並改變當前遊戲狀態 if(currentGameState == GAME_START && obj.message == currentAnswer){ var gameLogicData = {}; gameLogicData.dataType = GAME_LOGIC; gameLogicData.gameState = GAME_OVER; gameLogicData.winner = obj.name; gameLogicData.answer = currentAnswer; wss.broadcast(JSON.stringify(gameLogicData)); currentGameState = WAITING_TO_START; clearTimeout(gameOverTimeout); } }else if(obj.dataType == GAME_LOGIC && obj.gameState == GAME_RESTART){ startGame(); } }); }); //開始遊戲函式,初始化答案,控制開始的使用者是誰 function startGame(){ playerTurn = (playerTurn +1) % wss.clients.size; var answerIndex = Math.floor(Math.random()* wordsList.length); currentAnswer = wordsList[answerIndex]; var gameLogicData1 = {}; gameLogicData1.dataType = GAME_LOGIC; gameLogicData1.gameState = GAME_START; gameLogicData1.isPlayerTurn = false; wss.broadcast(JSON.stringify(gameLogicData1)); var index = 0; wss.clients.forEach(function each(client) { if(index == playerTurn){ var gameLogicData2 = {}; gameLogicData2.dataType = GAME_LOGIC; gameLogicData2.gameState = GAME_START; gameLogicData2.answer = currentAnswer; gameLogicData2.isPlayerTurn = true; wss.broadcast(JSON.stringify(gameLogicData2)); } index ++; }); gameOverTimeout = setTimeout(function(){ var gameLogicData = {}; gameLogicData.dataType = GAME_LOGIC; gameLogicData.gameState = GAME_OVER; gameLogicData.winner = 'no-one'; gameLogicData.answer = currentAnswer; wss.broadcast(JSON.stringify(gameLogicData)); currentGameState = WAITING_TO_START; },60*1000); currentGameState = GAME_START; } console.log("Websocket server is running");
3,客戶端配置(client.html)
建立一個websocket連線到伺服器
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>WebSocket Echo Demo</title> <meta name="viewport" content="width=device-width, initial-scale=1"/> <link href="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.min.js"></script> <link rel="stylesheet" type="text/css" href="index.css"> </head> <body > <div id="game"> <h1>你畫我猜</h1> <canvas id="drawing-pad" width="450" height="320"></canvas> <div class="vertical-center"> <ul id="chat-history"></ul> <div class="container"> <form role="form" id="chat_form" onsubmit="sendMessage(); return false;"> <div class="form-group"> 輸入:<input class="form-control" type="text" name="message" id="message" value="" /> <button type="button" id="send" class="btn btn-primary" onclick="sendMessage();"> Send </button> <button type="button" id="restart" class="btn btn-primary"> restart </button> </div> </form> </div> </div> </div> <script type="text/javascript" src="index.js"></script> <script> //啟動一個websocket,並連線到伺服器 var ws = new WebSocket("ws://localhost:8181"); ws.onopen = function (e) { console.log('Connection to server opened'); } ws.onmessage = function(evt) { var data = JSON.parse(evt.data); if(data.dataType == websocketGame.CHAT_MESSAGE){ $("#chat-history").append("<li>" + data.name + " said: " + data.message + "</li>"); }else if(data.dataType == websocketGame.LINE_SEGMENT){ drawLine(ctx,data.startX,data.startY,data.endX,data.endY,1); }else if(data.dataType == websocketGame.GAME_LOGIC){ if(data.gameState == websocketGame.GAME_OVER){ websocketGame.isTurnToDraw = false; $("#chat-history").append("<li>" + data.winner + " wins! The answer is '" + data.answer + "'.</li>"); $("#restart").show(); }else if(data.gameState == websocketGame.GAME_START){ canvas.width = canvas.width; $("#restart").hide(); $("#chat-history").html(""); if(data.isPlayerTurn){ isTurnToDraw = true; $("#chat-history").append("<li>Your turn to draw. pLease draw ' " + data.answer + "'.</li>"); }else{ $("#chat-history").append("<li>Game started. Get ready. You have ne minute to guess.</li>"); } } } }; function sendMessage() { var msg = $('#message').val(); var data = {}; data.dataType = websocketGame.CHAT_MESSAGE; data.message = msg; data.name = "client1"; ws.send(JSON.stringify(data)); $('#message').val(""); } </script> </body> </html>
4,客戶端JS檔案(Index.js)
控制畫板的繪圖功能,同步多個使用者之間的繪圖
var websocketGame = {
isDrawing:false,
startX:0,
startY:0,
LINE_SEGMENT : 0,
CHAT_MESSAGE : 1,
GAME_LOGIC:2,
WAITING_TO_START:0,
GAME_START:1,
GAME_OVER:2,
GAME_RESTART:3,
isTurnToDraw:false
}
var canvas = document.getElementById("drawing-pad");
var ctx = canvas.getContext('2d');
function drawLine(ctx,x1,y1,x2,y2,thickness){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.lineWidth = thickness;
ctx.strokeStyle = "#444";
ctx.stroke();
}
$(document).ready(function(){
$('#drawing-pad').mousedown(function(e){
var canvasPosition = $(this).offset();
var mouseX = (e.pageX - canvasPosition.left) || 0;
var mouseY = (e.pageY - canvasPosition.top) || 0;
websocketGame.startX = mouseX;
websocketGame.startY = mouseY;
websocketGame.isDrawing = true;
});
$('#drawing-pad').mousemove(function(e){
if(websocketGame.isDrawing){
var canvasPosition = $(this).offset();
var mouseX = (e.pageX - canvasPosition.left) || 0;
var mouseY = (e.pageY - canvasPosition.top) || 0;
}
if(!(mouseX == websocketGame.startX && mouseY == websocketGame.startY)){
drawLine(ctx,websocketGame.startX,websocketGame.startY,mouseX,mouseY,1);
var data = {};
data.dataType = websocketGame.LINE_SEGMENT;
data.startX = websocketGame.startX;
data.startY = websocketGame.startY;
data.endX = mouseX;
data.endY = mouseY;
ws.send(JSON.stringify(data));
websocketGame.startX = mouseX;
websocketGame.startY = mouseY;
}
});
$('#drawing-pad').mouseup(function(e){
websocketGame.isDrawing = false;
});
})
5,CSS檔案配置
body{
background:#ccd6e1;
font-family:arial,serif;
}
#game{
width:450px;
margin:0 auto;
}
#game h1{
text-align: center;
margin-bottom:10px;
font-size:20px;
}
#drawing-pad{
position:relative;
border:solid 1px black;
background: white;
}
.vertical-center{
position:relative;
}
ul li{
list-style:none;
}
#chat-history{
height:100px;
overflow:auto;
border:solid 1px #ccc;
font-size:14px;
}