基于Direct3D实现简单的粒子系统(二) - 增加LUA脚本支持

      之前已经创建了一个简单的粒子系统(点这里 ),但是使用起来还是不是很方便,这次的任务就是为这个系统增加脚本支持。使用脚本来定义粒子系统的各项属性,再从主程序中将这些属性读出来,创建粒子系统。我对小巧简洁的东西有种特殊的喜好,因此我选择了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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.github代码实践源代码是lua脚本语言,下载th之后运行thmain.lua-netTypevgg-savevgg_cifar10/-S0.0001,报错: 试看看安装lua:报错了,参考这篇文章:ubuntu18.04安装lua的步骤以及出现的问题_weixin_41355132的博客-CSDN博客问题解决,安装成功:情况并没有好转,出现相
此文为搬运帖,原帖地址https://www.cnblogs.com/zwywilliam/p/5999924.html前言在看了uwa之前发布的《Unity项目常见Lua解决方案性能比较》,决定动手写一篇关于lua+unity方案的性能优化文。整合lua是目前最强大的unity热更新方案,毕竟这是唯一可以支持ios热更新的办法。然而作
Rime输入法通过定义lua文件,可以实现获取当前时间日期的功能。1.TIMERime是一款可以高度自定义的输入法,相关教程可以查看往期文章,关于时间获取是指输入一个指定关键字,输出当前时间,效果如下(我定义了time关键字):实现如下:①在用户文件夹中新建一个rime.lua文件加入如下代码 ti
localfunctiongenerate_action(params)localscale_action=cc.ScaleTo:create(params.time,params.scale_x,params.scale_y)localfade_action=cc.FadeIn:create(params.time)returncc.Spawn:create(scale_action,fade_action)end
2022年1月11日13:57:45 官方:https://opm.openresty.org/官方文档:https://opm.openresty.org/docs#table-of-contents为什么建议使用opm不建议使用luarocks?http://openresty.org/cn/using-luarocks.html官方解释:请注意!LuaRocks并不是OpenResty官方推荐的装包方式。LuaRoc
在Lua中的table(表),就像c#中的HashMap(哈希表),key和value一一对应。元表:table的一个操作的拓展,里面包含关联了对应的方法,元方法就是其中一个。元方法:当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index键。如果__inde
表排序:table.sort(list[,comp])参数list:指定表,可选参数comp:排序函数,无参数时通常按升序排序。排序函数针对表中连续的序列,其间不可以存在空洞或nil,排序函数需要两个形参(对应表中每次参加比较的两个数据),需要一个比较两个形参表达式的返回值,不能含有等于关系,例如>=,<=,==。do
一、安装lua环境1.1安装依赖包[root@centos7~]#yuminstallgccreadline-devel1.2下线lua源码包并解压[root@centos7~]#wgethttp://www.lua.org/ftp/lua-5.3.5.tar.gz[root@centos7~]#tarxvflua-5.3.5.tar.gz-C/usr/local/src1.3进行编译[root@centos7~]
官网OpenResty® 是一个基于 Nginx 与Lua的高性能Web平台,其内部集成了大量精良的Lua库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态Web应用、Web服务和动态网关。OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由
表参考《lua程序设计》可以认为,表是一种动态分配的对象,程序只能操作指向表的引用(或指针)。除此以外,Lua语言不会进行隐藏的拷贝(hiddencopies)或创建新的表--创建表a={}--创建空表k="x"a[k]=10--键“x”值10a[20]="great"--键20值“great”print(a["x"])-->10
https://github.com/galenho/crossover.git一个跨平台的lua游戏服务器开发框架,该框架采用多线程并发来处理消息,开发者只需要调用相应的接口函数并绑定相应的回调函数即可,在逻辑层表现为单线程的开发模式,使开发者易用,易调试,易维护,易扩展,同时拥有快速的响应能力。   框架使用面
参考链接:https://www.runoob.com/lua/lua-metatables.htmlhttps://www.jianshu.com/p/cb945e7073a3 元表是一个table,可以让我们改变table的行为,每个行为有对应的元方法例如,对table进行设置键值,查找键值,运算等,就会触发对应的元方法1--__index:table被访问时,如果找不到这
https://github.com/yuin/gopher-luahttps://github.com/yuin/gopher-lua Lua5.1ReferenceManual-contentshttp://www.lua.org/manual/5.1/ go中使用luapackagemainimport( lua"github.com/yuin/gopher-lua")funcmain(){ l:=lua.NewState() d
编译问题不要留到运行时才跑出来啊。早上9:00-中午3:00,6个小时,服了自己了。 写了一个测试,springboot+redis+lua执行到redisTemplate.execute(redisScript,idList)的时候一直报错,integer无法转换为string。我一直以为是lua脚本写错了,翻文档翻过来又翻过去,写法变了又变,还是解
        。。是字符串连接符,字典用=号连接,  注意fordoend都是连一起,  注意ifthen,  如果local在函数里,是可以访问,非local出了函数一样能用,  doend代码块也是一样,    注意点号表示,只能key是字符串,  注意括号不是必须
C语言与Lua之间的相互调用详解写一个C调用Lua的Demo编译运行C语言调用Lua编译问题总结正确的编译命令问题1:缺少-lm参数问题2:缺少-ldl参数​1、为什么会出现undefinedreferenceto‘xxxxx’错误?​2、-l参数和-L参数写一个C调用Lua的Demo编译运行add.c内容//你需要
1、动态输出打开E:\study\openresty\openresty-1.19.9.1-win64目录下的confginx.conf文件在server中增加一下代码 location/hello{ default_typetext/html; content_by_lua'ngx.say("<p>hello,world</p>")'; }运行后,效果如下图localhost
参见:lipp/lua-websockets:WebsocketsforLua.(github.com)github网址可能需手动转换lipp.github.com/lua-websockets/>github.com/lipp/lua-websocketswebsockets为底层的类似于TCP、UDP的socket(实现上基于更底层的socket),不同于上层的webserver服务端(Service)需并行地支持多
lua发送消息到rabbitmq,我们选择类库lua-resty-rabbitmqstomp 来完成这个任务。类库安装:进入nginx.conf中 lua_package_path 中对应的目录下的resty目录(没有则创建),执行:wget-chttps:/aw.githubusercontent.com/wingify/lua-resty-rabbitmqstomp/master/libes
1Lua介绍Lua是一门以其性能著称的脚本语言,被广泛应用在很多方面。Lua一般用于嵌入式应用,现在越来越多应用于游戏当中,魔兽世界,愤怒的小鸟都有用到。优势Lua极易嵌入到其他程序,可当做一种配置语言。提升应用性能,比如:游戏脚本,nginx,wireshark的脚本兼容性强,可以直接使用C