レベル 1 から作るゲームのクエスト手帳
Author : Sheng Hsia Leng, 石井 宇大
ゲームな皆さんこんにちは、Game Solutions Architect の Leng (@msian.in.japan) と Game Developer Relations の Taka (@takahiroishii_) です。
この投稿ではゲームのバックエンドを初めてクラウド化させようと考えていて、オンラインゲームを作成する上で Amazon DynamoDB のデータ設計の基礎を学んでみたい、もしくは DynamoDB をゲームから学びたい、そんな皆さんへ向けて、初めてでもすぐにゲームデザインに合ったテーブル設計ができる事を目指す冒険を記した記事になります。
ゲーム開発者向けのその他の記事はこちら
- 選択
- Amazon DynamoDB で作るサーバーレスなゲーム用アチーブメントマイクロサービス
- AWS の知識ゼロから始める AWS GameKit
- Amazon GameLift を使って「最短」でマルチプレイヤーゲームを作る
- Amazon DynamoDB で作るサーバーレスなゲーム用フレンドマイクロサービス
- Amazon GameSparks でインフラを意識せずにゲームのバックエンドサービスを開発しよう
- 魔法で作る Amazon DynamoDB の 簡単ゲームインベントリ
- レベル 1 から作るゲームのクエスト手帳
- サーバーレスなゲームのギルド検索
- 一緒に学び考える ! ゲームの AI/ML 活用
- 3 ステップで始める AI モデル開発 ! 始める前に知っておくべきコト !
- 実践 ! 機械学習でゲームの休眠ユーザーを予測してみよう
- Amazon GameLift Anywhere でサクッとマルチプレイゲームを開発しよう
- ゲーム分析を Amazon Aurora と Amazon Redshift の Zero-ETL 統合ではじめよう
- Amazon Redshift を活用したゲームの行動ログ分析
- Amazon QuickSight によるゲーム分析ダッシュボードの構築
- 品質管理に生成 AI は使えるのか !? テキストチェックを生成 AI にやらせてみた
- 生成 AI を用いたヘルプソリューションを作成する
- 世界に 1 つだけの AI アシスタント作成 ~オリジナルにカスタマイズ
- マルチモーダルな生成 AI 活用の入門編! - 画像認識と画像生成
- Amazon S3 と Amazon CloudFront を活用したグローバル向けゲームビルドバイナリ共有環境の構築
- Terraform を利用した Amazon EKS の構築
- Amazon Bedrock でゲームの BGM を作ってみました !
- Amazon EC2 ではじめる Unreal Engine Pixel Streaming 入門
- Agones on Amazon EKS で構築するマルチプレイゲームの専用ゲームサーバー
- AWS Summit Japan 2024 Game Industry Booth の舞台裏
AWS for Games
AWS for Games ではより早い開発、よりスマートな運営、そしてより楽しいゲームへの成長という Build、Run、Grow の 3 つの柱に沿ってサポートします。本日は Run の柱、そして ゲーム向けデータベース のお話になります。
Amazon DynamoDB とゲーム
Amazon DynamoDB はハイパフォーマンスなアプリケーションを様々な規模で実行できる、フルマネージドかつサーバーレスの Key-Value 型 NoSQL データベースです。そんな DynamoDB とゲームの相性を考える上で、まずは DynamoDB の代表的な特徴をあげます
- Key-Value データベース : キーと値というシンプルな管理方法でデータを格納
- 高いスケーラビリティ : 一貫性のある高速パフォーマンスを自動でスケールしながら実現
- 低い管理負担 : バージョンアップやメンテナンスのような作業が不必要
次にそれぞれの特徴とゲームの相性を見ていきましょう
- Key-Value データベース : プレーヤー主体であるゲームのデータベースのキーはほとんどがプレーヤー ID
- 高いスケーラビリティ : 突然人気が出たり、時間帯で総プレーヤー数が著しい変化するのがゲーム
- 低い管理負担 : 管理負担を減らす事でゲーム本来の面白さを作る事に集中できる
どの DynamoDB の特徴もゲームと非常にマッチしていて高いシナジーがある事がわかります。
Amazon DynamoDB のコンポーネント
この記事では DynamoDB の基本的な機能にフォーカスし、テーブル設計をより簡単にイメージできる事を目指します。その中で出てくるいくつかの DynamoDB のコアコンポーネント があるので先に確認しておきましょう !
- テーブル (Table) : RDB や他のデータベース同様、データのコレクションをテーブルと呼びます
- 項目 (Item) : 各テーブルに入っている識別可能な属性のグループです。RDB でいう行にあたります
- 属性 (Attribute) : 各項目は1つ以上の属性で構成されます。RDB でいう列にあたります
次に Key-Value 型である DynamoDB の Key の部分に当てはまるコンポーネントです。各テーブルはキーを指定して作る必要があり、そのテーブル内の 2 つの項目が同じキーを持つことはありません。このキーをプライマリキー (Primary Key) と呼びます。
更に、DynamoDB は 2 種類の異なるプライマリキーをサポートします。
- パーティションキー (Partition Key) : パーティションキー、通称 PK という 1 つの属性で構成されたシンプルなプライマリキー
- パーティションキーとソートキー (Sort Key) の組み合わせ : PK とソートキー、通称 SK という 2 つの属性で構成された複合プライマリキー
シンプルな Key-Value として 1 つの属性でプライマリキーを作り管理することも多いですが、2 つのキーである PK と SK を組み合わせることで同じ PK に複数の SK を紐付け複数の項目を持たせるケースも様々場面で便利になります。
最後に代替キーを使用してテーブル内のデータのクエリを行うことができるセカンダリインデックスです。DynamoDB では 2 種類のインデックスをサポートしていますが、今日はその中の 1 つにフォーカスします。
- グローバルセカンダリインデックス : 通称 GSI という独自の PK 及び SK を持つインデックス
GSI では元のテーブルの PK 及び SK の組み合わせと異なるキーを新たに設定することで、本来のテーブルから行う場合と同じように別のキーでデータを読み取ることができます。
この他にも Amazon DynamoDB は沢山の機能を持ち合わせています。詳しくは 公式ドキュメント を参照してください !
クエスト手帳の定義
では早速冒険に出る準備をしたいと思います。
まず今日作るゲームのクエスト手帳とは何を指すのか、クエストを管理するとはどういう事か確認していきます。
クエスト
一般的にゲーム内の「クエスト」とは、プレーヤーがゲームの中で冒険に出る際に達成できる課題や目標の事を指します。例えば RPG のようなゲームの場合、シナリオに沿ったクエストが準備されていて、プレーヤーは順番にクエストを達成する事で物語が進み、また新たなクエストそしてシナリオを解放して行くといった感じです。
クエストの中身は前もってゲームのデザインの段階で細かく設定されており、プレーヤーは新しいクエストを解放する事で、初めて達成の条件や報酬を知るといった仕組みも少なくないと思います。1 つのクエストに対していくつかの一般的な要素があるので確認しておきます。
- クエストのタイトル : クエストの短いサマリーのような役割を果たし、時には物語を盛り上げる大事なコンポーネントです。
- クエストの内容 : ゲームによって内容は異なります。あるゲームでは特定のモンスターの討伐だったり、はたまたアイテムを村人に届けるなどの所謂おつかいのような物もあります。
- クエストの報酬 : ゴールド 10 個とシルバー 5 個など、プレーヤーからすると最も大切なのがクエストの報酬です、これを見てクエストに挑むかどうか決めるプレーヤーも少なくは無いと思います。
- クエストの状態 : 達成や未達成という状態です。ゲームによっては達成したものでも再び挑めるクエストもあるでしょう。
他にもクエストには解放条件であったり、制限時間などゲームによって様々な要素を持ったクエストがあるでしょう。今回はよりシンプルに分かりやすくするために上記の 4 つの要素を中心にデータとして管理するクエスト手帳を作ります。
クエスト手帳で管理
クエスト手帳で見られるものもゲームによっては様々です。解放していないクエストは見えない手帳、達成途中にあるクエストはハイライトされている手帳、チャプターや物語の節目に合わせて分けられているものもあります。
今回はクエストの定義に合わせて以下の 4 つのアクションが出来る手帳を作っていきます。
- 全クエストの一覧が見られる
- チャプターによって分かれたクエスト一覧が見られる
- 特定のクエストを選ぶ事で、そのクエストの報酬を含む詳細が見られる
- ゲームのトップ画面で進行中のクエスト一覧が見られる
最後の機能に関してはクエスト手帳からは少し離れますが、プレーヤーがゲームに戻った時にすぐ進行中のクエストの一覧が見えると冒険の意欲が上がるので追加しました。
オンライン対戦機能のついたゲームの場合、クラウド上にサーバーを置くことは必然となり、またオフラインメインのゲームでもクエスト手帳をクラウド上に保存し管理することでプレーヤーのデータが守られ、マルチプラットフォームな環境でも簡単にプレーヤーは遊ぶ媒体を変更することができます。
このように様々な理由でゲームのクラウド化を考える方は少なくないでしょう。管理の少ない DynamoDB だからこそ、普段は手をかけることなくプレーヤー体験を向上させることができるというのも大きな利点になります。皆さんもそんな DynamoDB という武器を持った冒険者になって、ゲームをあっという間に作っちゃいましょう !
ゲームスタート !
前置きが少し長くなりましたが、いよいよ作業を開始したいと思います !
DynamoDB のテーブル設計をしていく際、"アクセスパターンからテーブルは設計する” といったアドバイスを聞いたことのある方も多いでしょう、実際に公式ドキュメントにも 2 つの重要な概念 の 1 つとして紹介されています。いまいちこの概念の意味が理解できない方や初めて聞いたという方も安心して下さい ! ここからは皆さんが慣れているゲーム開発のフローに合わせて紹介させていただきます。
テーブル設計までの流れ
ゲームに置けるアクセスパターンとはずばり、ゲームデザインです。ゲームデザインとはゲームを面白くさせるために様々なアイディアを出しどんなゲームになるか設計していく作業のことです。テーブルを設計していく前にまずは、何を管理するのか、どんな情報が必要か、その情報を取得したり付与するゲームの UI/UX はどんなものになるのか、その UI/UX を支えるのに必要な API はどんなものになるのか、といった内容を考え決定した後にテーブル設計に取り組みます。
ゲームデザインを決める
管理する情報を決める
実際にデータとして保持する情報は上で説明したクエストの定義とほとんど同じものになります。
- 持ち主であるプレーヤーの ID
- クエストの ID (プレーヤー空間でユニーク)
- クエストのタイトル
- クエストの内容
- クエストが所属するチャプター
- クエストの報酬
- クエストの状態
プレーヤー ID 及びプレーヤー情報はすでに何かしらの方法で管理されているものとします。
UI/UX を決める
クエスト手帳で管理できるアクションを言葉では並べてみたものの、やはり実際のゲーム画面、つまり UI/UX が決まらないと細かいデザインはできません。
そこで実際に簡単な RPG ゲームをイメージして、クエスト手帳に関連した UI/UX を決めていきます。
今回使う画面は全部で 5 つ用意しました。
- トップ画面
- 全クエスト画面
- チャプター選択画面
- チャプター詳細画面
- クエスト詳細画面
この 5 つの画面は、それぞれが今回決めたクエスト手帳の管理アクションを実行できるように、そしてプレーヤーが自然とそのアクションを行えるように作られています。
さらに 5 つの画面をプレーヤーが図の中にある矢印の順に移動できるとします。例えばトップ画面からチャプター選択画面へは右下の ”手帳” のボタンを押すことで進むことができ、トップ画面の右の進行中クエストからは直接クエスト詳細画面へ進むことができるとしましょう。今回はレベル 1 の UI/UX となっているので ”戻るボタン” や ”スライドバー” はありません。
必要な API を決める
UI/UX が決まってくると必要な API は自然と決めやすくなります。まずは各画面に必要なクエスト情報を精査します。
- トップ画面 : 進行中のクエストのタイトルとチャプター
- 全クエスト画面 : 全クエストの全情報
- チャプター選択画面 : 3 つの固定されたチャプター (クエスト情報ではない)
- チャプター詳細画面 : チャプターに紐付いているクエストのタイトルと状態
- クエスト詳細画面 : 特定のクエストの全情報
次に各矢印をたどって行き、本当に API が必要か、すでに情報を持っていないか確認していきます
- トップ画面から進行中のクエスト詳細画面へ行くには指定したクエストを取得する API の呼び出しが必要
- トップ画面から全クエスト画面へ行くには全クエストを取得する API の呼び出しが必要
- トップ画面からチャプター選択画面へ行くには API 呼び出しは不要
- チャプター選択画面からチャプター詳細画面へ行くにはチャプターに紐付いているクエストの一括取得が必要なので API の呼び出しが必要
- チャプター詳細画面からクエスト詳細画面へ行くには指定したクエストの詳細を取得する API の呼び出しが必要
以上を踏まえた最終 API リストが以下になります。
GET : /quests/all/playerId
ある 1 人のプレーヤーの全てのクエストを取得する API
GET : /quests/chapter/playerId/chapterId
ある 1 人のプレーヤーのあるチャプターの全てのクエストを取得する API
GET : /quests/inProgress/playerId
ある 1 人のプレーヤーの全ての進行中クエストを取得する API
GET : /quests/playerId/questId
ある 1 人のプレーヤーのある 1 つのクエストの詳細情報を取得する API
テーブル設計
しっかりゲームデザインが出来上がったところで、定義された内容からテーブル設計をしていきたいと思います。以下の手順で設計していきます。
- まずはテーブルの名前を決める
- PK を考える
- 誰/何に紐付いている情報でか考える
- SK が必要か考える
- PK だけで管理できそうか考える
- データ型 を決める
- GSI が必要か考える
まずはテーブルの名前を決める
クエスト手帳ということで、ズバリ Quests に決めましょう !
PK を考える
クエスト手帳の中身はプレーヤーに紐付いています、なので PK は管理主であるプレーヤーの ID、playerId にします。
SK が必要か考える
PK だけで管理できそうか考えます。今回のゲームデザインの中にある API のリストには特定のクエストを取得する API があるので、SK をクエスト ID に設定し、プレーヤー ID とクエスト ID の組み合わせのプライマリキーを作ります。
データ型を決める
次にデータ型を決めます。プレーヤー ID やクエスト ID、そしてクエストのタイトルなどは、基本的なスカラー型である文字列型を選びます。しかしクエストの報酬だけは何か別の型を使うと便利そうですね。ゲーム内のクエストは、クエストによって報酬の数や種類が異なるという特徴があります。スカラー型の文字列などで表現することももちろんできますが、より直感的なデータ型であるドキュメント型を使いましょう。ドキュメント型では複雑な構造を表すマップを使うことが可能です。クエスト報酬をマップで表現する事で、ゴールドが 10 個、シルバーが 5 個などの報酬の対象とその数のペアのコレクションをニーズに合わせて設定する事ができるでしょう !
GSI が必要か考える
PK と SK を使って、1 人のプレーヤーの全クエストを取得することや特定のクエストの取得は可能となりました。しかし、今回のゲームデザインに含まれる 2 つの API、チャプター毎のクエスト取得と進行中のクエスト取得を行うには、このままでは全件取得をした後に、並び替えやフィルターといった作業が必要になってしまいます。ここで使えるのが GSI です。おさらいですが、GSI では元のテーブルの PK および SK の組み合わせと異なるキーを新たに設定することができます。つまりそれぞれ 2 つの API 用に新たなインデックスを作成することで、フィルター無しで必要な情報だけを取得することができるのです。それぞれ決めていきましょう。
- チャプター毎のクエスト取得 : プレーヤーに紐付いており、PK は引き続きプレーヤー ID、SK はチャプター毎で取得したいので、クエストが所属するチャプターを選択
- 進行中のクエスト取得 : プレーヤーに紐付いており、PK は引き続きプレーヤー ID、SK は進行中かどうかを判断するためのキーとして使いたいので、クエストの状態を選択
これらを踏まえて、以下のようなクエスト手帳のテーブル Quests が完成します ! 例となるデータも入れてみました。
GSI の確認
2 つ GSI を設定したので、それぞれがゲームデザインを満たしているか確認します。
まずは 1 つ目の GSI である ChapterIndex です。ChapterIndex では PK がプレーヤーの ID、SK がチャプターとし、属性の射影 は INCLUDE とし今回のチャプター詳細画面に必要な title と status を射影する属性として追加します。なお、元テーブルのパーティションキーとソートキーは常にインデックスに射影されるため、以下の図には記載がありません。
完成したインデックスは以下のようになります。今回の例では射影する属性を減らしストレージのコストを抑えたやり方を選んでいますが、ゲームデザインが定まらない内は ALL に設定しクエリ時に ProjectionExpression 側で属性を絞ることも可能です。この属性を絞る ProjectionExpression は SQL でいう SELECT 句に似たものになります。
このインデックスを使い、ある 1 人のプレーヤーのあるチャプターの全てのクエストを取得する API を構築することで、ゲームデザイン内のチャプター詳細画面を完成させることができます。実際に使うクエリの中身は以下のような内容になるでしょう。以下のサンプルコードは Typescript を使用して記載しています。
const queryInput: DocumentClient.QueryInput = {
TableName: "Quests",
IndexName: "ChapterIndex",
KeyConditionExpression: "playerId = :playerId and chapter = :chapter",
ExpressionAttributeValues: {
":playerId": "player1",
":chapter": "Mountain",
},
};
const result = await dynamodb.query(queryInput).promise();
クエリの内容を説明すると、上から TableName でテーブルの指定、 IndexName を使い GSI の指定、そして KeyConditionExpression の中で PK と SK を指定する事で ChapterIndex に対して特定のプレーヤーとチャプターで情報を取得しています。
ExpressionAttributeValues とは KeyConditionExpression の文字列の中にプレースホルダー ( : で始まる値) として定義した属性値を比較する実際の値、つまりランタイムまで分からない可能性のある値の代わりに指定する際に使うものです。今回は特定の値が決まっていますが、例として記載しています。
次に 2 つ目の GSI である StatusIndex です。StatusIndex では PK がプレーヤーの ID、SK がクエストの状態を示す status とし、こちらも属性の射影は INCLUDE とします。トップ画面では title と chapter のみの表示になるので、この 2 つの属性のみ射影します。
このインデックスを使い、status を inProgress に指定することで、ある 1 人のプレーヤーの全ての進行中クエストを取得する API を構築することができ、ゲームデザイン内のトップ画面を完成させることができます。以下はこのインデックスへのクエリの例です。
const queryInput: DocumentClient.QueryInput = {
TableName: "Quests",
IndexName: "StatusIndex",
KeyConditionExpression: "playerId = :playerId and #status = :status",
// status は reserved kyword なのでExpressionAttributeNames で定義する
ExpressionAttributeNames: {
"#status": "status",
},
ExpressionAttributeValues: {
":playerId": "player1",
":status": "inProgress",
},
};
const result = await dynamodb.query(queryInput).promise();
2 つ目のクエリは最初のクエリととても似ています。 1 つだけ追加されている物が ExpressionAttributeNames です。コメントとして記載していますが、DynamoDB は status という言葉を reserved keyword として保持しているので、今回のような属性の名前に使ってしまっている場合は KeyConditionExpression 内で属性名用のプレースホルダー( # で始まる値) を使用し、ExpressionAttributeNames 内でそのプレースホルダーの本当の値を定義します。
ここまでレベル 1 の冒険お疲れさまでした !
これで UI/UX からデザインしたクエスト手帳を構築するのに必要な DynamoDB のテーブル設計が見事に完了しました!
拡張性
レベル 2 を目指している冒険者の方は、今回行わなかったチャプターの管理も同じ DynamoDB のテーブルで行うことに挑戦してみてください。クエリのキー条件式である begins_with を使うことで、同じテーブルの中に種類が異なる複数のデータを入れておくことができます。
キー条件式の詳しい内容がみたい方、そしてゲームを作るためにもっとレベルアップを目指している方は 魔法で作る Amazon DynamoDB の簡単ゲームインベントリ をご覧ください !
まとめ
ゲームの裏側として採用が増えている Amazon DynamoDB を使ったテーブル設計を、ゲームデザインを元にゼロからやってみました。
なお、今回ご紹介した DynamoDB のゲームでの活用例やその他のデータベースに関する様々な情報は、ゲーム開発者の皆さん向けに AWS for Games のゲーム向けデータベース のページでまとめて確認できるようになっています。是非皆さんのゲームにあったデータベースを選んで、楽しいゲーム開発にお役立てください !
ゲーム開発者向けのその他の記事はこちら
- 選択
- Amazon DynamoDB で作るサーバーレスなゲーム用アチーブメントマイクロサービス
- AWS の知識ゼロから始める AWS GameKit
- Amazon GameLift を使って「最短」でマルチプレイヤーゲームを作る
- Amazon DynamoDB で作るサーバーレスなゲーム用フレンドマイクロサービス
- Amazon GameSparks でインフラを意識せずにゲームのバックエンドサービスを開発しよう
- 魔法で作る Amazon DynamoDB の 簡単ゲームインベントリ
- レベル 1 から作るゲームのクエスト手帳
- サーバーレスなゲームのギルド検索
- 一緒に学び考える ! ゲームの AI/ML 活用
- 3 ステップで始める AI モデル開発 ! 始める前に知っておくべきコト !
- 実践 ! 機械学習でゲームの休眠ユーザーを予測してみよう
- Amazon GameLift Anywhere でサクッとマルチプレイゲームを開発しよう
- ゲーム分析を Amazon Aurora と Amazon Redshift の Zero-ETL 統合ではじめよう
- Amazon Redshift を活用したゲームの行動ログ分析
- Amazon QuickSight によるゲーム分析ダッシュボードの構築
- 品質管理に生成 AI は使えるのか !? テキストチェックを生成 AI にやらせてみた
- 生成 AI を用いたヘルプソリューションを作成する
- 世界に 1 つだけの AI アシスタント作成 ~オリジナルにカスタマイズ
- マルチモーダルな生成 AI 活用の入門編! - 画像認識と画像生成
- Amazon S3 と Amazon CloudFront を活用したグローバル向けゲームビルドバイナリ共有環境の構築
- Terraform を利用した Amazon EKS の構築
- Amazon Bedrock でゲームの BGM を作ってみました !
- Amazon EC2 ではじめる Unreal Engine Pixel Streaming 入門
- Agones on Amazon EKS で構築するマルチプレイゲームの専用ゲームサーバー
- AWS Summit Japan 2024 Game Industry Booth の舞台裏
筆者プロフィール
Sheng Hsia Leng
アマゾン ウェブ サービス ジャパン合同会社 ソリューションアーキテクト
ゲーム業界に特化したソリューションアーキテクトとしてお客様を支援しております。
RPG とドット絵ゲームが好きです。オフモードの時はインスタでバイリンガル漫画を投稿しています。
石井 宇大
アマゾン ウェブ サービス ジャパン合同会社
ゲームデベロッパーリレーションズ
カナダ🇨🇦 で 10 年以上生活していたゲームで遊ぶのも作るのも好きな元ゲームエンジニア。趣味は奥さんと季節を感じながら美味しい物を食べ大好きな赤ワイン🍷 を嗜む事。
普段は楽しいゲーム作りに繋がるよう、様々なソリューションを提供するお仕事をしています。
AWS を無料でお試しいただけます