2Dゲームを作ってみたというお話
作ったもの
下記のように実行すると、ゲームマップが現れ、ゲーム開始。
$./so_long_bonus map.ber
player(勇者)を操作して、enemy(ドラゴン)から逃げながら、
collectible(光)を集めてexit(ダークサイドっぽいやつ)まで移動させてる。
一応enemyからはギリギリぶつからず逃げ切った。笑
wall(木)を通り抜けることはできない。
移動はW,A,D,S keyで。
- so_long_bonus : 今回作った実行ファイル 。
- map.ber : マップのソース。ゲームスタートの際の各マスの配置(enemyの配置はプログラム側で決める)。
- 0 : empty
- 1 : wall
- C : collectible
- E : exit
- P : player
$cat map 1111111111111 10010000000C1 1000011111001 1P0011E000001 1111111111111
ざっくりとした流れ
まず、今回マップの表示はXサーバを利用している。
そんでもってXサーバを利用する上で便利なライブラリ(今後使うmlx系関数はここから)が事前に用意されている。
1. マップのソースを引数で受け取り、読み込む、(Xサーバの)windowで表示するためのマップ情報を用意する。
2. mlx系関数を使ってwindowに表示するための情報を用意する(各マスの画像の用意など)
3. マップを表示させる。
主に使った関数
- mlx_init
Xサーバを利用するために必要な情報を持った構造体のポインタを返してくれる。 - mlx_xpm_file_to_image
xpmファイル(今回だと事前に用意した各マスの画像)を元にimage情報を持った構造体のポインタを返してくれる。 - mlx_new_window
使用するwindowの情報を持った構造体のポインタを返してくれる。 - mlx_put_image_to_window
window内の指定した位置にimageを表示してくれる。 - mlx_loop
事前に指定した関数(例えば、マップを表示する関数)を実行するなどの、ループ処理をしてくれる。
= プログラムが終了処理をするまで、マップを表示し続けてゲームを続行する。 - mlx_loop_hook
mlx_loop内で、実行する関数を指定できる。 - mlx_key_hook
mlx_loop実行中に、keyを押された際に実行する関数を指定できる。 - mlx_hook
mlx_loop実行中に、red cross(xボタン)を押された際など特定のイベント発生時に実行する関数を指定できる。
プログラムの流れ
各情報の用意
- 今回あらゆる情報を構造体(t_data *data)にまとめるので、構造体の初期化
- 引数で受け取ったmap.berの読み込み、中身のチェック
map.berの内容をint型の二次元配列data->mapに落とし込む(そっちの方が扱いやすく思えた) - imageやwindowを用意やら、enemyの位置をmapに追加やらの準備
- loopに入る前に各関数をセット
- keyが押された際にplayerの移動などマップの情報を書き換える関数をmlx_key_hookに渡す
- red crossが押された際にプログラムを終了させる関数へ繋ぐ関数をmlx_hookに渡す
- loop内で繰り返す関数(マップの表示、enemyを動かす、アニメーションを動かす)をmlx_loop_hookに渡す
loop実行
基本的に、マップ情報を元にimageを表示する処理(put_map)が常に一箇所で動いていて、
表示内容を変える場合はマップ情報の書き換えのみ他の関数で行っている。
imageの管理と表示について
windowに表示するimageは三次元配列で管理していて、
以下の情報を元に配列内のimageにアクセスして、それを表示させている。
- data->map(マップ情報、どのマスなのか、playerのマスなのか、emptyのマスなのか)
- data->square_side(どの向きなのか、playerは右向きなのか上向きなのか)
- data->square_act(どの動きなのか、これは向きに加え4種類の動きを用意している)
下の図は表示したいマップの位置のマスがENEMYで、向きは右向き、動きは2番の時の例
マップの情報を書き換えたり、向きの情報を変えたりすれば、マップ表示の際のimage配列へのアクセスが代わり別のimageを表示するので画面に変化が出てくるという仕組み。
さらに動き(data->square_act)の情報を定期的に変更するように関数を動かしておけば、アニメーションのように動きが生まれる。
課題
- 今回各マスに向きやアニメーションの動きを入れるコードを書いたが、結局全画像を用意することに疲れて全ての動きができていない。playerは正面のみだし、enemyは右向きのみ。
- メモリの使用量が200MG近くなったり多いのと、実行速度が環境によってかなり遅い様子。解決方法がないか考え中。
- 同じような文字列多用していたので、defineなど使ってコードをわかりやすくする。