オープニングとエンディング
本章では、オープニング演出とエンディング演出の追加について説明します。
オープニング演出の作成
オープニングはゲームの概要を説明する重要な部分です。 とくにランキング形式のニコ生ゲームにおいては、ゲームの起動時間に制約があります。 この時間の中で、簡潔かつわかりやすくゲームのルールを伝えられることが重要になります。
今回は以下のタイトルロゴと説明を順番に表示するようなオープニングを実装してみます。 以下の画像をそれぞれダウンロードして assets/opening/
ディレクトリに保存しておきます。
タイトルロゴ
説明
配置後、忘れずに akashic scan
を実行します。
akashic scan asset
それではオープニング用のシーン openingScene
を新規に作成します。
exports.main = (param) => {
const game = g.game; // よくアクセスするため変数に保持しておく
// オープニング用シーンの作成
const openingScene = new g.Scene({
game,
assetPaths: [
"/assets/opening/*"
],
});
openingScene.onLoad.addOnce(() => {
const titleLogo = new g.Sprite({
scene: openingScene,
src: openingScene.asset.getImage("/assets/opening/breakout_title.png"),
x: game.width / 2,
y: game.height / 2,
anchorX: 0.5,
anchorY: 0.5,
});
openingScene.append(titleLogo);
const descriptionLogo = new g.Sprite({
scene: openingScene,
src: openingScene.asset.getImage("/assets/opening/breakout_description.png"),
x: game.width / 2,
y: game.height / 2,
anchorX: 0.5,
anchorY: 0.5,
});
openingScene.setTimeout(() => {
titleLogo.destroy();
openingScene.append(descriptionLogo);
}, 2000);
openingScene.setTimeout(() => {
game.replaceScene(scene);
}, 6000);
});
game.pushScene(openingScene);
const scene = new g.Scene({
game,
assetPaths: [
"/assets/images/*",
"/assets/se/*",
"/assets/fonts/*",
],
});
openingScene
では、最初にゲームのロゴを2秒間表示し、その後ゲームの説明を4秒間 (ゲーム開始から6秒後まで) 表示します。 scene.setTimeout()
は scene.setInterval()
に似ていますが、繰り返しではなく一度のみ処理が実行されます。 scene
の部分には openingScene
を指定することに注意してください。
ゲームのシーンへと遷移には game.replaceScene()
を利用しています。
TIP
game.pushScene()
は現在のシーンスタックに対して遷移先のシーンを追加するため、遷移元のシーンの状態を保存します。 一方 game.replaceScene()
は遷移元のシーンを遷移先のシーンに置き換えます。 最初に追加するシーン以外で、戻る必要のないシーン遷移では game.replaceScene()
を利用すべきでしょう。
最後にコード末尾にある game.pushScene(scene)
を削除します。
scene.onLoad.add(() => {
...
function pointInRect(x, y, e) {
...
}
});
game.pushScene(scene);
};
ゲームを実行してみましょう。 ゲームロゴの後に説明が表示され、その後ゲーム画面へと遷移します。
エンディング演出の作成
エンディング画面では、ゲームの終了通知と獲得したスコアの2つの要素を表示します。
終了ロゴ
まずは終了を通知するロゴをゲームに組み込みます。 以下の画像をダウンロードして assets/images
へ配置してください。
ゲーム終了時に終了ロゴを表示するように修正します。 前に残しておいた // TODO: 終了処理
というコメントの部分に移動して、終了ロゴを表示させるコードを追加します。
// 残り時間の更新
const timer = scene.setInterval(() => {
remainingTime--;
if (remainingTime === 0) {
scene.clearInterval(timer);
vx = 0;
vy = 0;
// TODO: 終了処理
// 終了ロゴを表示
const finishLogo = new g.Sprite({
scene,
src: scene.asset.getImage("/assets/images/breakout_finish.png"),
x: game.width / 2,
y: game.height / 2,
anchorX: 0.5,
anchorY: 0.5
});
scene.append(finishLogo);
}
updateTimer();
}, 1000);
終了時に効果音を鳴らします。 scene.onLoad
の直後でオーディオ再生コンテキストを生成します。
scene.onLoad.add(() => {
const sePaddleAsset = scene.asset.getAudio("/assets/se/se_paddle");
const sePaddle = game.audio.create(sePaddleAsset);
const seBlockAsset = scene.asset.getAudio("/assets/se/se_block");
const seBlock = game.audio.create(seBlockAsset);
const seMissAsset = scene.asset.getAudio("/assets/se/se_miss");
const seMiss = game.audio.create(seMissAsset);
const seFinishAsset = scene.asset.getAudio("/assets/se/se_finish");
const seFinish = game.audio.create(seFinishAsset);
...
});
ロゴ表示部分で効果音を再生します。
// 残り時間の更新
const timer = scene.setInterval(() => {
remainingTime--;
if (remainingTime === 0) {
scene.clearInterval(timer);
vx = 0;
vy = 0;
// 終了ロゴを表示
const finishLogo = new g.Sprite({
...
});
scene.append(finishLogo);
seFinish.play();
}
updateTimer();
}, 1000);
スコア結果表示
最後に、プレイヤーが獲得したスコアを表示するための結果画面を作成しましょう。 以下の画像をダウンロードして assets/ending
ディレクトリへと配置してください。
結果画面では、スコア表示をわかりやすく目立つように、大きめのサイズのビットマップフォントを新たに作成します。 以下のコマンドを実行して font-number-large
を作成します。
bmpfont-generator rounded-mplus-2p-black.ttf -F "#fff" -S "#000" --stroke-width 4 -c "0123456789+-" -H 80 --margin 3 assets/fonts/font-number-large.png
akashic scan
コマンドで変更を適用します。
akashic scan asset
結果画面を表示するシーン endingScene
を作成します。 このシーンでは、スコアと表示されているパネル上に先ほど作成したフォント font-number-large
でプレイヤーのスコアを表示します。 scene.onLoad
の後ろ (コードの最終行付近) に以下のコードを追加します。
scene.onLoad.add(() => {
...
});
const endingScene = new g.Scene({
game,
assetPaths: [
"/assets/fonts/*",
"/assets/ending/*",
],
});
endingScene.onLoad.addOnce(() => {
// スコア用フォントの作成
const font = new g.BitmapFont({
scene: endingScene,
src: endingScene.asset.getImage("/assets/fonts/font-number-large.png"),
glyphInfo: endingScene.asset.getJSONContent("/assets/fonts/font-number-large_glyphs.json"),
});
// スコア表示用のパネル表示
const resultPanel = new g.Sprite({
scene: endingScene,
src: endingScene.asset.getImage("/assets/ending/breakout_result.png"),
x: game.width / 2,
y: game.height / 2,
anchorX: 0.5,
anchorY: 0.5,
});
endingScene.append(resultPanel);
// スコア結果表示エンティティの作成
const resultScoreLabel = new g.Label({
scene: endingScene,
font,
fontSize: font.size,
text: `${game.vars.gameState.score}`,
x: resultPanel.x,
y: resultPanel.y + 60,
anchorX: 0.5,
anchorY: 0.5,
});
endingScene.append(resultScoreLabel);
});
};
ゲームの終了後に endingScene
へと遷移するようにコードを追加します。
// 残り時間の更新
const timer = scene.setInterval(() => {
remainingTime--;
if (remainingTime === 0) {
scene.clearInterval(timer);
vx = 0;
vy = 0;
// 終了ロゴを表示
const finishLogo = new g.Sprite({
...
});
scene.append(finishLogo);
seFinish.play();
// エンディングシーンへと遷移
scene.setTimeout(() => {
game.replaceScene(endingScene);
}, 3000);
}
updateTimer();
}, 1000);
ゲームを実行してみましょう。 左上の残り時間が 0
になったタイミングで「Finish!」というロゴが表示され、その後獲得スコアが表示されれば成功です。
番外編: トゥイーンアニメーションを使った演出
トゥイーンアニメーション(Tween Animation)はアニメーションを作成する手法の一つで、物体やオブジェクトがある状態から別の状態に滑らかに変化するような動きを実現できます。 ゲーム制作だけではなく Web サイトのアニメーション演出など広く使われています。
Akashic Engine では、トゥイーンアニメーションを手軽に利用できる拡張ライブラリ akashic-timeline を提供しています。 以下をクリックすることでデモを動作させることができます。
今回は、実際に akashic-timeline を使って、残り時間が少なくなったときに画面全体を赤く明滅させるような警告表示を導入してみます。
akashic-timeline のインストール
akashic-timeline は akashic install
コマンドを使ってインストールできます。
akashic install @akashic-extension/akashic-timeline
以下のように出力されていることを確認します。
INFO: Installing @akashic-extension/akashic-timeline...
INFO: Adding file paths to globalScripts...
INFO: Adding file paths to moduleMainScripts...
INFO: Done!
akashic-timeline の利用
コードの冒頭で require()
を使用し、以降は tl
変数を介して akashic-timeline を利用します。
const tl = require("@akashic-extension/akashic-timeline");
exports.main = (param) => {
...
トゥイーンの作成には、まずはシーンに紐づいた Timeline
を生成する必要があります。 scene
の生成直後で Timeline
を生成します。
const scene = new g.Scene({
game,
assetPaths: ["/assets/images/*", "/assets/se/*", "/assets/fonts/*"]
});
const timeline = new tl.Timeline(scene);
トゥイーンを適用する警告用の赤い背景 warning
は、blockContainer
が生成された直後に作成します。
const blockContainer = new g.E({
scene
});
scene.append(blockContainer);
// 残り時間が少ないときの警告表示
const warning = new g.FilledRect({
scene,
cssColor: "#f00",
x: 0,
y: 0,
width: game.width,
height: game.height,
opacity: 0 // 初期状態は透過
});
scene.append(warning);
opacity
に 0
を設定することで、エンティティを透過状態にしています。
残り時間の更新処理で、トゥイーンを使って警告用の背景を明滅させます。
// 残り時間の更新
const timer = scene.setInterval(() => {
remainingTime--;
if (remainingTime === 0) {
...
} else if (remainingTime === 10) {
const tween = timeline.create(warning, {
loop: true, // ループを有効にする
});
// 警告用の明滅トゥイーンの作成
tween
.to({ opacity: 0.2 }, 300) // 300 ミリ秒で透過度 20%
.to({ opacity: 0 }, 300) // 300 ミリ秒で透過度を 0% に
.wait(400)
.call(() => {
if (remainingTime === 0) tween.cancel(); // 終了したらトゥイーンを終了
});
}
updateTimer();
}, 1000);
remainingTime
が 10
になったときに警告の表示を開始します。
トゥイーンの生成には timeline.create()
を用います。 第1引数には対象のエンティティを、第2引数にはオプションを指定します。 オプションで loop
を true
にしているため、トゥイーンアニメーションが繰り返し再生されます。
戻り値である変数 tween
に、実際のトゥイーンの変化をメソッドチェーン形式で定義します。
to()
メソッドはエンティティの指定されたプロパティを変化させるためのもので、ここでは opacity
を指定しています。 第2引数には変化にかかる時間をミリ秒単位で指定します。
wait()
メソッドは指定のミリ秒だけトゥイーンを一時停止します。
call()
メソッドは任意の関数を呼び出すもので、残り時間 remainingTime
が 0
になったとき、トゥイーンをキャンセルして警告用の表示を停止します。
以上から、このトゥイーンは以下のような挙動を示します。
warning.opacity
を300
ミリ秒かけて0.2
に変化させるwarning.opacity
を300
ミリ秒かけて0
に変化させる400
ミリ秒待機するremainingTime
が0
であればトゥイーンをキャンセル、そうでなければ 1. へループ
これで警告表示を実現できました。
akashic-timeline には他にも様々な機能が備わっています。 詳細については ガイド文書 や API リファレンス を参照してください。
TIP
Akashic Engine が提供する拡張ライブラリとして、二次元の物理エンジンをサポートする akashic-box2d、複数行の文字表示をサポートする akashic-label など他にも多くのものがあります。
また、もちろん開発者自身で拡張ライブラリを作成することもできます。 詳細については 拡張ライブラリを使う も参照してください。
完成したゲームとソースコード
おわりに
おつかれさまです! 以上で「ブロックくずしをつくろう」のチュートリアルは終了となります。 本チュートリアルを通してゲーム開発に興味が湧いたのなら、ぜひ Akashic Engine を使って自身のゲームを作成してみましょう。
冒頭でも説明した通り、作成したゲームはニコニコ生放送上で遊ぶことができます。 ニコ生ゲームを投稿しよう から、実際に作成したゲームをニコニコ生放送上で遊ぶための手順を確認することができます。
今回作成したゲームは一人プレイのものですが、Akashic Engine を使うと放送者と視聴者が参加できるマルチプレイのゲームも簡単に作成することができます。 マルチプレイのゲームを作成するためのガイドについては ニコ生ゲームを作ろう » マルチプレイゲーム を参照してください。
その他ニコ生ゲームを作る際の情報については ニコ生ゲームを作ろう にまとまっています。 ニコ生ゲームを作成する際には、これらのページも併せて参照してください。