【初投稿テスト】非同期ネットゲーム作ってみた


非同期ネットゲーム仕様書

はじめに

本書は、RPGアツマールで開催される非同期ネットゲームコンテスト(2019年3月3日(日)23:59〆切)に向けて作成するゲームの仕様を書いた物である。

  • マークダウン記法で記述するテキストデータである。
  • UML部分はPlantUMLを使用する。

マークダウン記法

本書で使用するマークダウン記法について、使い方と書き方を以下に記述する。

使い方

書き方

マークダウン記法では、文章内の改行は無視される。
画面の右端で自動改行される。
明示的に改行させたい時は行末に空白2つを付ける。

このようになります。

ですよ。

  • ハイフン+スペース「- 」を行頭に付けると、箇条書きになる。
  • 行頭に「●」が付く。
    • 行頭にスペース2個を付けると、インデントも可能。
  • 本書では要件や仕様に関する記述は、基本的に箇条書きで記述している。
  1. 連番による箇条書きは、番号+スペースを行頭に付ける。
    1. 番号は「1. 」だけでも自動採番される
    2. だから、「1. 」の方が変更に強い
  2. 改行が必要な時は、このように
    行末にスペース2個を付ける。
  3. 番号の場合はスペース4個でインデントする。
  4. 本書では処理の順序を表したい場合に使用する。

【注意】

箇条書きや引用などの文章の塊がある場合、その塊の種類が変わる所で空白行を入れる。

「> 」は引用です。

引用する時に開始行の先頭に使います。
このように表示されます。

表は以下のように記述する。

|A|ヘッダ|てすと|項目名|
|---|:---:|---|---|
|AAA|B|テスト|表の内容|
|Aの内容2|センタリング|C|表の内容2|
|Aの内容03|表はこのように書く|Test|D|

この記述により、以下のように表示される。

