21:変換行列によるスプライト移動
これまではスプライトの表示位置を、ID3DXSprite::Draw()の引数で直接指定していましたが、移動方法は他にもあります。それは幾何変換と呼ばれる方法です(座標軸自体の移動をイメージするとよいでしょう)。幾何変換は単純な移動だけではなく、回転や拡大縮小処理を同時に加えたスプライトを描画するときに便利です。![]() | ![]() |
スプライト自体を移動 | 座標軸自体を移動 |

[lはx、mはy、nはz方向の移動量]
おのおのの値の算出方法は以下の通りです。mは4×4の行列、角括弧([])内は行列の列方向(左から右)、行方向(上から下)を意味します。
上の式に先ほどの行列の値を代入すると、実際に平行移動が行われていることがわかるでしょう。x' = x * m[0][0] + y * m[0][1] + z * m[0][2] + 1 * m[0][3] y' = x * m[1][0] + y * m[1][1] + z * m[1][2] + 1 * m[1][3] z' = x * m[2][0] + y * m[2][1] + z * m[2][2] + 1 * m[2][3]
しかし、移動計算を行うたびに行列やその計算を意識するには結構つらいものがあります。うれしいことにDirect3Dには、幾何変換に関する行列計算を行うための変数や関数が用意されています。x' = x * 1 + y * 0 + z * 0 + 1 * l = x + l y' = x * 0 + y * 1 + z * 0 + 1 * m = y + m z' = x * 0 + y * 0 + z * 1 + 1 * n = z + n
以上をふまえて、プログラムの制作に取りかかるわけですが、このままだと計算結果の座標位置がスプライトの左上となります。背景グラフィックであればこれでも不便な点はないのですが、敵キャラクターなど動きのあるグラフィックならば、キャラクターの中心と座標位置が重なるようにすると、あたり判定の計算など、いろいろ都合のよい点が出てきます。D3DXMATRIX mtrx; D3DXMatrixTranslation(&mtrx, 10.0f, 10.0f, 0.0f); pSprite->SetTransform(&mtrx);


[原点が中央にある方が描画結果をイメージしやすい]
そこで、グラフィックの原点を変更できるようにし、その位置を中心にスプライトを描画できるようにする機能を付け加えることにします。位置はx方向とy方向をOR演算で組み合わせるようにします。
#define CP_MIDDLECENTER 0 // 中央(デフォルト値)
#define CP_LEFT 1 // x方向左端
#define CP_CENTER 2 // x方向中央
#define CP_RIGHT 4 // x方向右端
#define CP_TOP 8 // y方向上端
#define CP_MIDDLE 16 // y方向中央
#define CP_BOTTOM 32 // y方向下端
#pragma once
#include "Texture.h"
#define CP_MIDDLECENTER 0
#define CP_LEFT 1
#define CP_CENTER 2
#define CP_RIGHT 4
#define CP_TOP 8
#define CP_MIDDLE 16
#define CP_BOTTOM 32
CSprite : public CGameObject
{
private:
CTexture *texture;
BYTE cpos; // 基点の位置
float orig_x, orig_y; // 原点の位置
int swidth, sheight; // スプライトのサイズ
void Reset();
public:
CSprite();
CSprite(CTexture *source);
void SetTexture(CTexture *source);
void SetCenterPosition(BYTE pos);
BYTE GetCenterPosition();
/* 省略 */
};
#include "Sprite.h"
CSprite::CSprite()
{
Reset();
}
CSprite::CSprite(CTexture *source)
{
Reset();
SetTexture(source);
}
void CSprite::Reset()
{
texture = NULL;
cpos = CP_MIDDLECENTER;
orig_x = orig_y = 0.0f;
}
void CSprite::SetTexture(CTexture *source)
{
if(source == NULL) return;
texture = source;
texture->GetTextureSize(&swidth, &sheight);
// 原点位置の更新
SetCenterPosition(cpos);
}
void CSprite::SetCenterPosition(BYTE pos)
{
// 原点の位置を計算
cpos = pos;
if(pos & CP_LEFT){
orig_x = 0.0f;
}else if(pos & CP_RIGHT){
orig_x = (float)swidth;
}else{
orig_x = (float)swidth / 2.0f;
}
if(pos & CP_TOP){
orig_y = 0.0f;
}else if(pos & CP_BOTTOM){
orig_y = (float)sheight;
}else{
orig_y = (float)sheight / 2.0f;
}
}
BYTE CSprite::GetCenterPosition()
{
return cpos;
}

CSprite : public CGameObject
{
private:
/* 省略 */
public:
/* 省略 */
void Draw(float x, float y, int alpha = 255);
};
void CSprite::Draw(float x, float y, int alpha)
{
if(texture == NULL){
DXTRACE_MSG(_T("テクスチャが読み込まれていません"));
return;
}
D3DXMATRIX mtrx1, mtrx2;
// 原点を重ね合わせる平行移動
D3DXMatrixTranslation(&mtrx1, -orig_x, -orig_y, 0.0f);
// 指定の場所へ移動する行列との合成
D3DXMatrixTranslation(&mtrx2, x, y, 0.0f);
D3DXMatrixMultiply(&mtrx1, &mtrx1, &mtrx2);
pSprite->Begin(NULL);
pSprite->SetTransform(&mtrx1);
pSprite->Draw(texture->GetTexture(), &drawrect, NULL, NULL, 0x00FFFFFF | ((BYTE)alpha << 24));
pSprite->End();
}
//アンチエイリアスの無効
pD3Ddevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
pD3Ddevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
void CDxFont::Draw
(LPCTSTR text, int count, LPRECT pRect,
DWORD Format, D3DXCOLOR Color)
{
if(font){
pSprite->Begin(NULL);
D3DXMATRIX mtrx;
D3DXMatrixTranslation(&mtrx, 0.0f, 0.0f, 0.0f);
pSprite->SetTransform(&mtrx);
font->DrawText(pSprite, text, count, pRect, Format, Color);
pSprite->End();
}
}