北大侠客行MUD论坛

 找回密码
 注册
搜索
热搜: 新手 wiki 升级
查看: 5080|回复: 3

读“从零开始学lua”笔记

[复制链接]
发表于 2015-6-2 09:11:03 | 显示全部楼层 |阅读模式
本帖最后由 ltblue 于 2015-6-2 09:40 AM 编辑

由于刚刚看到这个帖子,所以写一下笔记吧,就当灌水了,呵呵
“小刀是在刻意模仿《Programming_In_Lua》这本书”
真好,这本书也是我用来写mush的手册,之前从未接触过lua,所以基本上是看着手册来写的


“这个操作,证明了我们已经搭建了一个可以正常运行的Lua环境。”
事实上,我到现在都没有搭起来测试的环境......我是很最近才知道可以在mush里写lua代码的,以前一直只会调用函数,多一点都不敢写


“大家好,这里是多行书写,请注意行末没有加;”
实际上,我现在的代码还没有统一,早期为了规范,写了分号,后来写着写着就忘了,反正不报错,也就不加了
关键是经常写数据文件,用table,table要加逗号(,),而有时候在写代码忘了,也加了逗号(比如在代码里写a.b.c="abc",),于是就出错了......


“Lua中的变量分成全局变量和局部变量”
事实上,我是在写lua之后,在开始注重加local的,以前写其他代码都喜欢全局变量,甚至还特地有个“变量表”来记录所有用过的变量
不过变量名的写法我仍然极其不规范,什么大写代表什么,小写代表什么,先大写后小写,先小写再大写等。
基本上能用英文的用英文,我英文极差,所以拼音也是少不了的
我最常用的一个函数iftf,是用来检查突发情况的,整个程序到处都是,含义呢?iftf=if突发......真心中国人看不懂外国人看不明白啊......

“⑵ 注意:Lua是大小写敏感的。”
啊?我现在才知道是敏感的......
怪不得用Send必须大写,小写不过呢......



--[[
print("这里是多行注释")
--]]

报告,在经常使用map[where].name这样的变量的我来说,不好用啊......


”nil这个小刀认为,写机器人没帮助,就直接过掉了。“
哇,竟然被放弃了?我的程序满地都是nil......
不对啊,不是vil吗?是不是弄错了?我都写vil啊

”true、false这两个,琢磨半天,也放弃了。原因有两个:一是,返回值的判断,可以用1和0来代替,相信这个对于普通人更直观一些;二是,想了半天,实在想不,怎么用浅显易懂的话来描述这两个概念。so……“
这个......我都用”yes“和”no“来代替,简单直观......

”functions这种将函数存入变量的灵活方式,就不要拿来折腾新手了吧。“
哈哈,果然我是新手,就不会用这种方式,最近才知道可以这么用

”Userdata可以将C数据存放在Lua变量中,Threads就是所谓线程。这种一看就是高大上的东西,就先不要来折磨我们的心灵了吧。“
这个我到现在都不知道是什么......


“北京遇上西雅图”
这是神马啊?

“谁的眼角触了谁的眉”
我......

“谁的笑容抵了谁的泪”
哇......

“谁的掌纹赎回谁的罪"
无力吐槽了......

”简单说明一下,字符串和数字连接可以不这么麻烦,但有某种情况之下,直接连接会报错的。而且这种错是很难查出来的。试想一下,一个你以前一直认为正确的写法,事实也一直证明是正确的,因为某个特殊情况,就变的不对了,那得有多逆天才能查出来。为了避免这种情况出现,建议各位初学者,在连接字符串和数字的时候,统一做一下转化吧。俗话说的好,行走江湖,安全第一,安全第一。“
字符串和数字,我一直都用..直接连啊,竟然会报错?
事实上,我从来没用过tostring这个函数,tonumber倒是常用(还常用自己写的getnumber(str)函数,返回2个值,作用是把str中第一个汉字版本的数字部分转化为数字作为返回值1,并把剩余部分作为返回值2,比如输入”一百零三个石子“,就会返回103和”个石子“)







