ゲーム画面

テーマ:
 ゲーム画面の表示ができたので、晒してみる。

神崎隼BLOG-ゲーム画面

 スコアとか、出てないけど、大体、こんな感じ。

 スペースがあったので、右下に、幻(?)のXNA版「ひげねコラムス」に肖って、アバターを表示してみました。
 何と言うか、碌に画像を作らなくても、ゲームっぽい画面になったね!
※印象には、個人差があります。

 HALO3 の服は、買った物が表示されるかどうかのテストのために、わざわざ買った物です。
 アバターのコンセプトは、昔の不良漫画に出てきそうな、弱そうな(そして、事実弱い)弟分キャラ。

AD

テスト中

テーマ:
 折角、使えるリソースがあるのに使わないと損なので、XNA Creators Club Online においてあるミニゲームの Movipa を改造して、一本でっち上げるためのテスト中。

神崎隼BLOG-TEST画像

 なんだけど、何だかメモリー食ってる模様。後で、要調査だな。

AD
 フォントを使わずに、テキストアドベンチャーをを作るお馬鹿な方法を思いついたので、カッとなって試した。後悔はしていない。

 ロゴ(Windows 版)
神崎隼BLOG-ロゴ

 タイトル(Windows 版)
神崎隼BLOG-ひげねこのなく頃に

 欠点は、Xbox360 上でのキャプチャ画面が撮れない事だが、些細な事であろう。

 ロゴ?(Xbox360 版)
神崎隼BLOG-ロゴ?

AD

ローカライズの注意点

テーマ:
 日本語以外の言語をサポートする時、注意する必要がいくつかあります。

 特に、LocalizationSample のように、アセンブリ リソース ファイルで文字列を扱う時です。
 恐らく、ローカライズは英語のみのゲームが多いと思いますが、リソースは以下のように作成しましょう。

・「リソース名.resx」に英語の文字列を登録し、日本語は「リソース名.ja.resx」に登録する。

 LocalizationSampleと同じ方法で、登録しましょうと言う事です。

 この形式で登録すると、以下のようにリソースが使用されます。

・日本語のXbox360上 → 日本語
・英語のXbox360上 → 英語
・それ以外の言語のXbox360上 → 英語

 これを逆に登録してしまうと、例えば英語はわかるけど日本語はわからないフランス人が、そのゲームを起動すると日本語が出てきてしまい、Xbox360の設定を変えない限り、英語では遊べなくなります。
 むしろ、英語に対応してないと勘違いしてしまう可能性が高いと思います。

 リソースを使わない場合でも、テクスチャ等を言語で分けている場合、日本語環境なら日本用のテクスチャ、それ以外は英語のテクスチャを読み込むと言う形にしておきましょう。

 ところで、日本語大好きフランス人が、日本製のゲームは日本語で遊びたいと思った時は、どうすれば良いでしょうか?
 Xbox360 の設定を日本語にすれば動きますが、切り替えが面倒です。

 ゲーム中で切り替え機能を入れれば、多少は楽になりそうです。

 リソースを使わない場合、特に問題はありませんね。言語情報を変数で確保し、そこを書き換えて、テクスチャ等の再読み込みをするだけで、終了です。

 では、リソースを使う場合は?

 リソース名で作られたクラスには、Cultureと言うプロパティがあるので、そこを書き換えればOKです。

 LocalizationSampleでは、初期化時に以下のように現在のCultureInfoを渡しています。

  Strings.Culture = CultureInfo.CurrentCulture;

 例えば、以下のような感じで、Cultureプロパティを初期化します。

・英語(アメリカ)

  リソース名.Culture = new CultureInfo(0x0409);

・英語(イギリス)

  リソース名.Culture = new CultureInfo(0x0809);

・英語(英語圏全体)

  リソース名.Culture = new CultureInfo(0x0009);

