ArcadeRS サンプルゲームを通じて play-clj に慣れる
ArcadeRSという ゲーム制作を通じての Rust 言語を学ぼうと言うチュートリアル記事がある。
この記事はそのチュートリアルを通じて完成するゲームを play-clj で作ってみようと言う記事。 元記事と違って Clojure そのものは既にある程度学習済で、ここのタイトルにあるように play-clj、引いてはベースとなる libGDX の使い方に慣れるのが主な目的になる。 なので、Clojure 自体の入門や開発環境の構築は他書籍やサイトを参考にして下さい。
この記事を作成するにあたっての開発環境だけは書いておきます。
- Windows7 Pro 64bit
- JDK 7u45(1.7.0_45)
- Clojure 1.8.0
- leiningen 2.6.1
- Emacs 24.5(NTEmacs64 IMEパッチ適用版)
- cider 0.12.0
- play-clj 1.1.0
流れだけは元記事に沿うようにするが、翻訳記事ではないので元記事のリンクを載せたりもしない。
また、後で検索しやすいよう arcade-clj
とタグ付けしておく。
完成イメージ
現在は元記事のスクリーンショットをそのまま持ってきているだけだが完成したら差し替える予定。
と言っても見た目は多分タイトルバーデザインが Windows のものになるだけだと思う。
目次
日本語になっていない所はまだ play-clj 版での記事になっていない部分。 また、機能ベースでタイトルを付けていく予定。
- play-clj のインストール、シンプルなウィンドウの表示 - 日曜プログラミング
- ESC を押したら終了するようにする(イベントハンドリングの触り) - 日曜プログラミング
More event handling, where we discuss macrosViews, where we learn about boxes, pattern matching, trait objects, and dynamic dispatch- 3,4 は Rust の言語機能がメインで、特にゲームとしての機能追加を行ってるわけではないので割愛。
- Screen の 切替 - 日曜プログラミング
- 四角形を動かす、描画する - 日曜プログラミング
- Sprites, where we create our player’s ship
- Backgrounds, where we handle resizing, scale and translate through time
- Main menu, where we play with textures and Rust’s vectors
- Asteroid attack!, where we render animated asteroids
- Shooting bullets, where we explore iterators
- Brawl, at last!, where we make objects interact and explode
- ≪ Boom! ≫, where we play sound.
- Variety, where we create more enemies
- Difficulty, where we manage the difficulty level and the score
- High score & wrap-up, where we play with the file-system and enhance our main menu
目次だけ最初に掲げちゃって大丈夫かと自分でも少し思うが ペースは遅くとも何とか最後までいけるよう頑張ります。
勿論チュートリアルのゲームを完成させるのが一番の目的だけど 記事の方も日本語に置き換えられて*1リンクが貼られれば完成とします。 また、この記事は主に目次なので記事を更新次第リンクとタイトルも更新します。
*1:翻訳じゃなくあくまで機能ベースの置き換え
cider で play-clj 触り始めました
libGDX を Clojure 上でより使い易くされた play-clj 触り始めました。
まだサンプル触ってる段階だけど REPL で起動したままいじれるのは 非ゲーム分野では経験済みとは言えゲームでも可能なのが改めて新鮮。
今日は 公式チュートリアル ではフォローされてない emacs+cider 使った時の補足事項みたいなのをいくつか。
cider で REPL
公式チュートリアルで流れは書かれてるがもう少し細かく言えば ソースをいじって REPL から起動したゲーム画面に反映させるには、
の作業が必要で、1. は1回でいいが、2~4 は繰り返す事になり、 これをコマンド+タイピングで毎度やるのはさすがに煩わしい。
なので emacs にコマンドとしてキー1発で呼び出せるものをてきとーに書いた。
(require 'cider) (defun play-clj-reload () "REPL へ play-clj への反映コマンドを投げる。 hello-world-game と mainscreen は適時書き換える事。" (interactive) (cider-interactive-eval "(on-gl (set-screen! hello-world-game main-screen))")) (defun save->eval->reload () "play-clj での開発用。バッファセーブ→バッファ評価→play-cljのリロードのコンボをまとめて実行する。 sit-for で wait かましているのはあんまり意味ないかも。" (interactive) (save-buffer) (sit-for 1) (cider-load-buffer) (sit-for 1) (play-clj-reload)) (define-key cider-mode-map (kbd "<f5>") 'save->eval->reload)
docstring にも書いたが sit-for は別になくてもいいかも。 まあけどこれでF5一発で画面反映までしてくれるようになるので結構楽になる。
cider-jack-in だとランタイムエラーが出ない?
play-clj(と言うか libGDX) は GL スレッドを 1 個作ってそこでイベントハンドリングするという まあ Swing や JavaFX などと同じような手法を取ってるのだが、この手のものは cider-jack-in した場合別スレッドを立ち上げる為か(詳しくは調べてない)、 例外のメッセージを吐き出さずに止まってしまう事がある。
play-clj はその場合にも対応できる方法を用意してて、set-screen-wrapper!
を使って
例外時は printStackTrace して空の画面を出させるようにするというスニペットをチュートリアルの
一番最後に載せてあり、それを core.clj の一番最後に入れておけば大抵 REPL を再起動せずとも
復帰できるようになる。
ただ、それでも cider-jack-in でコンソールを立ち上げずに REPL 起動した場合だと エラー時もやはりメッセージが出てくれない。
ウィンドウは増えてしまうがコマンドプロンプトから REPL 立ち上げるとエラーメッセージは 出るので個人的にはこちらの方をオススメする。
ちなみにここでも前述した emacs コマンド(F5) で復帰できて便利。
駄文:すいません、Rust 俺にはムリ
まあ誰に謝ると言う訳でもないんだけど Rustはプログラミング言語Rustを 一通り試してみて、さあそれじゃちょっとしたツールやライブラリみたいなの試しに作ってようかと 手を動かしてみたらコンパイラに怒られまくって正直心折れました。
いや、ネイティブコード吐き出す言語はちゃんと手を出した事がなかった分野なんでやってみたかったんだけどね、 トレイト+ジェネリック+静的型システム+ライフタイム辺りのコンボがどうにも辛い。
で、結構な間何も更新してなかったんだけど 今後はまた Clojure に出戻って気がついたような事を書いていきたいと思う。
Clojure も 1.8.0 になったってのを見た後くらいから全然触ってなかった。 またちょっと触りだして思ったのは cider も進化してんなあ、界隈の hot なライブラリ全然知らないなあ、 多少の起動の遅さというデメリット以上に REPL はやっぱり便利過ぎるなあ、などなど。
こんな事思ってる人いないかなあと ググッてこんな記事見つけてみたりしてまた Clojure へのモチベーションを上げてみたり。 postd.cc
ちなみにこの記事は Rust については全く触れてないので注意。
と言うわけで Rust は言語というよりは周りの開発環境的なものが もう少しこなれたらまた手を出すかも、出さないかも。 Winodows だけかもしれんけど racer もやたら固まるしなあ。
以上駄文でした。
環境変数設定画面を直接開く方法
前日本語でググって見つからず諦めてたが今日英語でググッてみたらあった。
と言うわけで以下のような感じでそのままバッチファイルにしたものを PATH 通してる所に放り込んだ。
@echo off rundll32 sysdm.cpl,EditEnvironmentVariables
コマンドプロンプト画面は出るが常時表示させておくものでもないので気にしない。
Rust Win GNU ABI で実際何か作る時は MinGW-w64 の gcc にパスを通しておくのが実質必須と言うお話
今回は Conrod と言う GUI ライブラリのサンプルを動かしてみたくて 試そうとしたら、コンパイルが途中で止まったのが発端。
確認環境
公式ガイドにあるサンプルを動かす Cargo タスクを実行すると外部 Crate のコンパイルで止まった。
cargo run --release --example text
エラーメッセージはもう長くなりすぎるんで省略するけど、
miniz-sys 0.1.7
という Crate のコンパイルで止まっていた。
現象やメッセージがどんなものかと言うのは gcc-rs の issue#7と同じなので 詳しくはそちらをどうぞ。
今回問題の原因は何かと言うと、Cargo は前の記事でもチラッと話題にしたが、
- Cargo にはカスタムビルドスクリプトと言う機能があり、
- Crate によってはそこで更に gcc-rs と言うカスタムビルドスクリプトから C/C++ コンパイラを直接呼ぶ為のライブラリが必要で、
- gcc-rs は Win GNU ABI の場合、MinGW-w64 の gcc に PATH を通している事が必須
と言う事。
ここで一つ疑問なのは Win GNU ABI 版 Rust 同梱の gcc じゃダメなのかと言う事だが *1、 rustc から呼ぶ gcc は主にコンパイル済みライブラリのリンクを目的として使ってて C ソースからコンパイルするにはヘッダファイル等も一緒に入ってないと色々と都合が悪く こういう仕様になってるみたい。Rust 同梱の gcc でも試してみたが確かに動かなかった。 まあ C ソースのコンパイルから必要な Crate だとそうするしかないか。
似たような主旨の事は実は gcc-rs の README にも書かれているんだが、この事は外部 Crate を使わずに何か作るという可能性が低いから 公式でももっと大きく書いておいて欲しいと個人的には思った。 *2
また、リンク先には MSVC 環境の場合もフォローしてるけど自分は GNU ABI でやってるので未確認。
最後に MinGW-w64 の gcc に PATH を通せば最初のコマンドは無事実行できた。
*1:実際 The Programming Language Rust でサンプルコードを試している時は今回の事はなかった→Rust 同梱/MinGW-w64 いずれの gcc にも PATH は通していなかったので
*2:未読のForeign Function Interfaceなどに書いてあったらごめんなさい
Cargo で gcc のフラグを任意に渡す方法→cargo rustc からのみ可能(2016-05-08修正)
要は Windows の GUI サンプルコードをお試しで動かすと コンソールも一緒に立ち上がってたのが嫌だったので調べると見つかった。
で、このフラグを Cargo から渡す方法はないか調べた。
確認環境
2016-05-08修正
申し訳ない、最初に書いた記事は自分の誤読で案について話しているだけで Cargoの設定ファイルで gcc へ任意のオプションを渡す方法は現時点では存在しておりませんでした。
ただ、cargo rustc
からであれば渡せます。
cargo rustc --release -- -C link_args=-Wl,--subsystem,windows
これは簡単なツール作って Windows エクスプローラから exe 起動して コマンドプロンプトが出なくなったのを確認済。
修正前の記事で紹介した
issue#544の件
のはまさしくこの cargo rustc
での機能を実装したよと言う事のみでした。すみません。
↓で見つけた。 github.com
やり方は簡単で、対象のプロジェクトの Cargo.toml に以下の一文を追加する。
[rustc] flags="-C link_args=\"-Wl,--subsystem,windows\""
MSVC ABI だとこの現象が発生しないのかは未確認。
ちなみにissue#544はcargo rustc
タスクでコマンドラインからオプションとして渡す方法がメインの話なのだが、
こちらでやると
前の記事の方法で設定した
追加ライブラリサーチパスが有効にならない。あくまでcargo run
orcargo build
した時だけって事なのかな。
Cargo でグローバルにライブラリサーチパスを追加する方法
Cargo で C ネイティブライブラリをリンクさせる為に 配置されているパスを Cargo に明示的に指示したい場合どうするか。
確認環境*1
プロジェクト単位での設定方法
探すと Qiita でこんな記事が見つかった。
グローバルに設定する方法
今回自分がやりたいのはこちら。
先に紹介した方法でもいいんだけど特に自分のような Windows ユーザだと MSVC/MinGW/Cygwin とかで配置する場所の慣習が変わってくるのと ほぼマルチユーザで使う事はないのでライブラリをインストールしたら プロジェクト単位すら面倒でグローバルに設定したくなる。
で Cargo のドキュメント探してたらあった。
Cargo は設定ファイルを記述する事が可能らしく
*2、
cargo run
や cargo build
実行時はまずその設定を読み込んでくれるらしい。
自分は %HOME% を設定してるので、%HOME%.cargo\config ファイルを配置。 そしてライブラリサーチパスの設定を以下のように書いた。 *3
[target.native] rustc-link-search = ["C:/path/to/lib"]
["C:/path/to/lib"]
は自分がリンクさせたいライブラリが存在するパスを指定する事。
参考
- http://doc.crates.io/build-script.html#overriding-build-scripts
- (推測) リンク先のサンプルは 64bit linux で foo ライブラリをリンクする際のパス指定方法だと思われる
一度このドキュメントはどこかでちゃんと読み込んでおきたいかな。 Tomlファイル自体の形式は分かりやすいんだけど何をどう設定できるのかがあんまり把握できてないし。