这个图是头领级的啊,我得仔细研究一下
比照了以下,我缺少”mush内的变量“一栏。实际上,我的所有变量都在lua里,mush的变量我完全没用,不知道有什么弊端,再往下读吧
另外,我引用了很多外部数据,都是以table格式存的,比如map(地图数据文件),比如data(游戏数据文件),比如config(设置文件),然后直接requie进来


”以前小刀觉得Lua更好(其实现在也是),但最近发现MUSHclient变量对于新手有一个独特的优越性,所以打算大力介绍一下;“
我一直存在lua中,是不是因为我已经不算新手了呢?呵呵,可喜可贺啊


”  什么是变量?
  什么是赋值?
  什么是表域?

本来以为能跳过去了,不过......什么叫”表域“呢?还得认真读啊


”一般情况下,n_变量名,表示存放的是数字(number);s_变量名,表示存放的是字符串(string);a_变量名,表示该变量是数组(array);t_变量名,表示该变量是临时变量(tmp)“
到现在也没这习惯,还是在每个lua文件的开头,有一个全局变量表(或者函数开头有个局部变量表),又或者是一个大table,然后把变量初始化声明一下,并在声明后面注释其作用
大概15年前吧,用”文曲星“里的gvbasic写程序,那时候还是有行号的呢,由于每行最多只能输入64个字符,整个程序超过8k就要出错,所以所有变量名最多2个字母(为了省地方),本子上密密麻麻记录的都是变量表......现在的变量名起起来宽松了,也规范了,可惜我的习惯还是没改啊......


”最后说一下,为什么建议新人使用MUSH变量,因为MUSH的值,可以在不操作任何Lua代码的情况下,直接在MUSHclient客户端里看见,这一点,实在是方便极了。“
所以我自己写了个printd(debug,v)的函数,用来代替print,然后为了调试,满程序都是print......
不过mush应该不支持table吧?我的变量大部分都是table,mush里支持不了,写进去也看不到


”表域(可以理解为数组)“
我还在想,表域是啥意思呢?原来是table啊......


换个页先
打了这么多字,不能算灌纯水吧?求别删......

评分

参与人数 1精华 +2 收起 理由
ffdm + 2 先奖励2gold 后面有自己的见解 继续打赏

查看全部评分

北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-6-2 10:08:18 | 显示全部楼层
本帖最后由 ltblue 于 2015-6-2 10:09 AM 编辑

”不知道,大家对集装箱有没有概念,就是那种很大的铁柜子,一般做对外贸易用的比较多,铁柜子打开以后,里面可以放许多纸箱。(我想不需要真的放一张集装箱的图片上来吧?)“说真的,要找装满了纸箱的集装箱图片你未必找得到......


”但总是有些情况是需要数组来解决的“
其实最早学程序的时候,我师父给我出了个题(师父是同学,现在在国家安全局管网络......),就是排序。现在看来排序不是个问题,当年我不懂数组,愣是用if搞定了10个数的排序......师父都崩溃了......然后才发现我还没学到数组那章......


”应该把具有相关性的数据放进一个数组“
其实我现在就犯了一些错误,比如任务数据,到底放到quest数组里,还是sta数组里(sta指状态,原谅我英文不好吧......)。关键我quest数组里全是任务名......


”先说一下,代码开头那行——require "tprint"——这是MUSHclient自带的一个查看数组的扩展,使用很简单,看一下就会,效果不错。“
还有这东西?mush我只看了一个wait.lua,其他一概没用过啊......我输出数组都用”table.concat“,具体啥用法也不知道,百度查的


”但类似t_quests格式也不是完全没有缺点,因为Lua默认的数组下标是从1开始的(这点跟绝大多数的编程语言不同),而且许多内置的操作都是仅针对下标从1开始的数组。当然,解决方案也不是没有,这个请放心。“
实际上,table的两种格式用起来很方便,但问题也很多,光说遍历就得分两种——还未必成功
绝大部分情况下,我都不混用,或者基本不混用,个别的时候混用也很谨慎
比如我的sta_cha函数,就是查看技能的函数,我在sta.cha中,除了有[1][2][3]这样的内容,也有一个特殊的ing="doing",用来确定此函数是否正在运行(没运行完就针对内容处理是很危险的,而我的这个东西放在单独的协程中,所以必须等ing="done",才能确保读取的内容准确,至于为什么放在协程里......我的本意是为了效率,虽然不确定能提升多少)