・日本語

  リソース名.Culture = new CultureInfo(0x0011);

 CultureInfoのコンストラクタの引数に渡す値は、CultureInfoのヘルプの表のカルチャ識別子を参照して下さい。

 尚、テクスチャ読み込み時に言語情報を見る場合は、LocalizationSampleのソースとは変えて、リソースのCultureプロパティを参照するようにすると、設定場所が一箇所になるのでうっかりミスも防げると思います。

 そんな感じで、本来遊んで貰えたかも知れない人々に遊んで貰えなくならないようにするためのTIPでした。

スターじゃないラスター

テーマ:
神崎隼BLOG-ラスタースクロール

 今更、Xbox LIVE インディーズ ゲーム開始記念に、ラスタースクロールについて書いてみようのコーナー。

 ラスタースクロールが何かは、説明しなくてもわかると思うけど、画面がグニャグニャするアレ。
 まぁ、知らない人は、ググッて下さい。

 ラスタースクロールにも色々と種類があるようですが、今回は、所謂、横ラスターです。

 XNA でその効果を実装するには、レンダーターゲットにグニャグニャさせたい物を描画して、グニャグニャと描画すれば終わりです。(頭の悪過ぎる説明)

 説明するより、コードを見たり、実行してみたりするのが、早いと思うので、早速、実装方法をサクッと説明。
※アメブロでは半角スペース使えないため、インデントには全角スペースを使用しています。

 とりあえず、Platformer スターター キットに追加する形でするので、それで新規作成して下さい。

 で、まずは、描画用の変数を定義させます。場所はどこでも良いので、PlatformerGame のコンストラクタの手前にでも、以下の定義を放り込んで下さい。

  RenderTarget2D renderTarget;

  int roll = 12;
  int loopCount = 360;
  int count;

 renderTarget はグニャグニャさせる物を描く用で、roll はグニャグニャ度合いみたいに理解して下さい。
 loopCount は count の最大値で、count はカウンターです。loopCount を小さくすると、高速でグニャグニャします。

 さて、続いては変数の初期化。

 LoadContent 関数の中の最後に、次のコードを追加して下さい。

  renderTarget = new RenderTarget2D(GraphicsDevice, BackBufferWidth, BackBufferHeight, 1, SurfaceFormat.Color);

  count = 0;

 今回は、Platformer の通常の描画をラスタースクロールさせるので、バックバッファと同じサイズのレンダーターゲットを作成してます。
 実際に使用する場合は、用途に合わせて変更して下さい。

 初期化が終わって、次は更新処理。

 Update 関数の最後に、次のコードを追加して下さい。

  if (loopCount - 1 > count)
    count++;
  else
    count = 0;

 そして、最後は描画。

 勿論、コードを追加するのは、Draw 関数です。

 追加箇所は二箇所で面倒なので、コードを全て書いてしまいましょう。

  protected override void Draw(GameTime gameTime)
  {
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

    GraphicsDevice.SetRenderTarget(0, renderTarget);
    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin();

    level.Draw(gameTime, spriteBatch);

    spriteBatch.End();

    GraphicsDevice.SetRenderTarget(0, null);

    spriteBatch.Begin();

    Texture2D tex = renderTarget.GetTexture();
    Vector2 vec = new Vector2();
    Rectangle rect = new Rectangle(0, 0, tex.Width, 1);

    for (vec.Y = 0; vec.Y < tex.Height; vec.Y += rect.Height)
    {
      vec.X = (float)((graphics.PreferredBackBufferWidth - tex.Width) / 2 + Math.Cos((count * 360 / loopCount + vec.Y) * MathHelper.Pi / 180) * roll);

      spriteBatch.Draw(tex, vec, rect, Color.White);

      rect.Y += rect.Height;
    }

    DrawHud();

    spriteBatch.End();

    base.Draw(gameTime);
  }

 肝は、for 文の中の一行目の計算ですかね? cos 関数でグニャグニャ位置を計算しています。

 それと、1ドットずつのラスターにしてますが、処理不可が気になる場合は、以下の行の最後の引数を増やして下さい。

  Rectangle rect = new Rectangle(0, 0, tex.Width, 1);

 この1を4にすると、for 文のぶん回し回数が1/4になります。勿論、4ドット単位でのスクロールになりますので、あまり大きくすると良くわからない効果になりますので、注意が必要です。

 どうでも良いですが、DrawHud 関数の呼び出しを level.Draw の後に移動させると、スコアとかもグニャグニャして少し楽しいです。

 さて、「ピクセルシェーダーでできそうな気もするけどやった事ないし、Zune でも動くと思うから」と言う事で、レンダーターゲットを使用した実装方法を紹介してみました。

 蛇足ですが、描画部分をちょっと変更すると縦ラスターにもなります。