A ヘッダ てすと 項目名
AAA B テスト 表の内容
Aの内容2 センタリング C 表の内容2
Aの内容03 表はこのように書く Test D
バッククォート3個「```」を開始行、終了行に書いて囲った
  この範囲は
自由に空白や改行できる。

開始側のバッククォート3個「```」の後に、テキストデータの形式を記述する。
この例では「```text」としているが、
「```javascript」「```plantuml」と書くと、その言語として表示される。

そのため
  ソースコードを
    書くのに最適。

本書で使いそうなマークダウン記法の書き方は以上。

なお、下の横線は「***」と記述する。


ゲーム情報 (概要)

ゲームの目的

  • 花を育てる。
    • 当初予定では、「いちご狩り」をするゲームであったが、いちごの素材がないため断念した。
  • 花をプレゼントして好感度を上げる。
  • キャラクターの人気投票をする。

ゲームタイトル

  • 『花摘み【パケキャラ総選挙】』を仮タイトルとする。
    • 「花摘み」は品がないがインパクトはあると思われるので、仮タイトルとする。
  • 最終的に、タイトルは『PKG16 総選挙』とした。

ゲームの流れ (基本設計)

概要

  • 放置系ゲームの要領で花を育て、花をパケキャラにプレゼントし、プレゼントの量でパケキャラの人気を競う。
  • 「パケキャラ」とは、RPGツクールMVの「パッケージキャラクター」の事である。本ゲームではNPCである。
  • 他人が育てた花を取る事が出来る。
  • パケキャラごとに好感度ランキングを用意する。

花を育てる

放置系ゲーム要素は以下の流れとする。

  1. 種を植える(プレイヤー操作)。
  2. 種が草に育つ(放置)。
  3. 草が花に育つ(放置)。
  4. 花が実になる(放置)。
  5. 実が種になる(放置)。
  6. 種が草に育つ(放置)。繰り返し。
  • 花壇は全プレイヤー共通の領域とする。
  • 花壇の数はプレイヤーの数に応じて増やす。
    • 自動でマップの拡張できる?
      しかし、1プレイヤーに1マップなどにするとマップ数が増えると困るので、自動で増やすのはやめた方が良さそう。
    • 花壇の数は何らかのタイミングで作者が手動で増やす。(増やせるように作る事)
  • 花の成長状況を花の上に表示させたい。「あと何秒で次の状態になるか」を表示する。

花を摘む

  • プレイヤーは、「花」または「実」を採取する事が出来る。
  • 「花」と「実」以外は採取できない。
  • 花壇は共通領域なので、他のプレイヤーが育てた「花」や「実」を採取する事が出来る。
  • 花を摘んだ花壇は「空き」になる。プレイヤーが種を植えるまで「空き」になる。

花をプレゼントする。

  • プレイヤーはパケキャラに「花」または「実」をプレゼントする事が出来る。
  • プレイヤーがプレゼントする事で、「好感度」と「種」と「所持金」を得る事が出来る (このゲームに公職選挙法のようなものは無い)。
  • プレイヤーがプレゼントする事で、パケキャラの人気ポイントが上昇する。

種の入手

  • プレイヤーはゲーム開始時に「種」をいくつか持っている。
  • プレイヤーがパケキャラにプレゼントした時に、「種」と「所持金」をもらえる。
    • 「実」をプレゼントした時に、その「種」をもらえると面白いかも。 出所がはっきりしているので。
  • プレイヤーは所持金を使用して「種」を買う事が出来る。

プレイヤーのデータ

  • アイテム(植える前の「種」、採取した「花」または「実」)
    • 「種」と「花」&「実」でアイテム種別を分ける。
  • プレイヤーの実績を表す何か。
    • 実績アイテム(大事なもの)
  • 経験値(レベル)
  • 所持金
  • 好感度(パケキャラそれぞれなので、16人分)
    • ステータス画面を使うのと、アイテムの個数で表現するの、どっちが楽?
    • 変数を16個用意して、ステータス画面でその変数を表示する?

アツマールAPIを使う場面

  • 花壇はプレイヤー共有なので、何らかのAPIを使用する。
    • 使うAPIは、グローバルシグナルになりそう。
    • 花の成長はプレイヤーごとに行い、採取した時にシグナルを送る。
    • 採取シグナルを受け取ると、その花壇は「空き」になる。
    • タイミングによっては、同じ花壇で複数プレイヤーが同時に採取できるが、許容する。
    • APIの通信は『5秒に1回よりも緩やかにすること』との事なので、採取シグナル送受信のタイミングで、何らかの演出を行い、時間を稼ぐ。
  • ランキング機能を使う。
    • パケキャラごとの好感度をランキングにする。
    • パケキャラ総選挙の順位はランキング機能を使わない。プレイヤーのランキングではないので。
  • 総選挙の順位に、グローバルサーバー変数を使用する。
    • 1キャラにつき1変数を使用すると、16個のグローバルサーバー変数が必要になる。
    • グローバルサーバー変数では、トリガーを使用して値の変更を行う。

パケキャラ

  • RPGツクールMVのパッケージキャラ16体を使う。
  • マップに表示する。
  • プレゼントを渡す事が出来る。プレゼントは総選挙の票(人気ポイント)を兼ねている。
    • プレゼントは「花」または「実」である。
    • アイテム選択の処理でプレゼントを渡す。
  • 好きな「花」「実」があり、それによってプレゼント時の好感度に差がある。
  • 好きな「花」「実」の説明と、プレゼントを渡す場所は分けておく。
    • 好きな「花」「実」の説明はすぐに見れる場所に置く。
    • プレゼントを渡す場所は、パケキャラごとにマップを用意する。
    • プレゼントを渡してお礼を受け取ると、ランキングAPIの通信を行う。そのため、(プレゼントは1アイテムずつ選択するが)プレゼントに対してのお礼はまとめて受け取るのが良さそう。そのマップを出る時でもイイかも。

メモ

  • メッセージWindowに歩行キャラを表示させたい。名前だけでパケキャラを識別するのが難しいと思われるため。
    • アイコン化(32×32)するか、プラグインを用意するか。
    • IconSet.pngを下に拡張できるので、アイコン化するのが良さそう。

詳細設計

  • 詳細設計の代わりに、JavaScriptのソースコードを記述する。

Promise全般

// promise() を使いたい場合
// thenはPromise受信時に実行される
// catchはエラー発生時に実行される
// ドット「.」区切りで連続して記述する
// 1行で書くとこのようになっている
promise().then(function(a){ 非同期処理 }).catch(function(b){ エラー処理 });

グローバルシグナル送信

window.RPGAtsumaru.experimental.signal.sendSignalToGlobal(data)
// catchはエラー発生時に実行される
// 引数errを受け取る
.catch(function(err){
    switch(err.code) {
    case "UNAUTHORIZED":
        // プレイヤーがログインしていない
        console.log('send error : UNAUTHORIZED');
        break;
    case "BAD_REQUEST":
        // ゲーム側で何か間違えているとき=指定したボードIDが大きすぎるかマイナスの場合などに発生
        console.log('send error : BAD_REQUEST');
        break;
    case "INTERNAL_SERVER_ERROR":
        // サーバー側で何らかの問題=通信不良やメンテ等で発生
        console.log('send error : INTERNAL_SERVER_ERROR');
        break;
    case "API_CALL_LIMIT_EXCEEDED":
        // 短時間にゲームAPIを利用しすぎて、一時的に利用を制限されている
        console.log('send error : API_CALL_LIMIT_EXCEEDED');
        break;
    }
});

グローバルシグナル受信

window.RPGAtsumaru.experimental.signal.getGlobalSignals()
// thenはPromise受信時に実行される
// Promiseの内容を引数vとして受け取る
// 非同期処理なので、いつ受信するかは分からない事に注意!
.then(function(v){
    KRD_checkSignal(v); // 別関数で処理する
})
// catchはエラー発生時に実行される
// 引数errを受け取る
.catch(function(err){
    switch(err.code) {
    case "INTERNAL_SERVER_ERROR":
        // サーバー側で何らかの問題=通信不良やメンテ等で発生
        console.log('get error : INTERNAL_SERVER_ERROR');
        break;
    case "API_CALL_LIMIT_EXCEEDED":
        // 短時間にゲームAPIを利用しすぎて、一時的に利用を制限されている
        console.log('get error : API_CALL_LIMIT_EXCEEDED');
        break;
    }
});

データフロー