print(t_quest["hyd_city"] )  --显示出城市名
print(t_quest.hyd_name) --显示出任务人名,这里用了另外一种方法,两者是等价的,小刀最近看论坛代码,发现这两种都有人用,特此指出

实际应用上,这两者有时候不见得能一起使用,比如
我在一个数组里要查找一个值,这个值的下标是另外一个数组里的一个值
比如我要在map数组里查找下标是where.now的值,我写
map.where.now显然是不合适的
一般我写成
map[where[now]]
就比较方便了
可惜这样的代码会影响多行注释,比如想把这段多行注释掉,我写
--[[,就会碰到这样里的]],然后注释就停掉了
当然,写成map[where.new]也是没问题的,我只是举个例子




”先要说明一点,这里的遍历,是指读取数组内每一个值,而不是北侠论坛机器人版上一直比较神秘的遍历。按北侠机器人守则,这个是不允许讨论了,抱歉了。“
啊?版规还不让谈遍历?我才知道。但我记得在论坛里看过谈遍历的帖子啊,还有画图呢,奇怪了


”数组的遍历,是一个实用性比较强的功能,但因为Lua比较坑爹的table功能,在使用过程中需要比较小心,不然的话会出一些很麻烦的错误,下面会详细说明。“
深表同感,感同身受。不过table真心方便啊。lua本身就是个及其方便的语言,各种不规范,但出错也难找反正......变量名写错了我都不知道......有一次命名是score,我写成了scroe,愣是找了好久......


”要在循环结束时将需要的值取出“
应该是作用域的事吧?for的都是局部变量


”在实际工作中,一般建议使用方案C来代替方案A。一来,两者使用效果基本一样,方案C的书写更简单一些。二来,细心的同学可能会发现,方案A和方案B实在太接近了,两者就差了一个字符。哪怕是为了减少误写的可能,也是选择方案C比较好一些。“
实际上,我一直保持的是方案c来写,不过那个#我不懂,我一般是这样
for i=1,table.getn(tablename) do
就是取一下最大值
不过我的table都是连续的,没出现不连续的情况,可能是危险的举动吧?


”在这里给诸君留一个作业,根据上面的代码和运行结果,能分析出什么注意点吗?“
这就是table坑爹的一个部分了——顺序未知
鬼知道会以什么顺序遍历......
用在其他地方还好,用在地图文件里,由于人要看的嘛,就会非常的莫名其妙,出现很多可笑的东西
不过我在网上找到了一些代码,可以对table进行排序,方便多了