XACT2 -> XACT3

テーマ:
 XNAGS3.1 日本語版公開開始記念に、カキコ。

 ↑にもある通り、3.0 のプロジェクトをアップグレードすると、XACT のビルドでエラーになります。

 XACT3 ツールで開いて保存しなおせば、確かに、解決します。

 が、そんな面倒で時間かかる事やってられっかー!

 と、言う方々のために、朗報。

 この方法なら、もっと速く解決します!※効果には、個人差があります。

 1.テキストエディタ(VSでプロジェクトを開いて、ダブルクリックでも可)で、xap ファイルをオープン
 2.最初の行の「Signature = XACT2;」を「Signature = XACT3;」に変更
 3.保存

 はい。できあがり。

 以上、3秒クッキングでした。

新・哀のメモリー

テーマ:
 とりあえず、忘れないうちに、メモリー虫君達をメモっておく。何かの参考に、どぞ。

・Dictionary のキーに enum を指定
・StringBuilder の Append で数値渡し
・引数に delegate を渡す関数呼び出し
・引数に params object[] を渡す関数呼び出し

 有名な物も混じってるけど、気にしない。
 後、食うメモリーの量はそれ程でも無いけど、油断するとあちこちで毎フレーム呼んでいて、マジ死亡。

 StringBuilder に関しては、もちろん、AppendFormat が4つ目に引っかかります。使えなくね?
 Append で数値渡ししたい時は、ひにけにXNA の伊藤さん作の StringBuilderExtensions を使うのが吉。

 こう言うのを一つ一つ潰していって、究極的にはシーン切り替え以外でメモリーの消費を抑えるのがベストだと思うんだけど、外人はタイトル画面や全く動きのない文字のみに近い画面でさえ、ガバガバメモリー食ってても平気なのが、いやん。

哀のメモリー

テーマ:
 タイトルに、深い意味はありません。

 ちょっと、野暮用で、XNA で作られたプログラムの処理落ちの原因を調べてたら、奇妙な動作に遭遇。

 何故か、メモリーが増えるはずの無い場所で、メモリーが確保されている! 新手のスタンドの攻撃か!?

 簡単に説明すると、Dictionary 型に突っ込んだ値を持ってくるだけで、メモリー食ってる。こいつは、妙だ。
 Dictionary 型なんて、何度も使ってるけどこんな事は初。

 とりあえず、サクッとテストプログラムを作成。うは! メモリー確保してやがる。

 まさか、3.0になってから、こうなった? と、一瞬、思ったけど、もう一つ、気になる点があったので、確認。ハーミットパー

 今度は、メモリーは微動だにせず。了解。

 そんな訳で、Dictionary 型のキーに列挙型を指定すると、その列挙型をキーにして渡す時に、メモリーとボクシングが発生する事が判明。

 と、言う事で、Microsoft Connect にサクッと登録。
 数日、放置していたら、状態が「終了 (外部)」になっていたので、3.1で治っている事を期待する。

 あ、ちなみに、キーを byte とか int とかにして、列挙型をキャストして渡した場合は、無問題。
 まぁ、だから、バグとして報告した訳だが。

ZuneZune教の野望

テーマ:
 なぜか、Zuneが二台も会社にあるので、ちょっと、調査。
 とりあえず、「Network Game State Management 」サンプルがほぼ正常動作する事を確認。

 なぜ、ほぼかと言うと、ZuneではNetworkSessionクラスのEndGameメソッドで、IsEveryoneReadyプロパティがクリアされないくさいから。
 なので、GameplayScreenでメニューからロビーに戻っても、直後にGameplayScreenに戻されてしまうのだよ、ワトソン君。