9月, 2011 のアーカイブ

今回はノベルゲームとかで見られる文字列を一文字ずつ描画する方法を残します。ちなみに、描画には前回のメモで作ったテキストボックスを使っています。

まず、タイマー、描画する文字列、描画する文字数、文字を描画するスピードを保存する変数を作ります。

string m_text = "...etc"; // 描画する文字列
float m_timer;      // タイマー
float m_nextLetter; // 次の文字列を描画する時間
int m_currentIndex; // 描画する文字の数

次に、Updateメソッド(または、毎フレーム呼ばれる他の関数)内でタイマーに前のフレームから経過した時間を足します。

float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
m_timer += delta;

タイマーを更新した後は前回描画する文字数を増やしてから一定以上時間が経過しているかを確認します(ここで使われるm_nextLetter変数の値を下げるとより早く描画され、上げると遅くなります)

// 次の文字を描画するかの確認
if (m_timer >= m_nextLetter)
{

一定上時間が経過していた場合、タイマーをリセットし、描画する文字数を増やします。増やした文字数は念のために文字列を超えていないかも確認します。

// タイマーのリセット
m_timer = 0.0f;

// 描画する文字数を増やす
m_currentIndex++;
if (m_currentIndex >= m_text.Length)
{
m_currentIndex = m_text.Length;
}
}

次は、描画方法です。描画する文字列を獲得するにはstring.Substring()メソッドを使用します。このメソッドは文字列の指定した部分(この場合最初の文字から、m_currentIndexの部分までの文字)を返します。

// 描画する文字列を獲得する
string text = m_text.Substring(0, m_currentIndex);

後は文字列を描画するだけです。この部分には前回作ったテキストボックスが使われています。

// 文字列の描画
m_textbox.Draw(spriteBatch, m_font, text, m_pixel, new Color(0, 0, 0, 0.65f), Color.White, true);

今回はココまでです。作ったプロジェクトはココに置いておきます:

http://www.mediafire.com/download.php?q9c2y0pp9h5vebb

今回はかなりシンプルなメモです。XNAで文字列を描画すると、改行するためには自分で’\n’を足す必要が有ります。これは文字列が増えるとかなり面倒になるので、自動で改行してくれるテキストボックスを作成します。

普通の描画:

テキストボックスを使っての描画:

まず、TextBoxクラスを作成し、テキストボックスの大きさを示すRectangleのメンバ変数を持たせます。

class TextBox
{
protected Rectangle m_bounds;
public TextBox(Rectangle bounds)
{
m_bounds = bounds;
}
...

次に、文字列をに改行加えてくれる関数を作ります。文字列の改行は英語と日本語とで方法が少し変わりますのが(単語ごとの確認か、文字ごとの確認)、日本語の描画を説明するのが面倒なので今回は英文専用です。

まず、一行の文字列を保存する変数、変換した文字列を保存する変数、単語別に分解された文章を保存している配列を作ります。


private string WrapWords(string text, SpriteFont font)
{
string line = ""; // 現在の行の文字列
string wrappedText = ""; // 変換済みの文字列
string[] words = text.Split(' '); // 単語別に分解した文字列

...

次に、全ての単語をループして改行を加えた新しい文字列を作ります。まず、現在の行の文字列(line)に、現在の単語を足した長さを測ります。


foreach (string word in words)

{

// 現在の行の文字列(line)に、現在の単語を足した長さを測る
float length = font.MeasureString(line + word).Length();
...

そして、獲得された長さがテキストボックスの横幅を越えていた場合、現在の行の文字列と改行(’\n’)を、変換後に返す文字列に足し、現在の行の中身を次にそなえ空にします。


if (length > m_bounds.Width)
{
  wrappedText += line + '\n';
  line = "";
}

次に、今の行に現在使われている単語を足します。

  line += word + ' ';
} // foreach 終了

全ての単語を確認し終わった後に、変換済みの文字列と現在の行を足した文字列を返して終わりです。

return wrappedText + line;

これらを作り終わったら、後は描画するだけです。これは結構適当なので、テクスチャアとかはメンバとして保存しておくのもアリです。


public virtual void Draw(SpriteBatch sp, SpriteFont font, string text, Texture2D texture, Color colour)
{
if (texture != null)
{
  sp.Draw(texture, m_bounds, colour);
}

sp.DrawString(font, WrapWords(text, font), new Vector2(m_bounds.X + 5, m_bounds.Y + 5), Color.White);
}

今回はコレで終わりですが、もしかしたら何時か付け足します。

作ったクラスはココに置いておきます(中身は少しだけ違い、文字ごとに改行を確認する関数も実装されてます)。

http://www.mediafire.com/download.php?6nppsxug4glsoou