function pairsByKeys(t)
--按顺序的pairs

    local a = {}     

    for n in pairs(t) do      

        a[#a+1] = n     

    end     

    table.sort(a)      

    local i = 0      

    return function()         

        i = i + 1         

        return a, t[a]      

    end
end


具体啥意思我也不知道,反正好用就是了......
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-6-2 10:20:17 | 显示全部楼层

通过上面的学习,诸君应该有以下认识:
1、计算机其实是很笨的,而且是个死心眼,一定要按照它明白的方式来书写代码,不然的话,它不会认帐;“
如果有人学了lua之后,再学其他语言,才会真的觉得死心眼吧......lua是我遇到的最灵活的语言了,啥都认,咋都不出错,语法及其宽松,真心适合初学者啊


”编程和诸君目前手上的工作没有任何区别,如果非要找出一个区别来的话,那只是诸君目前对编程这件事还没有属于自己的认识。一旦有了,编程完全可以和诸君手中的工作一样,变得非常简单。“
我不知道大家做的什么工作,反正对我来说,编程比我现有工作难多了......

”本身不影响程序的走向,只是在正常的过程中,加入一个判断“
这句话已经不是语法上了,而是从编程思路上的理解了。
if--end,不影响主进程,反正要回来的。
当然,如果你在if中有return等内容,那么其实end就相当于else了,只是书写方便一些罢了。

”想了一下,在mud里,很少有纯粹使用if+else+end的,因为分割的条件极少有一种(就是所谓两分)“
实际上,我经常判断某变量是否为空,不为空时如何,为空时如何,所以就一个else,比如
l,w=wait.regexp("渡河成功|渡河失败",3)
if l then
  if l=="渡河成功" then
     XXX
  elseif l=="渡河失败" then
     XXX
  else
    print("出错1")
  end
else
  print("出错2")
end
大体就是这样,比较保险吧,虽然代码很烂
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
 楼主| 发表于 2015-6-2 11:07:33 | 显示全部楼层
"如果是有编程基础的,只要一句——类似case——就可以解决问题。"
不得不说,虽然我知道什么是case,但我从没用过case这类的东西
因为case之前的那个sw什么的单词不会拼!
所以从来都是if....elseif....elseif...end......
另外补充一句,前一段写打坐模块的时候死循环,后来发现就是elseif出错了
elseif不等于else    if,区别很大
我在打坐时用到了elseif,就是当什么情况下打坐,什么情况下疗伤,什么情况下吐纳,什么情况下练功,什么情况下要去找大夫(薛慕华)。
但在某个elseif中,我写下了大概这样的代码
elseif  AAA then
   if  BBB then
       CCC
   end
elseif DDD then
......
这就导致,当满足AAA条件时,进入此分支,而进入本分支后,BBB的条件又不满足,于是整个本轮if跳过,而我外面有个while true do,于是死循环了
改正办法是
elseif AAA and BBB then
   CCC
elseif DDD then
......
这样问题就解决了
基本功还是不扎实啊





又见大图



总体来说感觉这个框架有点简单啊

我觉得哈,可以有以下改动
1.把取钱吃饭买武器学习,以及做任务,都当成平等的任务来对待,这样框架写起来比较容易添加新的东西
2.把一个任务分成几个模块,分模块的原则是:任何时候,可以从本模块的开头执行本模块,而不用管这个模块运行到哪步。换句话说,我不需要知道这个模块做到哪了,我从头做,都能跑的通,这样的原则来确立模块。因为一旦出现突发情况,有风吹草动,我必须去处理其他事情,而回来时,我必须知道自己之前正在做什么,而且能继续做,而不用放弃掉整个任务从来。
当然,一些简单的任务,不需要分模块,比如吃饭喝水,是因为这些任务本身就可以从头做也跑得通。比如吃饭,我正在去茶馆的路上的时候,被人pk了,我就要去处理pk。等pk结束,假设还活着的话(死了就是另外的事了),我可以从头运行吃饭喝水模块,再一次往茶馆跑。
相反,如果是送信任务,如果不分模块,半路被人pk了,那么pk结束,我就只能回去重新接任务——而任务本身已经接完了,就还得重新开始。而如果我分模块,我是接完任务向目标移动的时候被pk的,那么处理完pk事宜后,我会“重新”开始往送信目标那里跑。这样可以提高效率。
3.“任务是否存在”应该是有记录的,而不必跑到npc那里问,会影响效率。
4.初始化没必要每次都进行得很彻底,比如cha就没必要每次做——开头做一次,中间每次升级自己都有记录,就没必要看cha。不过为了定时校准,可以在一个不费时间的时候cha一下,并不等待,比如我是在过江过河的时候cha一下,更新一下,确保信息准确。这样的目的,还是效率......

我目前机器人最缺乏的,是“提高”这一块,当然由于机器人还没写完,这一块也还谈不到,但我下一步打算记录走过路过看到的npc,并根据频度,剔除掉随机生成的npc和玩家,只保留固定的npc,并写入地图,虽然估计没啥用......
北大侠客行Mud(pkuxkx.com),最好的中文Mud游戏!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|北大侠客行MUD ( 京ICP备16065414号-1 )

GMT+8, 2024-11-24 04:46 PM , Processed in 0.010345 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表