本帖最后由 slxc920113 于 2013-5-16 20:32 编辑
1. 首先科普一下lua这种脚本语言 Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。 Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。 参考文献:
2. 一些使用lua语言的游戏 《愤怒的小鸟》中关卡文件,一代以后的文件已经加密了,无法直接用文本编辑器打开,需要转码。 大量网页游戏的数据库文件,这就不举例。
3. lua基本语法 熟悉C/C++,java等各种其他语言的请无视之……基本一样。 一、数据类型 和javascript、perl等脚本语言一样,Lua是动态类型语言,变量不要类型定义。 Lua有8种数据类型:nil、boolean、number、string、userdata、function、thread和table。 nil代表无、空值,等价于C语言中的null,VB中的empt。 Boolean代表关系运算中的布尔值,值为true或false,在一些其他语言中也写成0或非0。 Number代表实数,可以是整型、长整型、浮点型…… String代表字符型,即常说的文本类型。和python一样, Lua中字符串是不可以修改的,只能生成新的字符串。转义字符、ASCII码和C语言完全一样。 Function是函数,不解释。 Userdata和thread暂时用不到,请无视之…… 二、表达式 算术运算符:+ - * / ^ (加减乘除幂) 关系运算符:< > <= >= == ~=,返回结果为false或者true 逻辑运算符:and or not(不认识这个的向小学老师忏悔去……) 连接运算符:print("Hello" .. "World") -->Hello World。注意“..”的前后要加空格。 表的构造(即数组):和C语言不同的是,lua的数组是从1而不是0开始数的。 例如:days = {"Sunday", "Monday","Tuesday", "Wednesday", "Thursday","Friday", "Saturday"} print(days[4]) --> Wednesda
三、语法 赋值:a = "hello".. "world" 局部变量:local i = 1 结构语句: if 条件 then 命令 end; if条件then命令else命令end; if 条件then命令elseif 条件 then 命令else 命令end; while 条件do 命令; end; repeat命令; until 条件; for var=初始值,结束值,步长 do命令 end 还有一种遍历for,不好简单表示,会拿具体的函数说明。 break语句用来退出当前循 return用来从函数返回结果 4. 具体的MOD教程开始了,请注意听讲哦…… 先看官方给的sample,好吧,允许我吐槽一下,从来没见过比这个更简单的官方MOD教程。 --[[ *************************************************************** Created by: JamieCheng Date: February 20,2013 Description: Samplemod that shows how to: - add post init functions for prefabs,components, simulation - edit tuning values - create your own component *************************************************************** ]]-- 解释:--[[*******]]--里面的都是注释,这种格式代表多行注释,不知道神马叫做注释的自行度娘。 --special post-initfunction for Wilson 解释:--*****也是注释,这种格式表示单行注释,就是从--开始到本行结束都是注释内容。 functionwilsonpostinit(inst) 定义了一个名叫wilsonpostinit的函数,变量inst,至于什么是inst,估计表示当前对象吧。 print "hello wilson init!" 输出hello wilson init!,就像Hello World一样吧,好经典。 --halve wilson's max hunger oninitialization 看注释的意思是在初始化的时候修改威尔逊的最大饥饿值。 inst.components.hunger:SetMax(TUNING.WILSON_HUNGER*0.5) 将对象inst的components中的hunger的值设置为TURNING中WILSON_HUNGER的值的0.5倍。表达有点奇怪,确实不好说明,”.”表示的是节点,这儿components.hunger表示data\scripts \components\hunger.lua文件,TUNING.WILSON_HUNGER表示data\scripts\turning.lua文件中WILSON_HUNGER = 150,--stomach size这一句。 --add your owncomponent, defined in mods/[yourmodname]/scripts/components/myowncomponent.lua 上面注释的意思就是,添加自定义component的方法,把文件丢到mods/[你的mod文件夹]/scripts/components/[自定义的文件].lua inst:AddComponent("myowncomponent") 为当前对象添加一个名叫“myowncomponent”的Component functiongamepostinit() print "hello game init!" --if you want to load your own prefabs,this is where you'd do it --TheSim: LoadPrefabDefs(MODROOT.."prefabs.xml") 这是说明添加物品的方法,具体例子以后介绍。 end --override specifictuning values here! TUNING.WILSON_HUNGER = 50 这个是修改TUNING文件中的值,TUNING文件中保存了大量初始定义值,通过上面这中格式进行修改
MOD实例说明:
第一类:覆盖型,就是data中的文件进行修改,然后放到mod文件夹下的相同根目录。
举个例子,more_harvest,论坛里面有收获10个蔬菜,一锅煮10个,都是这一类。 具体制作过程: 1. 在mod文件夹下新建一个文件夹,比如more_harvest,这也是你的mod的名称。 2. 然后找到需要修改的文件,直接先拷贝过来。data\scripts\ components\ crop.lua,打开看一下,发现一个函数function Crop:Harvest(harvester),游戏的函数命名习惯很好,直接从字面上了解意义:Crop下面的Harvest子函数,(收获粮食)。 function Crop:Harvest(harvester)--注意变量是harvester,就是说这个函数只作用于采集者 if self.maturedthen--如果self(指作物)成熟了,然后 local product = SpawnPrefab(self.product_prefab)--刷出将当前作物代表的prefab物品,赋值给局部变量product harvester.components.inventory:GiveItem(product)为采集者的inventory中添加物品,因为inventory属于components的子文件,所以必须写成harvester.components.inventory ProfileStatsAdd("grown_"..product.prefab) self.matured =false--后面一系列文件是清除对象,就是已经收获了,全部清零 self.growthpercent = 0 self.product_prefab= nil self.grower.components.grower:RemoveCrop(self.inst) self.grower = nil return true end end 3.开始修改,比如需要一次收获10个 把harvester.components.inventory:GiveItem(product)这句多运行几遍,那么就多获得几次物品 比如改成:local num = 1 for num = 1,10 do harvester.components.inventory:GiveItem(SpawnPrefab(self.product_prefab)) end 表示循环运行10次 当然最笨的办法,直接把harvester.components.inventory:GiveItem(SpawnPrefab(self.product_prefab))复制粘贴十遍 再比如,无限收获次数。 self.matured= false self.growthpercent= 0 self.product_prefab = nil self.grower.components.grower: RemoveCrop(self.inst) self.grower = nil 这几句全部无效化,改成注释,就是在前面添加”--” --self.matured= false --self.growthpercent= 0 --self.product_prefab = nil --self.grower.components.grower: RemoveCrop(self.inst) --self.grower = nil 4. 注册MOD,在文件夹下创建modmain.lua文件,随便写点注释。 5. 安装MOD,别告诉我你不会…… Ps:那个一锅煮10个和这个原理一模一样,可以自己尝试修改。
我再举一个其他的例子,笼中的鸟儿。文件scripts\prefabs\ birdcage.lua 第一个函数: local function ShouldAcceptItem(inst, item) local seed_name =string.lower(item.prefab .. "_seeds")--这个很有意思哦,种子名称(seed_name)赋值为物品名称(item.prefab)加上seeds,还记得前面说的,”..”是连接符。 local can_accept =item.components.edible and (Prefabs[seed_name] or item.prefab =="seeds" or item.components.edible.foodtype == "MEAT") --这儿是决定鸟儿吃什么,首先得是可食的(item.components.edible),并且必须是种子(包括有种子的粮食)或肉。 if item.prefab =="egg" or item.prefab == "bird_egg" or item.prefab =="rottenegg" or item.prefab == "monstermeat" then can_accept =false end--然后进一步,如果符合上面的情况之后,物品是蛋、鸟蛋、臭鸡蛋、怪物肉的话,不接受(can_accept= false) return can_accept end 如果把这些条件修改了,比如if之后到end无效化,那么鸟儿就可以吃蛋、鸟蛋、臭鸡蛋、怪物肉, 如果再进一步,把local can_accept = item.components.edible and(Prefabs[seed_name] or item.prefab == "seeds" oritem.components.edible.foodtype == "MEAT")改成local can_accept =item.components.edible那么鸟儿就什么都吃 如果再进一步,直接--local can_accept……(无效化),天哪,那是饕餮吗?真不挑食。
后面一个函数 local function OnGetItemFromPlayer(inst, giver, item) ifitem.components.edible then localseed_name = string.lower(item.prefab .. "_seeds") localcan_accept = Prefabs[seed_name] or item.prefab == "seeds" oritem.components.edible.foodtype == "MEAT" if can_acceptthen--上面这部分和前面一样哦 inst.AnimState: PlayAnimation("peck") inst.AnimState: PushAnimation("peck") inst.AnimState: PushAnimation("peck") inst.AnimState: PushAnimation("hop")--这四句是动作,不用管 inst.AnimState: PushAnimation("idle_bird",true) inst: DoTaskInTime(60*FRAMES, function() ifitem.components.edible.foodtype == "MEAT" then--如果吃的是肉,下蛋 inst.components.lootdropper:SpawnLootPrefab("bird_egg") else if Prefabs[seed_name] then--如果吃的是种子或蔬菜 localnum_seeds = math.random(2)--种子数目,随机数0-2 fork = 1, num_seeds do inst.components.lootdropper:SpawnLootPrefab(seed_name)--拉出种子 end ifmath.random() < .5 then inst.components.lootdropper:SpawnLootPrefab("seeds") end else inst.components.lootdropper:SpawnLootPrefab("seeds") end end end) end end end 修改: 如果要鸟儿多下几个蛋,比如10个,修改nst.components.lootdropper:SpawnLootPrefab("bird_egg"),方法和前面收获10个一样 如果要鸟儿拉10颗种子,local num_seeds = math.random(2)改成local num_seeds = 10 貌似大家对MOD这种影响平衡的东东不感冒,算了…… |