画面を歪ませる処理は描画可能画像と非公開関数の2Dポリゴンを描画する関数の
DrawPrimitiveIndexed2D を使用すればシェーダーが無くても実現できます
サンプルを組んでみましたので、よろしければご覧ください
#include "DxLib.h"
#include <math.h>
#define CIRCLE_ANGLE_VERTEX_NUM 16 // 円周の頂点数
#define CIRCLE_RADIUS_VERTEX_NUM 8 // 半径の頂点数
#define SCREEN_W 640 // 画面の幅
#define SCREEN_H 480 // 画面の高さ
// 画面を歪ませながら描画する関数
void DrawCircleScreen(
int CenterX, // 円の中心座標X
int CenterY, // 円の中心座標Y
float InRadius, // 内側の円のサイズ
float OutRadius, // 外側の円のサイズ
float Absorption, // 内側の円に引き込まれるドット数
int ScreenHandle // 画面グラフィックハンドル
)
{
float CenterDistance ;
float GraphCenterDistance ;
float AbsorptionDistance ;
float AbsorptionMoveX, AbsorptionMoveY ;
float Angle ;
int TextureW, TextureH ;
float Sin, Cos ;
COLOR_U8 DiffuseColor ;
int i, j ;
VERTEX2D *Vert ;
WORD *Ind ;
float AngleCosTable[ CIRCLE_ANGLE_VERTEX_NUM ] ;
float AngleSinTable[ CIRCLE_ANGLE_VERTEX_NUM ] ;
float InCircleCosTable[ CIRCLE_RADIUS_VERTEX_NUM ] ;
// スタックに積むには大きいので static 配列にしました
static VERTEX2D Vertex[ CIRCLE_RADIUS_VERTEX_NUM * CIRCLE_ANGLE_VERTEX_NUM ] ;
static WORD Index[ ( CIRCLE_ANGLE_VERTEX_NUM + 1 ) * 6 * ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ] ;
// 描画可能画像が使用しているテクスチャのサイズを取得しておく
GetGraphTextureSize( ScreenHandle, &TextureW, &TextureH ) ;
// 最初に普通に描画
DrawGraph( 0, 0, ScreenHandle, FALSE ) ;
// 描画カラーを作成しておく
DiffuseColor = GetColorU8( 255, 255, 255, 255 ) ;
// 外周部分用の Sin, Cos テーブルを作成する
Angle = 0.0f ;
for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++, Angle += PHI_F * 2.0f / CIRCLE_ANGLE_VERTEX_NUM )
{
AngleSinTable[ i ] = ( float )sin( ( double )Angle ) ;
AngleCosTable[ i ] = ( float )cos( ( double )Angle ) ;
}
// 内側の盛り上がっているように見せる箇所で使用する Cos テーブルを作成する
Angle = 0.0f ;
for( i = 0 ; i < CIRCLE_RADIUS_VERTEX_NUM ; i ++, Angle += ( PHI_F / 2.0f ) / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) )
{
InCircleCosTable[ i ] = ( float )cos( ( double )Angle ) ;
}
// ポリゴン頂点インデックスの準備
Ind = Index ;
for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ )
{
for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM - 1 ; j ++, Ind += 6 )
{
Ind[ 0 ] = i * CIRCLE_RADIUS_VERTEX_NUM + j ;
Ind[ 1 ] = Ind[ 0 ] + 1 ;
if( i == CIRCLE_ANGLE_VERTEX_NUM - 1 )
{
Ind[ 2 ] = j ;
Ind[ 3 ] = j + 1 ;
}
else
{
Ind[ 2 ] = Ind[ 0 ] + CIRCLE_RADIUS_VERTEX_NUM ;
Ind[ 3 ] = Ind[ 0 ] + 1 + CIRCLE_RADIUS_VERTEX_NUM ;
}
Ind[ 4 ] = Ind[ 2 ] ;
Ind[ 5 ] = Ind[ 1 ] ;
}
}
// バイリニア補間描画にする
SetDrawMode( DX_DRAWMODE_BILINEAR ) ;
// 外側のドーナツ部分を描画
// 中心に向かうにしたがって中心方向にテクスチャ座標をずらす
Vert = Vertex ;
for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ )
{
// 使用する Sin, Cos の値をセット
Sin = AngleSinTable[ i ] ;
Cos = AngleCosTable[ i ] ;
for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM ; j ++, Vert ++ )
{
// 円の中心までの距離を算出
CenterDistance = OutRadius - ( OutRadius - InRadius ) * j / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ;
// 中心に引き込まれる距離を算出
AbsorptionDistance = Absorption * j / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ;
// 中心に向かって移動する距離を算出
AbsorptionMoveX = Cos * AbsorptionDistance ;
AbsorptionMoveY = Sin * AbsorptionDistance ;
// スクリーン座標の決定
Vert->pos.x = Cos * CenterDistance + CenterX ;
Vert->pos.y = Sin * CenterDistance + CenterY ;
Vert->pos.z = 0.0f ;
// テクスチャ座標のセット
Vert->u = ( Vert->pos.x + AbsorptionMoveX ) / TextureW ;
Vert->v = ( Vert->pos.y + AbsorptionMoveY ) / TextureH ;
// その他のパラメータをセット
Vert->rhw = 1.0f ;
Vert->dif = DiffuseColor ;
}
}
// 歪んだドーナツの描画
DrawPrimitiveIndexed2D( Vertex, sizeof( Vertex ) / sizeof( VERTEX2D ), Index, sizeof( Index ) / sizeof( WORD ), DX_PRIMTYPE_TRIANGLELIST, ScreenHandle, FALSE ) ;
// 内側の盛り上がっているように見える部分を描画
// Cosテーブルにしたがってテクスチャ座標をずらす
Vert = Vertex ;
for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ )
{
// 使用する Sin, Cos の値をセット
Sin = AngleSinTable[ i ] ;
Cos = AngleCosTable[ i ] ;
for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM ; j ++, Vert ++ )
{
// 円の中心までの距離を算出
CenterDistance = InCircleCosTable[ j ] * InRadius ;
// 画像座標視点での円の中心までの距離を算出
GraphCenterDistance = ( ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) - j ) * ( Absorption + InRadius ) / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ;
// スクリーン座標の決定
Vert->pos.x = Cos * CenterDistance + CenterX ;
Vert->pos.y = Sin * CenterDistance + CenterY ;
Vert->pos.z = 0.0f ;
// テクスチャ座標のセット
Vert->u = ( Cos * GraphCenterDistance + CenterX ) / TextureW ;
Vert->v = ( Sin * GraphCenterDistance + CenterY ) / TextureH ;
// その他のパラメータをセット
Vert->rhw = 1.0f ;
Vert->dif = DiffuseColor ;
}
}
// 中心の盛り上がって見える部分を描画
DrawPrimitiveIndexed2D( Vertex, sizeof( Vertex ) / sizeof( VERTEX2D ), Index, sizeof( Index ) / sizeof( WORD ), DX_PRIMTYPE_TRIANGLELIST, ScreenHandle, FALSE ) ;
}
// WinMain 関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int ScreenHandle ;
int GrHandle ;
int GraphX, GraphAddX ;
int CircleX, CircleAddX ;
int CircleAngle ;
int i ;
// ウインドウモードで起動
ChangeWindowMode( TRUE );
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1;
// 描画可能画像の作成
ScreenHandle = MakeScreen( SCREEN_W, SCREEN_H ) ;
// 画像の読み込み
GrHandle = LoadGraph( "Test1.bmp" );
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK );
// 画像と円の推移用パラメータを初期化
GraphX = 0 ;
GraphAddX = 2 ;
CircleX = 320 ;
CircleAddX = -1 ;
CircleAngle = 0 ;
// メインループ(何かキーが押されたらループを抜ける)
while( ProcessMessage() == 0 )
{
// 画像を移動
GraphX += GraphAddX ;
if( GraphX < 0 || GraphX > 640 - 119 ) GraphAddX = -GraphAddX ;
// 歪み円を移動
CircleX += CircleAddX ;
if( CircleX < 0 || CircleX > 640 ) CircleAddX = -CircleAddX ;
// 歪み円の円周の値を揺らがせる処理
CircleAngle += 1 ;
if( CircleAngle >= 360 ) CircleAngle = 0 ;
// 描画先を描画可能画像にする
SetDrawScreen( ScreenHandle ) ;
// 画面のクリア
ClearDrawScreen();
// 画面に格子を描画する
for( i = 0 ; i < 640 / 16 ; i ++ )
DrawLine( i * 16 + 1, 0, i * 16 + 1, 480, GetColor( 128,128,128 ) ) ;
for( i = 0 ; i < 480 / 16 ; i ++ )
DrawLine( 0, i * 16 + 1, 640, i * 16 + 1, GetColor( 128,128,128 ) ) ;
// 画像の描画
DrawGraph( GraphX, 0, GrHandle, TRUE );
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
// 画面を歪ませて描画
DrawCircleScreen(
CircleX, 240, // 中心座標
80.0f + sin( CircleAngle * PHI_F / 180.0f ) * 15.0f, // 内側の円のサイズ
200.0f + sin( CircleAngle * 2 * PHI_F / 180.0f ) * 50.0f, // 外側の円のサイズ
48.0f, // 内側に引き込まれるドット数
ScreenHandle ) ;
// 裏画面の内容を表画面に反映
ScreenFlip();
}
// DXライブラリの後始末
DxLib_End();
// ソフトの終了
return 0;
}
手順としては、まず歪ませるものをすべて描画可能画像に描画した後、それを頂点座標と
テクスチャー座標を歪んで見えるように操作した頂点データを用意して DrawPrimitiveIndexed2D で
円形内を敷き詰めるようにポリゴンを描画する、というものです
ただ、こちらのサンプルで使用している関数 GetGraphTextureSize は今回追加したものですので、
コンパイルにはこちらの最新バージョンが必要です
お手数ですが、よろしければダウンロードしてください m(_ _;m
http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibGCCTest.exe // Gnu C++ 用
(中身を既存のライブラリのファイルに上書きして、BCCをお使いの
場合は『再構築』を、VCをお使いの場合は『リビルド』を、
Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
爆発の炎と黒煙は、もやっとした白くて丸い煙の画像さえ用意できれば、
最初に SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ; SetDrawBright( 0, 0, 0 ) ;
の設定を行い真っ黒に描画されるようにした上で煙画像を何枚も描画して黒煙を表現した後、
SetDrawBlendMode( DX_BLENDMODE_ADD, 255 ) ; SetDrawBright( 255,180,64 ) ;
の設定を行い赤っぽく、そして描画すればするほど輝度が加算されて明るくなるように上で
画像を何枚も描画して発光する炎を表現すればアップしていただいた爆発を表現できます
爆発が広がっていく様と、だんだん消える様を表現するには、それぞれ黒煙や炎を表現している画像一枚一枚を
徐々に爆心地から離れさせる処理と、一定時間経過したら SetDrawBlendMode の第二引数の値を徐々に下げて
フェードアウトさせる処理が必要になります
爆発初期の閃光については、閃光の一枚絵を用意して単純に描画するのが一番簡単そうです
( その一枚絵を用意するのが大変そうですが・・・ )