ニコ生ゲーム関連の仕様

ここまでの文書で述べたことを含め、仕様や要求事項をまとめます。

# モード

ニコ生ゲームでは、 game.json に environment.nicolive.supportedModes の値が定義されている必要があります。

この値は文字列の配列でなければなりません。 配列の各要素は、次のいずれかでなければなりません。

  • "single" - ひとりプレイモードに対応する場合
  • "ranking" - ランキングモードに対応する場合
  • "multi_admission" - マルチプレイモードに対応する場合
  • "multi" - マルチプレイモードに対応する場合で、起動時にプレイヤー募集をしない場合

"multi_admission""multi" は排他的です。両方を指定した場合、 "multi" は無視されます。

"ranking" または "multi_admission" の場合、ゲーム起動時に プレイヤーの募集 が行われます。

environment.niconico プロパティは非推奨となりました。 互換性のため、当面の間 environment.niconico も引き続きサポートされます。 environment.niconicoenvironment.nicolive が両方指定されている場合、 niconico 側の指定は無視されます。

# 解像度と FPS

次の値である必要があります。

  • 画面解像度: 1280x720 以下 (16:9 を推奨)
  • FPS: 1 以上 60 以下 (30 または 60 を推奨)

ニコニコ生放送内のゲームは放送画面に合うよう自動的に拡縮されます。放送画面上で縦横に余白なく表示できるよう、アスペクト比 16:9 を推奨します。公開されているいくつかのサンプルコンテンツ(泥棒バスターなど))は、640x360 で作成されています。

# ランキング対応ゲームの gameState

supportedModes"ranking" を指定するゲームでは、 g.game.vars.gameState が特別な意味を持ちます。

# スコア

ランキング対応ゲームは、ゲームの進行中、次の変数に スコア を代入しなければなりません。

g.game.vars.gameState.score

スコアは 0 以上の整数でなければなりません。 上限はありませんが 99999 以下を推奨します。

ランキングモードでは g.game.vars.gameState.score の値をスコアとして扱い、ゲームの終了後、このスコアに基づいてランキングの順位が決定されます。

テンプレートでは以下のようにスコアを付与する処理が記述されています。

var scene = new g.Scene({ game: g.game });
g.game.vars.gameState = { score: 0 };
scene.loaded.add(() => {
  var time = 60; // 制限時間
  // フォントの生成
  var font = new g.DynamicFont({
    game: g.game,
    fontFamily: g.FontFamily.Serif,
    size: 48
  });
  // スコア表示用のラベル
  var scoreLabel = new g.Label({
    scene: scene,
    text: "SCORE: 0",
    font: font,
    fontSize: font.size / 2,
    textColor: "black"
  });
  scene.append(scoreLabel);

  scene.pointDownCapture.add(() => {
    // 制限時間以内であればゲーム画面のタッチ1回ごとにSCOREに+1します
    if (time > 0) {
      g.game.vars.gameState.score++;
      scoreLabel.text = "SCORE: " + g.game.vars.gameState.score;
      scoreLabel.invalidate();
    }
  });
});

# プレイ閾値

ランキング対応ゲームでは プレイ閾値 を定めることができます。 プレイ閾値以下のスコアは「プレイしなかったもの」として扱われ、ランキング上位者として表示されなくなります。 プレイ閾値は、次の変数に代入された値です。

g.game.vars.gameState.playThreshold

値は整数でなければなりません。この変数に値が代入されていない場合、プレイ閾値は 0 として取り扱われます。 生存期間に応じてスコアが入るなど、プレイヤーが何も操作しなくてもスコアが 0 より大きくなってしまうゲームでは、この値を適切に設定してください。

この値は、ゲームに参加した人数が少ない場合に「全くプレイしていないのにランキングに名前が出ることがある」という違和感のある挙動を避けるために提供されています。

# クリア閾値

同様に「ゲームをクリアしたとみなすか」にも閾値(クリア閾値)を定めることができます。クリア閾値は次の変数に代入された値です。

g.game.vars.gameState.clearThreshold

ただしこの値は将来の拡張のために予約されているものです。現在のところ参照されません。

# セッションパラメータ

実行時、ニコ生ゲームにはいくつかの追加情報が与えられます:

  • どのサービスで実行されているか
  • どのモードで起動されたか
  • ランキングモード時の制限時間
  • ランキングモード時の共通乱数シード など

これらの追加情報(またはそれをまとめたオブジェクト)を セッションパラメータ と呼びます。

セッションパラメータは、与えられる場合、ゲーム開始直後に g.MessageEvent で通知されます。通知された MessageEvente とすると、 (e.data.type === "start") である時、 e.data.parameters の値がセッションパラメータです。

次のコードは、セッションパラメータを取得する例です。

var scene = new g.Scene({ game: g.game });

// 何も送られて来なかった時は、空のオブジェクトで動作する
var sessionParameters = {};

scene.message.add(function (msg) {
    if (msg.data && msg.data.type === "start" && msg.data.parameters) { // セッションパラメータのイベント
        sessionParameters = msg.data.parameters;
    }
});

