6.10 透過処理
6.10.1 背景を透明にする
ジャンルに関係なく、多くのゲームには背景とキャラクターの画像を制御するロジックが要求されます。RPG ゲームやシミュレーションゲームであれば、マップやフィールドを描画するのは背景処理と考えることができ、マップやフィールド上でユーザーが操作するキャラクターアイコンは背景画像とは別に描画される前景画像のロジックとなります。
アドベンチャーゲームや恋愛シミュレーションであれば、ユーザー視点で画面が構成されるので、この関係はより明確になります。2Dゲームの対話シーンであれば背景画像、前景画像(キャラクターや演出)、そしてメッセージウィンドウという構成になるでしょう。
最終的に画面に表示されるときには一枚のイメージとして構築されていますが、この画面を作る過程では背景画像を描画し、その上に前景画像を描画するというように Image オブジェクトを重ねて実現しています。
しかし、この処理は単純にイメージを重ねれば良いというものではありません。例えば、図3を背景に、図4を前景キャラクターとして重ねたい場合を考えてください。開発者が理想とする結果は図5となるでしょう。
しかし、背景に重なる前景を担当するイメージは多くの場合で複雑な形をしています。PNG や GIF 形式のような透明色をサポートしているファイルフォーマットであれば透明な背景を指定できますが、JPEG や BMP 形式のファイルフォーマットには透明な背景を設定することはできません。もし、BMP ファイルから生成した Image オブジェクトを前景のイメージとして描画するとイメージの背景も描画されてしまいます。つまり、図6のようなお粗末が画面が表示されてしまいます。
ゲームの画面は、複数のイメージファイルを重ねて描画することで完成します。背景、前景、自分のキャラクタ、敵キャラクタ、障害物など、その構成はゲームの性質によって様々ですが、個々のイメージを重ねる方法は同じです。しかし、背景に前景を重ねたとき、前景用のビットマップの背景も描画されてしまうのです。通常、前景のイメージは複雑な形をしているものであり、完全な矩形であることは期待できません。
イメージが Bitmap オブジェクトであれば、イメージの特定の色を透明な色として設定することができます。あらかじめ、キャラクターなどの前景画像で背景色として使う色を定めておけば、BMP ファイルから読み込んだ Bitmap オブジェクトの背景を透明にすることができます。透明色を指定するには Bitmap クラスの MakeTransparent() メソッドを使います。
public void MakeTransparent(Color transparentColor)
transparentColor パラメータには透明にする色を表す Color オブジェクトを指定します。JPEG の場合は色が劣化するので注意してください。透明な色は指定した Color オブジェクトの値に完全に一致しなければなりません。
using System.Drawing; using System.Windows.Forms; public class Test : Form { private Bitmap fore, back; protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); e.Graphics.DrawImage(back, 0, 0); e.Graphics.DrawImage( fore, back.Width / 2 - fore.Width / 2, back.Height / 2 - fore.Height / 2 ); } public Test() { fore = new Bitmap("fore.bmp"); back = new Bitmap("back.bmp"); fore.MakeTransparent(Color.Red); } static void Main() { Application.Run(new Test()); } }
コード1は、背景画像に back.bmp という名前のファイルを読み込んで描画し、この背景画像に重ねるように fore.bmp を前景画像として描画します。Test クラスのコンストラクタでは、Bitmap クラスのコンストラクタから画像ファイルを読み込んでインスタンスを生成し、MakeTransparent() メソッドで赤色を透明色として設定しています。この設定によって、ビットマップ上で Color.Red と色が一致するピクセルを透明なピクセルとして扱います。
6.10.2 半透明処理
演出を重要とするアプリケーションのでは、前景画像を突然表示させるのではなく、例えば徐々にイメージが浮き上がってくるフェードインや、徐々にイメージが薄くなって消えるフェード・アウトのような処理が必要になります。これは、ゲームでは頻繁に採用されている基本的な演出です。
これを実現するには、前景色と背景色を混合する半透明処理を行わなくてはなりません。理屈では、前景画像のピクセルの色と背景画像のピクセルの色をそれぞれ任意の割合で混ぜればよいのですが、ビットマップのすべてのピクセルを書き換えるという作業は簡単なものではありません。
.NET では、ビットマップの書くピクセルのアルファ要素を操作すればピクセルを半透明にすることができますが、多くの場合は演出のために一時的に半透明にしたいだけなので、半透明なイメージを永続的に保存するケースでなければ冗長な処理です。オリジナルの画像のピクセル値を変更することなく、描画時にイメージを半透明にすることができれば、この問題を解決できます。
実は、Image オブジェクトを描画するときにピクセルの色を調整することができる DrawImage() メソッドがオーバーロードされています。
public void DrawImage( Image image, Rectangle destRect, int srcX, int srcY, int srcWidth, int srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttr )
image パラメータには描画するイメージを、destRect にはイメージを描画する矩形を指定します。srcX には描画するイメージの部分を指定する X 座標、srcY には Y 座標、srcWidth には幅、srcHeight には高さをそれぞれ指定します。srcUnit には抽出元の矩形に設定されている値の単位を指定します。
描画するイメージのピクセルの色を調整するのは imageAttr に指定する System.Drawing.Imaging.ImageAttributes クラスのオブジェクトです。
System.Object System.Drawing.Imaging.ImageAttributes
public sealed class ImageAttributes : ICloneable, IDisposable
ImageAttributes クラスでは、色の調整、明度、ガンマ補正など、描画するイメージに対して様々な調整を行うことができます。ImageAttributes クラスのコンストラクタはパラメータを受け取らない単純なコンストラクタのみです。
色の調整を行うには SetColorMatrix() メソッドからカラー調整行列を設定します。
public void SetColorMatrix(ColorMatrix newColorMatrix)
newColorMatrix パラメータには、色の調整を行うカラー調整行列を指定します。
カラー調整行列は System.Drawing.Imaging.ColorMatrix クラスのオブジェクトです。カラー調整行列は、アルファ、赤、緑、青、及び常に 1 の w 成分で構成される 5 × 5 の行列です。
System.Object System.Drawing.Imaging.ColorMatrix
public sealed class ColorMatrix
このクラスのインスタンスは、空のパラメータのコンストラクタから作成することができます。行列の値は、Matrix00 ~ Matrix44 プロパティで設定することができます。色合いの強さは、Matrix00 が赤、Matrix11 が緑、Matrix22 が青、Matrix33 がアルファ、Matrix44 が w 成分となります。これらのプロパティは 0 ~ 1 の値で強さを設定することができます。0.5 を設定すれば、元の色の半分の強さになります。
色合いを変えたい場合は、赤、緑、青成分の値を 1 以外に設定しますが、不透明度だけを変更して描画したいのであれば、他の成分は全て 1 に設定し、アルファ成分のみを 1 以下の値に設定します。
using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; public class Test : Form { private Bitmap fore, back; protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); ColorMatrix mx = new ColorMatrix(); mx[0, 0] = 1; mx[1, 1] = 1; mx[2, 2] = 1; mx[3, 3] = 0.5F; mx[4, 4] = 1; ImageAttributes attr = new ImageAttributes(); attr.SetColorMatrix(mx); Rectangle rect = new Rectangle( back.Width / 2 - fore.Width / 2, back.Height / 2 - fore.Height / 2, fore.Width, fore.Height ); e.Graphics.DrawImage(back, 0, 0); e.Graphics.DrawImage( fore, rect, 0, 0, fore.Width, fore.Height, GraphicsUnit.Pixel , attr ); } public Test() { fore = new Bitmap("fore.bmp"); back = new Bitmap("back.bmp"); fore.MakeTransparent(Color.Red); } static void Main() { Application.Run(new Test()); } }
コード2は、ImageAttributes オブジェクトの SetColorMatrix() メソッドから ColorMatrix オブジェクトを設定しています。この ColorMatrix オブジェクトでは、アルファ値の変換に 0.5F を設定しているため、イメージのアルファ値が現在の値から 50% に修正されます。