はじめに
こんにちは。普段は情報系の学科で大学生をしている者です。
この記事に紹介されている、wh.im(ウィム)というサービスの立ち上げに関わっているのですが、その一環でwh.im上で楽しめるゲームを開発しました。
このサービスの特徴として、誰でもゲームを投稿 できます!そのやり方を知っていただきたく、前回に引き続き記事を書きますので、興味を持った方はぜひゲーム開発を試してみてください!
アプリを公開するまでの一連の流れは、前回の記事にありますので、併せてご覧ください。
Vue.js以外でも実装は可能ですが、今回はVue.jsに限ってご紹介できればと思います!
今回は実際に遊ぶことのできるじゃんけんを例に挙げて、実装方法を説明いたします。
5/28更新
- 続編記事「爆速でwh.imのゲームを実装する(NGワードゲーム編)」が公開されました。
- ゲームの開発環境が変更となりました。詳細は「wh.imで自作ゲームを登録するまで」をご覧ください。
- デバッグが可能となりました。
6/13更新
- より丁寧に解説した記事「【Vue.js】半日でできる、ビデオチャット上で動くオリジナルゲームの開発から公開まで。」が公開されています。そちらも併せてご活用ください。
まずは開発環境で実際に動かしてみる(5/28更新)
実際にじゃんけんを開発環境で動かしてみたいと思います。
まず
$ cd ダウンロードしたいディレクトリ
$ git clone https://github.com/whimRTC/whim-janken.git
とします。そして
$ cd whim-janken
$ yarn # or npm install
$ yarn serve # or npm run serve
とします。yarnまたはnpmがインストールされていない場合はインストールしてください。
するとlocalhost:8080
にゲームが起動します。
そして、wh.imから「遊び場」へ入室し、そのアドレスの末尾に&develop=trueをつけます。するとwh.imが開発者用のモードとなります。右上のメニューの「アプリを選ぶ」から「開発用(port:8080)」を選ぶことにより、自分の手元でゲームを試すことができます。
このように表示されれば成功です!
実際のコードを見てみる
続いて、実際のコードを使いながら通信方法を説明していきます。ここは全くじゃんけんと同じなので、確認不要な方は飛ばしてしまってかまいま
まず表示される画面が書かれているsrc/App.vue
をご覧ください。
<template>
<div id="app">
<Main class="main" />
<Player
v-for="user in $whim.users"
:key="user.id"
:class="whimUserWindowClass(user)"
:displayUser="user"
/>
</div>
</template>
<script>
export default {
name: "App",
components: {
Main: () => import("@/components/main/Index"),
Player: () => import("@/components/player/Index")
},
computed: {
users() {
return this.$whim.users;
}
}
};
</script>
このゲームではMain画面とPlayer画面に分かれて実装されています。そのため、App.vue
内でMain
、Player
の2つのコンポーネントを呼び出しています。
Mainは画面中央部の画面を、Playerはそれぞれのユーザーのいる場所に表示される画面を表します。
Main
、Player
の実装はそれぞれ、 src/components/main/Index.vue
、src/components/player/Index.vue
に実装があります。
wh.imを経由した通信の方法
App.vue
で$whim.users
という呼び出しがあります(this.$whim.users
の省略形です)が、これはwhim-client-vue
というパッケージに入っています。このようにすることで、this.$whim
から始まる関数だけで、利用者間の非同期通信まわりは全てできるようになっています。
ここに扱える関数一覧を示します。scriptタグ内では適宜this
を先頭に付けてください。
状態取得(呼び出すたびに通信する)
コード | 型 | 説明 |
---|---|---|
$whim.users | [User] | ルームに入っているユーザー一覧 |
$whim.room | Room | Room Object |
$whim.accessUser | User | 現在アクセスしているUser |
$whim.state | State | ゲームの状態(自由に設計可能) |
状態変更
コード | 引数 | 説明 |
---|---|---|
$whim.assignState(Object) | Object | ゲーム情報を追記更新、 |
存在しないキーの場合:追記 存在するキーの場合:更新 |
||
$whim.resetState(Object) | Object | ゲーム情報を渡されたObjectにすべて変える |
これでは分かりにくいと思うので、後ほどのコードで使っている部分を見ながら、理解していただけると助かります。
より詳細な説明は、開発者ドキュメントをご覧ください。
このゲームのデータ構造
stateはゲームに合わせて自由に設計することができます。
今回のゲームでは、ユーザーのIDをキーとしてじゃんけんの手`('rock', 'scissors', 'paper')を値に持つObjectとします。
これらの変数は開発環境ではどんな時でも見ることができます。右上のメニューから「SHOW APP STATE」を選択すると
白い部分には私のuserIdが表示されています。
このように、全員のじゃんけんの手を確認することができます。うまくやれば、カンニングすることもできます(友達とやるときはやめましょう)。
Main
次にMain画面のコードについて説明していきます。Main画面は書くプレイヤー上にに表示されます。じゃんけんゲームでは、各プレーヤーが選択中か選択済みかがボタンを出しています。
<template>
<div class="container">
<a v-if="isAllSelected" class="btn" @click="reset">もう一度</a>
<Me v-if="!isAccessUserSelected" class="me" />
</div>
</template>
<script>
export default {
name: "Main",
components: {
Me: () => import("@/components/main/Me")
},
computed: {
users() {
return this.$whim.users;
},
isAllSelected() {
return (
this.users.length > 0 &&
this.users.every(user => this.$whim.state[user.id])
);
},
isAccessUserSelected() {
return !!this.$whim.state[this.$whim.accessUser.id];
}
},
methods: {
reset() {
this.$whim.resetState();
}
}
};
</script>
<!-- 以下略 -->
ここでcomputed
プロパティでusers
とisAllSelected
の値を定義しています。
じゃんけんでは、state[user.id]
にじゃんけんの手の状態が入るようになっていて、isAllSelected
では全員が選択しているかどうかを判定しています。つまり、state[user.id]
が全員undefined
でないかどうかを判定しています。users.length > 0
としているのは、データベースからuser
が取得できていない状態での判定を防ぐためです。
このようにVue内で先ほど定義した関数を用いることでゲームを実装できます。
Me
コンポーネントについては次で説明します。
Me
<template>
<div>
<h2 class="subtitle">
選択してください!
</h2>
<div>
<img src="@/assets/rock.png" class="img" @click="select('rock')" />
<img
src="@/assets/scissors.png"
class="img"
@click="select('scissors')"
/>
<img src="@/assets/paper.png" class="img" @click="select('paper')" />
</div>
</div>
</template>
<script>
export default {
name: "Me",
methods: {
select(show) {
this.$whim.setState(this.$whim.accessUser.id, show);
}
}
};
</script>
じゃんけんの手を選択したときに、select(show)
メソッドが呼ばれ、
this.$whim.setState(this.$whim.accessUser.id, show);
によってデータベースのstate[accessUser.id]
に自分の手が登録されます。
Player
次にやや複雑なのですが、Player画面を実装していきます。
<template>
<div class="container">
<Result v-if="isAllSelected" :displayUser="displayUser" />
<h2 v-else-if="isAccessUserSelected && isSelected" class="subtitle">
選択済み
</h2>
<h2 v-else-if="isAccessUserSelected" class="subtitle">
選択中
</h2>
</div>
</template>
<script>
export default {
name: "Player",
components: {
Result: () => import("@/components/player/Result")
},
props: {
displayUser: {
type: Object,
required: true
}
}, // 表示されているUserの情報
computed: {
users() {
return this.$whim.users;
},
isMe() {
return this.$whim.accessUser.id === this.displayUser.id;
},
isAccessUserSelected() {
return !!this.$whim.state[this.$whim.accessUser.id];
},
isSelected() {
return !!this.$whim.state[this.displayUser.id];
},
isAllSelected() {
return (
this.users.length > 0 &&
this.users.every(user => this.$whim.state[user.id])
);
}
}
};
</script>
computed
の内容を中心にご説明します。
まず、先ほどと同じisAllSelected
がすなわち全員が手を選択した状態を表していて、これがtrue
のときResult
コンポーネントを表示します。
また、isSelected
でthis.$whim.state[this.displayUser.id]
、すなわちデータベース上のstate[画面の人のID]
を取得していて、その画面の人がどのじゃんけんの手を選んだ状態かどうかが得られています。this.displayUser
がこの画面のプレーヤーを表すことに注意してください(displayUser
の情報はApp.vue
で渡されています)。isSelected
がtrue
である、すなわち選んだ状態のとき、画面に「選択済み」が表示されます。
次に、isMe
でこの画面が自分が映っている画面であるかを取得しています。これがtrue
のときに表示される、自分のじゃんけんの手を決める画面はMe
というコンポーネントで実装されています。
そして、上のいずれの状態でもないときに、「選択中」と表示します。
Result
<template>
<div>
<h2 class="subtitle">
結果
</h2>
<div>
<img
v-if="show === 'rock'"
src="@/assets/rock.png"
width="150"
height="150"
/>
<img
v-if="show === 'scissors'"
src="@/assets/scissors.png"
width="150"
height="150"
/>
<img
v-if="show === 'paper'"
src="@/assets/paper.png"
width="150"
height="150"
/>
</div>
</div>
</template>
<script>
export default {
name: "Result",
props: {
displayUser: {
type: Object,
required: true
}
},
computed: {
show: function() {
return this.$whim.state[this.displayUser.id];
}
}
};
</script>
<style lang="scss" scoped></style>
state[ユーザーのid]
には手が保存されているのでshow
でプレーヤーの手を返します。displayUser
は呼び出し元のPlayer
から渡されています。
以上のコードがあれば、じゃんけんゲームが正常に動きます。
最後に
今回は、ゲームの中では最も単純なじゃんけんゲームについて説明しました。次回はNGワードゲームの実装について説明したいと思っています。乞うご期待!
5/28更新
「爆速でwh.imのゲームを実装する(NGワードゲーム編)」が公開されました。