#2 画像の表示 >>
2019/09/02 更新
この記事の内容は2019/09/02現在の最新版amethyst(v0.12.0)についての内容になります。
はじめに
この記事はRust言語とゲーム作成に興味のある大学生が、Rust製のゲームエンジンamethystを使用した備忘録になります。
Rust製のゲームエンジンは有名なものでpistonやggezなどがありますが、amethystに関する記事がQiitaには(そもそもウェブ上に日本語の記事が)ほとんどなかったので、新たに始める方向けに残していこうと思います。
こちらに製作物があります。
今回はexamples/01_create_window
の内容になります。
ronファイル
amethystでは、タイトルやウィンドウサイズなどの情報を設定ファイルとして別に書きだすようになっており、ronファイルという珍しいファイルを用いています。これは"Rusty Object Notation"の略で、Rustのオブジェクトと同じような感覚で書くことができるファイルになっています。詳しくはこちら。
書き方の例
(
title: "amethyst: 01_create_window",
icon: None,
fullscreen: false,
dimensions: Some((500, 500)),
max_dimensions: None,
min_dimensions: None,
visibility: true,
multisampling: 0,
vsync: false,
)
このように、Some
やNone
、タプルを用いて書くことができます。記述しない箇所はデフォルトの設定になりますので、とりあえず必要最低限だけで良いです。
(
title: "amethyst: 01_create_window",
dimensions: Some((500, 500)),
)
main.rs
// examples/01_create_window/main.rs
use amethyst::{
prelude::*,
renderer::{
RenderingBundle,
types::DefaultBackend,
plugins::{RenderToWindow, RenderFlat2D},
},
input::is_key_down,
utils::application_dir,
winit::VirtualKeyCode,
};
struct ExampleState;
impl SimpleState for ExampleState {
fn handle_event(
&mut self,
_: StateData<'_, GameData<'_, '_>>,
event: StateEvent,
) -> SimpleTrans {
if let StateEvent::Window(event) = event {
if is_key_down(&event, VirtualKeyCode::Escape) {
Trans::Quit
} else {
Trans::None
}
} else {
Trans::None
}
}
}
fn main() -> amethyst::Result<()> {
amethyst::start_logger(Default::default());
let app_root = application_dir("assets/")?;
let display_config_path = app_root.join("display_config.ron");
let render_bundle = RenderingBundle::<DefaultBackend>::new()
.with_plugin(
RenderToWindow::from_config_path(display_config_path)
.with_clear([1.0; 4]),
)
.with_plugin(RenderFlat2D::default());
let game_data = GameDataBuilder::default()
.with_bundle(render_bundle)?;
Application::new(app_root, ExampleState, game_data)?.run();
Ok(())
}
では一つずつ簡単に解説します。ExampleState
構造体は最後に解説します。
amethyst::start_logger(Default::default());
これにより、プログラムの情報がコンソールに表示されます。書かないと警告を出してくれますが特に動作に影響はありません。
let app_root = application_dir("examples/01_create_window/")?;
utils
モジュールよりスコープに導入されます。
プロジェクトディレクトリ直下(サンプルの場合はamethyst-example/
)からのパスを引数に与え、PathBuf
として取得します。app_root
の変数名が示すように、アプリケーションのルートをここで用意しておくといろいろ楽になります。もしくはアセットをまとめているディレクトリがおすすめ。
ほかにも、amethyst_utils
クレートには便利な関数が用意されているので気になった人は調べてみてください(→リファレンス)。
因みに、この?
はResult
型に対して用い、Ok(v)
であればv
を取り出し(.unwrap()
)、Err(e)
であればe
を返す(return e;
)糖衣構文です。よく見ると、このmain
関数は返り値がありますね。
let display_config_path = app_root.join("display_config.ron");
let render_bundle = RenderingBundle::<DefaultBackend>::new()
.with_plugin(
RenderToWindow::from_config_path(display_config_path)
.with_clear([1.0; 4]),
)
.with_plugin(RenderFlat2D::default());
display_config.ron
ファイルへのパスを用意し、それを用いてRenderBundle
を作成しています。.with_clear
は画面の初期化に用いる色を、[f32; 4]
型で設定します。
この辺りは複雑な設定を使用するまでは「おまじない」として使ってよいでしょう。
let game_data = GameDataBuilder::default()
.with_bundle(render_bundle)?;
Application::new(app_root, ExampleState, game_data)?.run();
GameDataBuilder
を作成し、with_bundle
メソッドでWindowBundle
のインスタンスを与えます。WindowBundle
構造体の関連関数により、設定ファイルのパスを元に作成しています。
Application
構造体を作成する際、3つの引数を取ります。
1つ目はゲームの場所です。この後amethystによって定義された関数にパスを与える場合ここがルートになります。例えばexamples/01_create_window/sample.ron
を読み込む場合、与えるパスは./sample.ron
もしくはsample.ron
になります。
2つ目は初期のゲーム状態です。ゲームには様々な状態があります(例:待機状態、ゲームプレイ状態、ポーズ状態、終了状態などなど...)。これら状態を表す構造体を今後作っていくことになります。今回のプログラムで用いる状態はExampleState
一つだけです。これはユニット構造体なのでこれでインスタンスを作成できています。もしExampleState(i32)
であれば、ここはExampleState(0)
のように記述する必要があります。
3つ目は、すぐ上で作ったgame_data
を与えています。
今後のmain
関数はこの形がメインになります。
struct ExampleState;
impl SimpleState for ExampleState {
fn handle_event(
&mut self,
_: StateData<'_, GameData<'_, '_>>,
event: StateEvent,
) -> SimpleTrans {
if let StateEvent::Window(e) = event {
if is_key_down(&e, VirtualKeyCode::Escape) {
return Trans::Quit;
}
}
Trans::None
}
}
最後になります。これが先ほど説明に出てきた状態を表す構造体です。
SimpleState
トレイトで定義されている関数はすべてデフォルト実装がなされているので、必要なものだけを再定義します。今回はEscキーで終了する処理を実装します。
is_key_down
関数は指定したキーが押されているか否かを返します。VirtualKeyCode
列挙型のヴァリアントによってキーボードのキーを指定します。
return Trans::Quit;
により、終了状態を伝えてゲームを終了させています。もしキーが押されていなかった場合、Trans::None
が返るため何も起こりません。
以上で完成になります。
cargo run --example 01
で実行してみましょう。真っ白なウィンドウが表示されれば成功です。フォーカスした状態でEscキーで終了させましょう。
終わりに
今後も進捗に合わせて記事を公開していこうと思います。
amethystでのゲーム制作を始めた人が、最初でつまづかないよう手助けになれればと思います。
また疑問や訂正などありましたらコメントしていただければ幸いです。