总结之前已经创建了一个简单的粒子系统(点这里 ),但是使用起来还是不是很方便,这次的任务就是为这个系统增加脚本支持。使用脚本来定义粒子系统的各项属性,再从主程序中将这些属性读出来,创建粒子系统。我对小巧简洁的东西有种特殊的喜好,因此我选择了Lua语言。Lua与C的交互需要频繁的 *** 作栈,使用起来并不是很方便,因此先简单的封装一下,可以不用直接 *** 作栈就可以了。
下面的这个类用于加载一个lua脚本,并提供了几个读取变量值的方法。其中GetInt,Getfloat,GetString用于读取变量fIEld,GetTInt,GetTfloat,GetTString用于读取表table中的第IDx个字段,ret返回读取到的值。
EpLuaScriptEngine.h:
#ifndef _EPLUASCRIPTENGINE_H_
#define _EPLUASCRIPTENGINE_H_
#include <lua.hpp>
class EpLuaScriptEngine
{
public :
EpLuaScriptEngine ();
virtual ~ EpLuaScriptEngine ();
bool LoadScript ( const char * filename );
bool GetInt ( const char * fIEld , int * ret );
bool Getfloat ( const char * fIEld , float * ret );
bool GetString ( const char * fIEld , const char ** ret );
bool GetTInt ( const char * table , int IDx , int * ret );
bool GetTfloat ( const char * table , float * ret );
bool GetTString ( const char * table , const char ** ret );
protected :
lua_State * m_L ;
};
#endif
EpLuaScriptEngine.cpp:
#include "EpLuaScriptEngine.h"
#include <iostream>
using namespace std ;
EpLuaScriptEngine :: EpLuaScriptEngine ()
{
m_L = lua_open ();
}
EpLuaScriptEngine ::~ EpLuaScriptEngine ()
{
lua_close ( m_L );
}
bool EpLuaScriptEngine :: LoadScript ( const char * filename )
{
if ( luaL_loadfile ( m_L , filename ) || lua_pcall ( m_L , 0 , 0 ))
{
cout << lua_tostring ( m_L , - 1 ) << endl ;
return false ;
}
return true ;
}
bool EpLuaScriptEngine :: GetInt ( const char * fIEld , int * ret )
{
int top = lua_gettop ( m_L );
lua_getglobal ( m_L , fIEld );
if ( lua_isnumber ( m_L , - 1 ))
{
* ret = ( int ) lua_tonumber ( m_L , - 1 );
lua_settop ( m_L , top );
return true ;
}
else
{
lua_settop ( m_L , top );
return false ;
}
}
bool EpLuaScriptEngine :: Getfloat ( const char * fIEld , float * ret )
{
int top = lua_gettop ( m_L );
lua_getglobal ( m_L , - 1 ))
{
* ret = ( float ) lua_tonumber ( m_L , top );
return false ;
}
}
bool EpLuaScriptEngine :: GetString ( const char * fIEld , const char ** ret )
{
int top = lua_gettop ( m_L );
lua_getglobal ( m_L , fIEld );
if ( lua_isstring ( m_L , - 1 ))
{
* ret = lua_tostring ( m_L , top );
return false ;
}
}
bool EpLuaScriptEngine :: GetTInt ( const char * table , table );
if ( ! lua_istable ( m_L , - 1 ))
{
lua_settop ( m_L , top );
return false ;
}
lua_rawgeti ( m_L , - 1 , IDx );
if ( ! lua_isnumber ( m_L , top );
return false ;
}
* ret = ( int ) lua_tonumber ( m_L , - 1 );
lua_settop ( m_L , top );
return true ;
}
bool EpLuaScriptEngine :: GetTfloat ( const char * table , top );
return false ;
}
* ret = ( float ) lua_tonumber ( m_L , top );
return true ;
}
bool EpLuaScriptEngine :: GetTString ( const char * table , IDx );
if ( ! lua_isstring ( m_L , top );
return false ;
}
* ret = lua_tostring ( m_L , top );
return true ;
}
有了这个类以后就可以用它读取粒子脚本中的属性。现在需要在之前的粒子系统类中,加入一个静态函数,用于从脚本加载一个粒子系统。
EpParticleSystem * EpParticleSystem :: CreateFromfile ( LPDIRECT3DDEVICE9 device , const char * filename )
{
if ( ! filename ) return NulL ;
//初始化lua,加载粒子脚本
EpLuaScriptEngine lua ;
lua . LoadScript ( filename );
D3DVECTOR position = { 0 }; //粒子系统的位置
lua . GetTfloat ( "position" , 1 , & position . x );
lua . GetTfloat ( "position" , 2 , & position . y );
lua . GetTfloat ( "position" , 3 , & position . z );
D3DVECTOR range = { 0 }; //长宽高范围
lua . GetTfloat ( "range" , & range . x );
lua . GetTfloat ( "range" , & range . y );
lua . GetTfloat ( "range" , & range . z );
D3DVECTOR accel = { 0 }; //加速度
lua . GetTfloat ( "accel" , & accel . x );
lua . GetTfloat ( "accel" , & accel . y );
lua . GetTfloat ( "accel" , & accel . z );
D3DVECTOR emiPosMin = { 0 }; //发射位置的范围
lua . GetTfloat ( "emiPosMin" , & emiPosMin . x );
lua . GetTfloat ( "emiPosMin" , & emiPosMin . y );
lua . GetTfloat ( "emiPosMin" , & emiPosMin . z );
D3DVECTOR emiPosMax = { 0 };
lua . GetTfloat ( "emiPosMax" , & emiPosMax . x );
lua . GetTfloat ( "emiPosMax" , & emiPosMax . y );
lua . GetTfloat ( "emiPosMax" , & emiPosMax . z );
D3DXVECTOR3 veloMin ; //粒子初始速度范围
ZeroMemory ( & veloMin , sizeof ( veloMin ));
lua . GetTfloat ( "veloMin" , & veloMin . x );
lua . GetTfloat ( "veloMin" , & veloMin . y );
lua . GetTfloat ( "veloMin" , & veloMin . z );
D3DXVECTOR3 veloMax ;
ZeroMemory ( & veloMax , sizeof ( veloMax ));
lua . GetTfloat ( "veloMax" , & veloMax . x );
lua . GetTfloat ( "veloMax" , & veloMax . y );
lua . GetTfloat ( "veloMax" , & veloMax . z );
D3DcolorVALUE colorMin = { 0 }; //粒子颜色范围
lua . GetTfloat ( "colorMin" , & colorMin . a );
lua . GetTfloat ( "colorMin" , & colorMin . r );
lua . GetTfloat ( "colorMin" , & colorMin . g );
lua . GetTfloat ( "colorMin" , 4 , & colorMin . b);
D3DcolorVALUE colorMax = { 0 };
lua . GetTfloat ( "colorMax" , & colorMax . a );
lua . GetTfloat ( "colorMax" , & colorMax . r );
lua . GetTfloat ( "colorMax" , & colorMax . g );
lua . GetTfloat ( "colorMax" , & colorMax . b);
float psizeMin = 0.0f ; //粒子大小范围
lua . Getfloat ( "psizeMin" , & psizeMin );
float psizeMax = 0.0f ;
lua . Getfloat ( "psizeMax" , & psizeMax );
int maxCount = 0 ; //最大粒子数量
lua . GetInt ( "maxCount" , & maxCount );
int emiCount = 0 ; //每次发射数量
lua . GetInt ( "emiCount" , & emiCount );
float emiInterval = 1.0f ; //发射间隔时间
lua . Getfloat ( "emiInterval" , & emiInterval );
const char * texturefile = NulL ;
lua . GetString ( "texture" , & texturefile );
EpParticleSystem * ps = new EpParticleSystem ( position , range , accel , emiPosMin ,
emiPosMax , veloMin , veloMax , colorMin , colorMax , psizeMin , psizeMax , maxCount ,
emiCount , emiInterval , device , texturefile );
return ps;
}
这里粒子系统的构造函数稍微有一点变动。因为脚本中只能定义纹理使用的文件名,而真正创建纹理还是要在C++中做,因此把纹理的创建由外部改到了内部。对于字符串texturefile 因为是存在于Lua的栈中,所以在这个函数返回后就会被销毁,因此如果需要在EpParticleSystem的构造函数以外创建纹理的话,在构造函数中就需要复制该字符串。像下面这样:
m_Texfilename = NulL ;
if ( texturefilename )
{
int length = strlen ( texturefilename ) + 1 ;
m_Texfilename = new char [ length ];
strcpy_s ( m_Texfilename , length , texturefilename );
}
对于上次的烟火的粒子,在Lua脚本中就可以这样写:
Firework.lua:
emiRange = 0.05
veloRange = 0.006
position = { 0.0 , 0.0 , 0.0 }
range = { 4.0 , 4.0 , 4.0 }
accel = { 0.0 , - 0.0002 , 0.0 }
emiPosMin = { - emiRange , - 2.0 , - emiRange }
emiPosMax = { emiRange , emiRange }
veloMin = { - veloRange , 0.02 , - veloRange }
veloMax = { veloRange , 0.03 , veloRange }
colorMin = { 0.0 , 0.0 }
colorMax = { 0.0 , 1.0 , 1.0 }
psizeMin = 0.3
psizeMax = 0.5
maxCount = 3000
emiCount = 10
emiInterval = 0.01
texture = " sNow.tga"
现在就可以把之前创建粒子系统的那一大段代码改成下面这行了:
g_Firework = EpParticleSystem :: CreateFromfile ( g_D3DDevice , "Firework.lua" );
if ( ! g_Firework ) return false ;
脱离了硬编码,这个粒子系统变得灵活多了。比如我们可以再写一个雪花的脚本,然后只需要更改上面的文件名就可以了。
sNow.lua:
emiRange = 2.0
veloRange = 0.006
position = { 0.0 , 4.0 }
accel = { 0.00005 , - 0.0001 , 2.0 , 0.00 , 1.0 }
colorMax = { 0.0 , 1.0 }
psizeMin = 0.3
psizeMax = 0.5
maxCount = 3000
emiCount = 10
emiInterval = 0.01
texture = " sNow.tga"
最新的源代码: http://download.csdn.net/source/1663374
以上是内存溢出为你收集整理的基于Direct3D实现简单的粒子系统(二) - 增加LUA脚本支持全部内容,希望文章能够帮你解决基于Direct3D实现简单的粒子系统(二) - 增加LUA脚本支持所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)