scene.loaded.add(function () {
    // 通常のゲームとしての初期化処理
    // ...
}

セッションパラメータが与えられない場合には、そもそもこのイベントが来ないか、あるいは来たイベントに parameters がありません。

Akashic Engine では通常、イベントはシーンのロードタイミング(g.Scene#loaded)より後に受信されるため、 loaded の処理中にはこの値を参照できないことに注意してください。これは仕様による制限です。

厳密にセッションパラメータの受信を待って loaded の初期化処理を行いたい場合は、 loaded ではなく message トリガーの fire を待って処理を行う必要があります。 (ただしそうするとセッションパラメータが送られない環境では動作しないコンテンツになってしまうので、「 g.Scene#update の fire を数回待ってもこなければデフォルト値で開始する」などの対応も検討してください。)

# サービス (service)

セッションパラメータ sessionParameters がある時、 sessionParameters.service は実行環境を表す値です。

この値は将来の拡張のために用意されています。ニコ生ゲームの場合、値は常に "nicolive" です。

# モード (mode)

セッションパラメータ sessionParameters がある時、 sessionParameters.modeモード を参照できます。

この値は game.json の environment.nicolive.supportedModes (旧仕様で投稿した場合は environment.niconico.supportedModes) に記述した文字列のいずれかで、実際にゲームが起動されたモードを表します。 例えば、 "single" が送られてきたら「ひとりで遊ぶ」モードで、 "ranking" が送られてきたら「ランキング」モードで、ゲームが起動されています。

# 制限時間 (totalTimeLimit)

セッションパラメータ sessionParameters がある時、 sessionParameters.totalTimeLimit の値は 制限時間 です。

この値はランキングモードの場合にのみ与えられます。与えられる場合、この値は秒数を表す整数です。 ランキング対応ゲームは、起動からこの時間が経過した後、自動的に終了されます。

この値はあくまでも目安であることに注意してください 。ゲーム起動後、厳密にこの時間で終了されることを保証するものではありません。 これはゲームリソースのダウンロード時間のばらつきや、スコア送信時の通信遅れを救済するためのサーバ側の多少のマージンなど、いくつかの要因でずれが生じるためです。

たとえば制限時間から逆算して「クリア画面」を作るような場合、念のため、制限時間の数秒前にはゲーム上の演出が完了するように作る ことを推奨します。

# 共通乱数シード (randomSeed)

セッションパラメータ sessionParameters がある時、 sessionParameters.randomSeed の値は 共通乱数シード です。

この値はランキングモードの場合にのみ与えられます。与えられる場合、この値は整数です。

ランキングモードでは、各プレイヤーの手元で個別にゲームが実行されます。 そのため、プレイヤー間で標準の乱数生成器 (g.game.random) の結果は一致しません。 ゲーム開発者はこの値を使って、プレイヤー間で共通のシードを持つ乱数生成器(共通乱数生成器)を作ることができます。

共通乱数生成器を作る場合、共通にしたい乱数(クイズの出題順など)以外に使わないように注意してください。 例えばユーザ操作などに応じて共通乱数生成器を使うと、乱数の系列が他のプレイヤーとずれてしまって元も子もありません。

# 難易度設定 (difficulty)

セッションパラメータ sessionParameters がある時、 sessionParameters.difficulty の値は 難易度設定 です。

与えられる場合、1 以上 10 以下の整数です。 この値は、ゲームに対して「この難易度でゲームを行なって欲しい」という要望を通知するものです。 ゲーム開発者はこの値を見てゲームの難易度を調整することができます。これは必須ではありません。

(ただし、現時点ではゲーム起動時に難易度を選択する方法がありません。したがってこれは現在のところ「将来的な対応に備えて利用することができる値」に過ぎません。)

# 旧仕様: gameTimeLimit

セッションパラメータ sessionParameters がある時、 sessionParameters.gameTimeLimit の値が与えられることがあります。

この値は後方互換性のために残されているものです。 totalTimeLimit を利用してください。

# preferredSessionParameters

ニコ生ゲームの game.json に environment.nicolive.preferredSessionParameters フィールドがある場合、 その内容はコンテンツにとって望ましいセッションパラメータの値として解釈されます。

preferredSessionParameters は、与えられる場合、オブジェクトでなければなりません。 そのプロパティとして指定できるものは次の通りです:

プロパティ 説明
totalTimeLimit 20 以上 200 以下の整数 "ranking" モードで与えられる totalTimeLimit の値

この値はあくまでも参考値として扱われます。 実際に渡されるセッションパラメータが、ここで指定した値と同じである保証はありません。

後方互換性のため、 environment.nicolive がなく environment.niconico がある場合、そちらが参照されます。

# プレイヤーの募集

"ranking", "multi_admission" モードのニコ生ゲームは、ゲームの実際の起動に先立ってプレイヤーの募集が行われます。 これはニコニコ生放送の 生ゲームプレイ中 ページの「視聴者を待っている番組」欄に配信を掲出します。

視聴者を待っている画面ページ

募集中は次のような画面が表示されます。配信者は任意のタイミングで募集を打ち切ってゲームを開始することができます。

プレイヤー募集画面

プレイヤー募集は設定したモードに従って自動的に行われます。 またゲームの外部で、起動前に行われるため、ゲーム内での特別な対応は不要です。

プレイヤー募集は、あくまでも配信外から視聴者 (プレイヤーの候補) を募集する (=「生ゲームプレイ中」ページに掲出する) 機能であることに注意してください。

オンラインゲームのいわゆるマッチング機能のようなものではなく、何人集まったか、誰が集まったかなどの情報がゲームに与えられることはありません。 ゲーム側での特別な対応なしにプレイヤー募集を利用できるのはこのためです。

たとえばゲームの内容的に人数制限があり、参加者と観戦者を分けるようなゲームでは、ゲーム内で改めて参加者を募る必要があります。(配信内での "参加者" の募集)