Rustで簡単な卓球ゲームを実装する -その1-
前書き
現在、Rsutで業務アプリケーションを開発中。
まずは勉強がてら、Rustで簡単なゲームをり、言語の特性などを理解したい。
というのが背景で今回は簡単なゲームを開発することにした。
ちなみに筆者はプログラミングの経験は皆無で、Rustを触るのが初めてなので色々と間違っている箇所がこの後に出てくるかもしれません。
その際は間違いをコメントで指摘していただけますと幸いです。
今回、このゲームを実装するにあたって以下のサイトを参考にさせていただきました。
参考サイト:https://tetra.seventeencups.net/
【このチュートリアルで実装するゲームイメージ図】
前提
このゲームを開発するには以下の環境が必要です。
Linuxの場合は特別にALSA development librariesというものが必要みたいなのですがここでは触れません。上述の参考サイトに詳細がありますのでLinuxの場合は参考サイトへ。
OS:Mac
rustc: 1.46.0 //Rustのコンパイラ。大体はcargoでコンパイルするのであまり使うことはない
cargo: 1.46.0 //ビルド&パッケージ管理ツール。よく使う
rustup: 1.22.1 //Rustのバージョン管理などのツール
sdl2: 2.0.12 //マルチメディア(音や画面の出力など)クロスプラットフォームライブラリ。このライブラリを利用してゲーム画面の描画を行う。
SDL2のインストールについては下記のサイトを参考にすると良いかと思います。
参考サイト:https://gist.github.com/aita/28fef7fa91fce3122b1005ae5d34a7ef
プロジェクト作成
cargoで新規プロジェクトを任意のディレクトリに作成。
この手のゲームはどうやら「pong」と外国で言われているみたいですので、
pongというプロジェクト名を使用します。(参考サイト通り)
cargo new --bin pong
cd pong
プロジェクトを作成したらCargo.tomlの[dependencies]以下に
[dependencies]
tetra = "0.5"
と記述してください。今回はこの「tetra」クレートを使用してゲームを開発します。
[dependencies]についてですが、 Rustでは、パッケージのコードをクレートとして参照します。そのためプロジェクトの依存関係をこちらに列挙する必要があります。
クレートについてはライブラリと同義だと考えて問題なさそうです。
ちなみに、以下のサイトで世界中のプログラマーが作成したクレートを参照できます。
ゲーム画面の表示
次に、main.rsファイルの最上部に以下の2行を付け足して今回使用するモジュールを宣言しておきます。(後々使用するモジュールは増えます)
use tetra::graphics::{self, Color};
use tetra::{Context, ContextBuilder, State};
1行目のuse宣言はゲーム画面の背景色を設定するのに必要なモジュールです。
2行目のuse宣言はよくわかっていませんが、とりあえずグラフィックを描画したりプログラムの状態を保持するためのモジュールらしいです。
次にこのゲームを起動する際の関数を記述します。
fn main() {
ContextBuilder::new("Pong", 640, 480)
.quit_on_escape(true)
.build();
}
ContextBuilder::newでゲーム名とウィンドウサイズを指定します。
.quit_on_escapeなどのメソッドは任意で記述できますので詳しくは以下の公式サイトを参照してください。
https://docs.rs/tetra/0.5.0/tetra/struct.ContextBuilder.html
この状態でcargo runを実行すると一瞬(早すぎて画面が開いたかを確認することができません笑)だけ画面がポップアップされますがゲームの状態を保持していないためすぐに画面を閉じてしまいます。
そのためState文で状態を記述してあげる必要があります。
現状ではデータを保存したりする必要がないため空の構造体を作成します。
struct GameState;
impl State for GameState {}
構造体の宣言はstructで行います。構造体名は任意です。
この構造体に後々、メソッドを追記したいのでimplを記述しておきます。
impl State のStateはゲームの状態を更新して画面に色々と描画するためのロジックを提供するトレイとです。ゲームロジックはここに記述していきます。
このStateはResultを戻り値としてデフォルトで返してくれます。?演算子を明示的に記述して戻り値を返すことも可能、みたいです。
この後にmain.rsにrunというメソッドを記述することによっておそらくインスタンス化がされる、のだと思います。仮にエラーが返された場合はゲーム画面が閉じるみたいです。
そしてこのrunによってゲームは実行されます。runの後には「;」がないため戻り値が自動的に返されます。
ということでゲーム画面を表示するソースを追記します。
fn main() -> tetra::Result {
ContextBuilder::new("Pong", 640, 480)
.quit_on_escape(true)
.build()?
.run(|_ctx| Ok(GameState {}))
}
現時点で記述したソースをcargo runするとおそらく黒い画面が表示されます。
試してみて下さい。
画面の装飾
次にStateトレイとのメソッドを利用してゲーム画面の背景をいじってみます。structの下の方に以下のimplを記述してください。
impl State for GameState {
fn draw(&mut self, ctx: &mut Context) -> tetra::Result {
// Feel free to change the color to something of your choice!
graphics::clear(ctx, Color::rgb(0.392, 0.584, 0.929));
Ok(())
}
}
draw関数は画面を描画する際にコールされる関数です。
最終的なソースコード
use tetra::graphics::{self, Color};
use tetra::{Context, ContextBuilder, State};
fn main() -> tetra::Result {
ContextBuilder::new("Pong", 640, 480)
.show_mouse(true)
.quit_on_escape(true)
.build()?
.run(|_ctx| Ok(GameState {}))
}
struct GameState {}
impl State for GameState {
fn draw(&mut self, ctx: &mut Context) -> tetra::Result {
graphics::clear(ctx, Color::rgb(0.392, 0.584, 0.929));
Ok(())
}
}
個人的にはマウスポインタが画面に重なった時に見えなくなる仕様が気に入らないので、show_mouseメソッドを追記しています。
上記のソースコードでcargo runして画面が表示されればOKです。
次回
このゲームのラケット?的なものを画面上に表示し、動かすところまでやりたいと思います。
この記事へのコメントはありません。