ミニDTL.xna “ゲームはイチニチ30分まで!” 第3回
ミニDTL.xnaその3です。
今回は配信にlivestreamを使ってみました。640*480で配信しても24fpsで受信でき、弾が飛んでる様子も僕がビルドエラー起こしている様子も丸見えとなりました。
内容は以下の通り。
自機をクラス化
前回作ったShotクラスと同じ要領でFighterクラスを作り、fighter1変数として持つようにしました。
自機のコントローラ判定はFighter.Updateに任せ、Game1クラスからは自機に関わる変数shobo, shoboPos, gamePadStateを追い出しました。
将来的に複数のコントローラやプレイヤーに対応できるように、コンストラクタでPlayerIndexを渡すようにしてあります。
自弾を適度な間隔で撃つように
ショットボタンを押しっぱなしにしている間、毎フレーム自弾を撃ってしまっているので、4フレームに1発だけ撃つようにしました。
FighterクラスにShotButtonStateというint変数を作っておいて、符号で押下状態を、絶対値で継続フレーム数を保持するようにしました。
- if (gamePadState.Buttons.A == ButtonState.Pressed) {
- if (ShotButtonState < 0) {
- ShotButtonState = 0;
- }
- ShotButtonState++;
- } else {
- if (ShotButtonState > 0) {
- ShotButtonState = 0;
- }
- ShotButtonState--;
- }
自弾の発射判定はいまだにGame1クラスのほうでやっていて、
- if (fighter1.ShotButtonState > 0) {
- if (fighter1.ShotButtonState % 4 == 1) {
- Shot shot = new Shot();
- shot.Position.X = fighter1.Position.X;
- shot.Position.Y = fighter1.Position.Y;
- shots.Add(shot);
- }
- }
なんてことをやっちゃってます。本当はイベントなり使いたかったのですが、調べる時間を惜しんでしまいました。こまけぇこたぁいいんです。
ちなみに押下した次のUpdateではShotButtonStateは1になるので、==1で比較すると押下した瞬間に常に自弾が出るのでゲーム的に正しいです。
自機のサイズと中心点を移動
自機がでかいのと、画像の左上に自機の原点があるのが気になったので、改善してみました。
SpriteBatch.Drawがオーバーロードされていて、第二引数にRectangleを渡すとリサイズするようなので、以下のようにしました。
- private Rectangle drawDest;
Initialize中に
- drawDest = new Rectangle(0, 0, 48, 48);
Update中に
- drawDest.X = (int)(Position.X - drawDest.Width * 0.5);
- drawDest.Y = (int)(Position.Y - drawDest.Height * 0.5);
Draw中に
- spriteBatch.Draw(texture, drawDest, Color.White);
これでfighter1.Positionの位置に自機の画像の中心が来るようになりました。
同じ要領でShotにもdrawDestを用意しましたが、リサイズすると重くなるかと考え、こちらはVector2で行いました。
溜まった自弾を掃除する
自弾を撃つときnewしてて、画面外に出ても保持しっぱなしだったので、とりあえずshotsからRemoveするようにしてみました。
Shotクラスにpublic Boolean Destroyedを用意し、Update中に画面の外に出たらtrueを入れます。
Game1クラス中で、ものは試しに
- foreach (Shot shot in shots) {
- shot.Update(gameTime);
- if (shot.Destroyed) {
- shots.Remove(shot);
- }
- }
とやってみたところ例外が出たので、まあそんなに世の中甘くないよねと思いながら以下のように修正。
- foreach (Shot shot in shots) {
- shot.Update(gameTime);
- }
- for (int i = shots.Count - 1; i >= 0; i--) {
- Shot shot = shots[i];
- if (shot.Destroyed) {
- shots.Remove(shot);
- }
- }
Shot中の閾値を変えて試してみたところ、ちゃんとRemoveされているようです。
でも本当はいちいち新しいインスタンスnewするなんて言語道断です。ちゃんとプールすべきなのですが、そこは例によって先送りします。
敵を作る
この段階で残り5分でしたが、無謀にも敵の追加に挑戦しました。
例によってペイントを起動します。プロなのでWin, mspaint, Enterで起動します。(Vistaじゃない人はWin+R, mspaint, Enterを使いましょう)
絵を描きました。やる気はあります。時間がないのです。
画像をアセットに追加し、Enemy.csを追加し、Shotクラスをほぼコピペしてでっちあげ、List<shot> shotsをほぼコピペしてenemiesをでっちあげました。
敵が出現するようにする
毎フレーム出現するとうるさいので、1/10の確率で出現するようにしました。
- if (Math.Random() < 0.1) {
- }
と打ってMath.Randomが無いことに気づき、Randomクラスを思い出してインスタンスを作りました。
次に
- if (rand.NextDouble < 0.1) {
- }
と書いたところ、XELFさんにNextDoubleはメソッドだよとコメントをもらいました。ありがとうございます!
その後ひととおりビルドエラーを取ったのですが、弾が画面に出現しない。もう30分経ったし、断念するかーと思ってたところ、Drawしてないことに気づきました。恥ずかしい。
無事敵が画面に出るようになりました。まだ自機とも自弾とも当たり判定をしていませんが、30分経過してしまったのでここまで。
今回の感想
- livestreamがかなり強力。ソースコードが読めるぐらいの解像度と、弾の動きが分かるぐらいのフレームレート。次回からもこれを使いたいです。
- コメントで日本語を使えないのと、
コメントが保存されない嘘。保存されてました のが欠点なので、Twitterを使おうかな。 - コメントでアドバイスもらえたのが楽しかったです!やってて良かった。
明日は順当に当たり判定を入れる予定です。ではまた!
タグ: DeskTopLive, desktoplivexna, MiniDTL, XNA

2009 年 8 月 22 日 12:32 AM
shotsの掃除にforを使ってますが、shots.RemoveAllにdelegateを渡す夢を見ました。夢の中でそれはPredicateと呼ばれていました。また明日。
2009 年 8 月 22 日 3:59 PM
[...] ミニDTL.xna “ゲームはイチニチ30分まで!” 第3回 [...]