前置き
Illustratorで絵を描いたので、それらを使ってゲームを作ってみました。
以前はJavaScriptで絵をただランダムに表示させるだけだったのですが、Nuxt.jsを使ってゲームに作り変え、遊び方説明ページを加えたり結果を表示させるようにしたり、英語対応やダークモードも実装したりしました。
しかし、
何かモヤモヤとしたものが残っています。
そして、
そのモヤモヤは日々募るばかりです。
なぜか?
そうです。
一人でしか遊べないからです。
誰かと対戦できるようにしたいのです。
調べると、
Socket.IO enables real-time, bidirectional and event-based communication.
It works on every platform, browser or device, focusing equally on reliability and speed.
Node.js用の双方向通信サポートライブラリであるSocket.IOを使うと対戦ゲームに作り変えられるような予感がします。
そこで、Socket.IOを試しに一度使ってみようと思い、『はじめてのNode.jsプログラミング Kindle版』(松尾 勇也 著) の通りにチャットを作ってみました。
本題
前置きが長くなりましたが、ここからが本題のメモ書きです。
以下はserver.jsのこの部分の抜粋です。
// socket.ioの設定
io.sockets.on('connection', function(socket) {
socket.on('login', function(name) {
// 接続しているユーザー全員にloginを送信
var time = new Date().toJSON();
io.sockets.emit('login', time, name);
// name を記憶
socket.set('name', name);
});
socket.on('post', function(name, text) {
// 接続しているユーザー全員にpostを送信
var time = new Date().toJSON();
io.sockets.emit('post', time, name, text);
});
socket.on('disconnect', function() {
// 接続しているユーザー全員にlogoutを送信
socket.get('name', function(err, name) {
var time = new Date().toJSON();
io.sockets.emit('logout', time, name);
});
});
});
(Matsuo Yuya. Hajimete no Nodejs Programming (Japanese Edition) (Kindle の位置No.741-750). Kindle 版. より抜粋)
node server.js
としたところ、以下のエラーが発生しました。
root@7f37fa299545:/app# node server.js
/app/server.js:18
socket.set('name', name);
^
TypeError: socket.set is not a function
at Socket.<anonymous> (/app/server.js:18:16)
at Socket.emit (events.js:310:20)
at /app/node_modules/socket.io/lib/socket.js:528:12
at processTicksAndRejections (internal/process/task_queues.js:79:11)
サーバーに接続すると login
イベントがクライアントに向けて発信されます。その中でユーザーの入力した名前を記憶させるための記述の中で set
を用いています。
調べてみたところ、
『node.js - socket.io socket.set and socket.get - what is the callback argument for? - Stack Overflow』の回答によると
The
get
andset
functions on the socket object were removed in version 1.x.
get
と set
は廃止になっているようです。
ドットインストールにも載ってました。
Socket.IO の 1.0 から socket.set と socket.get メソッドが廃止されたため、そのまま動作させるとエラーが発生してしまいます。
そこで、以下のように修正したところうまくいきました。
(いくつか修正していますが、「修正」と書いたところの修正のみがエラーに関連している部分です。)
//socket.ioの設定
io.sockets.on('connection', socket => {
socket.on('login', name => {
//接続しているユーザー全員にloginを送信
const time = new Date().toJSON()
io.sockets.emit('login', time, name)
//nameを記憶
socket.client_name = name
})
socket.on('post', (name, text) => {
// 接続しているユーザー全員にpostを送信
const time = new Date().toJSON()
io.sockets.emit('post', time, name, text) // 修正
})
socket.on('disconnect', () => {
// 接続しているユーザー全員にlogoutを送信
const time = new Date().toJSON() // 修正
io.sockets.emit('logout', time, socket.client_name) // 修正
})
})
脇道
スタイルも修正してみました。
自分が送信したメッセージは画面の右に表示されて、他の人のメッセージは画面の左に投稿されるような見た目にしようと思ったので、以下のことを試しました。
socket.on('post', (name, text) => {
// 接続しているユーザー全員にpostを送信
const time = new Date().toJSON()
socket.emit('self-post', time, name, text)
socket.broadcast.emit('others-post', time, name, text)
})
上記のように自分の投稿と他人の投稿をそれぞれ socket.emit
と socket.broadcast.emit
を使い分けて別のイベントとして発信することで、
socket.on('self-post', (time, name, text) => {
const content = document.createElement('div')
content.className = 'self'
createMessageNode(content, text, time, name)
})
socket.on('others-post', (time, name, text) => {
const content = document.createElement('div')
content.className = 'others'
createMessageNode(content, text, time, name)
})
自分の投稿にはself
、他人の投稿にはothers
のようにそれぞれ別のクラスを設定でき、別のスタイルを割り当てることができました。
おわりに
次はNuxt.jsで作っているゲームにSocket.IOを組み合わせて対戦できるようにしたいです。
Nuxt.jsでSocket.IOを使うには『Nuxt.js (Vue.js) + Express + Socket.IO でリアルタイムWeb (チャット) を体験する』が参考になるのかなと思っているのですが、やってみないとまだわかりません。