サンプル
- トップ
- > データの作成
- > プラグイン−パーティクル
- > サンプル
概要
『雨』パーティクルをサンプルとして用意しました。
プロジェクトは[particle_plugin\sample_rain]にあります。
このプロジェクトは Microsoft Visual Studio 2005 用のものです。
VS2008 でもコンバートを行うことでコンパイルする事が出来ます。
雨パーティクルといっても真上から真下に垂直落下させるだけでは単純すぎるので、ある程度の角度を指定出来るようにしてあります。
cs2Particleクラス
sample_rain.cpp の cs2Particle クラスを編集してパーティクルを作成します。
追加のメンバ変数は sample_rain.h で定義しています。
今回は各パーティクルの落下方向を保持するVEC3のポインタを定義しています。
class cs2Particle : public cs2ParticleBase { public: cs2Particle( ); ~cs2Particle( ); VOID Init( LPINITPARAM p ); VOID Exec( LPEXECPARAM p, DWORD before, DWORD frame ); VOID Stop( LPSTOPPARAM p ); private: // ポジションリセット void ResetPos( long no, float w, float h, float tx, float ty ); // 移動ベクトル取得 VEC3 cs2Particle::SetDir( long no, float spd, float r1, float r2 ); private: // 移動ベクトル LPVEC3 lpDir; };
コンストラクタ(cs2Particle)
cs2Particleクラスが作成されるときに呼ばれる関数です。
プライベート変数[lpDir]を初期化します。
この段階ではまだパーティクル数は分からないので、ここではメモリ確保は行っていません。
/********************************************
Public Function cs2Particle
コンストラクタ
input :
output :
*********************************************/
cs2Particle::cs2Particle( )
{
lpDir = NULL;
}
デストラクタ(~cs2Particle)
cs2Particleクラスが破棄(delete)されるときに呼ばれる関数です。
プライベート変数[lpDir]にセットされたメモリ領域を破棄しています。
/********************************************
Public Function ~cs2Particle
デストラクタ
input :
output :
*********************************************/
cs2Particle::~cs2Particle( )
{
if( lpDir != NULL )
{
free( lpDir );
lpDir = NULL;
}
}
初期化(Init)
パーティクルが実行される直前に呼ばれる関数です。
ここで初めてパーティクル数を知ることが出来ます。
その為、lpDirにパーティクル数分のメモリを割り当てます。
また、各パーティクルの初期位置と移動方向を設定しています。
このように、全てのパーティクルを初期化します。
/******************************************** Public Function Init 初期化 input : LPINITPARAM p 初期化パラメータ output : *********************************************/ void cs2Particle::Init( LPINITPARAM p ) { float* reg = p->param; if( lpDir == NULL ) { // メモリが確保されていない場合は確保 lpDir = (LPVEC3)malloc( p->count * sizeof(VEC3) ); } if( lpDir != NULL ) { for( DWORD i = 0; i < p->count; i++ ) { // 初期位置の設定 ResetPos( i, p->screen_width, p->screen_height, p->width, p->height ); SetDir( i, reg[0], PPF->Deg2Rad(reg[1]), PPF->Deg2Rad(reg[2]) ); } } }
パーティクル数は p->count で得ることが出来ます。
また、パーティクルを実行する際に指定されたパラメータは p->param で得ることが出来ます。
この値に基づき、パーティクルを初期化します。
関数 ResetPos(初期座標の算出)と SetDir(移動方向の設定)については後ほど説明します。
実行(Exec)
パーティクルが実行されている間、毎フレーム呼ばれる関数です。
この関数内でパーティクルを動かします。
/******************************************** Public Function Exec 実行 input : LPEXECPARAM p 実行パラメータ DWORD before 前回実行時のフレーム値 DWORD frame フレーム値 output : *********************************************/ void cs2Particle::Exec( LPEXECPARAM p, DWORD before, DWORD frame ) { float f; float* reg; if( lpDir != NULL ) { f = (float)(frame - before); reg = p->param; for( DWORD i = 0; i < p->count; i++ ) { lpParticle[i].pos.x += lpDir[i].x * f; ※1 lpParticle[i].pos.y += lpDir[i].y * f; lpParticle[i].pos.z += lpDir[i].z * f; if( lpParticle[i].pos.y > p->screen_height + 200.f ) { // 下まで落ちたので、再度位置を初期化 ResetPos( i, p->screen_width, p->screen_height, p->width, p->height ); SetDir( i, reg[0], PPF->Deg2Rad(reg[1]), PPF->Deg2Rad(reg[2]) ); } } } }
引数の before と frame は共にフレーム値になります。
before は前回 Exec 関数が呼ばれたときのフレーム値、frame は現在のフレーム値です。
フレーム落ちが無ければ、frame - before = 1 となりますが、フレーム落ちが発生するとこの差はより大きくなります。
パーティクルを動かすときは、frame - before 分のフレームを動かす必要があります。
※1 で f を掛けているのは、この為になります。
これを行わないと、フレーム落ちすればするほどゆっくりとした動作になってしまいますので、注意して下さい。
停止(Stop)
パーティクルが停止される時に呼ばれる関数です。
今回は特に行うことは無いので、何も処理していません。
/********************************************
Public Function Stop
停止
input : LPSTOPPARAM p 停止パラメータ
output :
*********************************************/
void cs2Particle::Stop( LPSTOPPARAM p )
{
}
ResetPos 関数
各パーティクルの座標の初期化を行っている関数です。
/********************************************
Private Function ResetPos
パーティクル位置を初期化
input : long no 初期化するパーティクルNo
float w スクリーンの幅
float h スクリーンの高さ
float tx パーティクル画像の幅
float ty パーティクル画像の高さ
output :
*********************************************/
void cs2Particle::ResetPos( long no, float w, float h, float tx, float ty )
{
lpParticle[no].pos.x = PPF->frand( ) * w * 2.f - w * 0.5f;
lpParticle[no].pos.y = -(PPF->frand( ) * h * 2.f);
lpParticle[no].base.x = tx * 0.5f;
lpParticle[no].base.y = ty * 0.5f;
}
lpParticle[no].pos.x / lpParticle[no].pos.y に数値を設定する事でパーティクルの表示座標を設定します。
今回は斜めに動くことを考慮して、X座標は2画面分(-0.5〜1.5)の間をランダムで設定しています。
Yは表示エリアより上2画面分の中に納まるようにランダムで設定しています。
また今回はパーティクルの中心位置を、真ん中に設定しています。
これで画像の中心を原点に回転するようになります。
PPF->frand( ) 関数は、不動少数 0.0 〜 1.0 の間のランダムな値を返す関数です。
システムで用意している関数は、このように PPF からアクセスすることが出来ます。
SetDir 関数
パーティクルの移動方向をセットする関数です。
/********************************************
Private Function SetDir
パーティクル移動方向をセット
input : long no パーティクルNo
float spd スピード(パラメータ0)
float r1 角度1(パラメータ1)
float r2 角度2(パラメータ2)
output : VEC3 移動ベクトル
*********************************************/
cs2Particle::VEC3 cs2Particle::SetDir( long no, float spd, float r1, float r2 )
{
VEC3 v;
float r;
v.x = 0.f;
v.y = spd;
v.z = 0.f;
r = PPF->frand( ) * (r2 - r1) + r1;
PPF->VecRotateZ( &v, r );
lpDir[no] = v;
lpParticle[no].rot.z = -r;
return v;
}
lpDir に角度を指定しつつ、パーティクル自体もその方向に回転させています。
さいごに
簡単ではありますが、パーティクルプラグインの説明をしました。
パーティクルプラグインは、パーティクル個々の表示座標などを連続的に操作する事で全体の動きを制御します。
言い換えると、それだけ行えば、あとの事はcs2システムが行ってくれます。
これを元にオリジナルのパーティクルにチャレンジしてもらえれば幸いです。