加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 Sion 于 2013-12-17 15:56 编辑
我在某群看到有人问,如何开始学习脚本
这个问题不是问我的,其实我脚本也不算多厉害,只自己写过几个简单的,不过在这里共享一下自己的思路。
我首先想到的是,学习Ruby。不过有人说,他最开始改脚本,没学Ruby,后来才看的。
我是这么想的,看Ruby的过程,不一定要把它全部学会,但是至少你得知道编程是个怎么回事,知道Ruby有什么东西可以用。就算你一时没记住,在你看脚本的时候看到了这玩意,你也大概知道是什么,去查查就明白了。
以下是我想到什么写什么的无条理Ruby介绍,都是理论知识,可以直接转到下面看更改脚本去。
Ruby是面向对象的
什么叫面向对象?
首先根据客户需求抽象出业务对象;然后对需求进行合理分层,构建相对独立的业务模块;之后设计业务逻辑,利用多态、继承、封装、抽象的编程思想,实现业务需求;最后通过整合各模块,达到高内聚、低耦合的效果,从而满足客户要求。
如果你不是学计算机的,上面这么说简直看不懂。所以我们来看例子
class Greeter def initialize(name = "world") @name = name end def say_hi puts "Hi #{@name}!" end def say_bye puts "Bye #{@name}, come back soon!" end end
class Greeter
def initialize(name = "world")
@name = name
end
def say_hi
puts "Hi #{@name}!"
end
def say_bye
puts "Bye #{@name}, come back soon!"
end
end
以上这个例子是我抄来的。我们来看看这是什么意思。
我们定义了一个Greeter类,这个类就是所谓的业务对象。我查了查Greeter的意思,是接待员。
这个接待员他可以做什么?他可以跟你打招呼(say_hi),还有说再见(say_bye)。这个类能做的每一个动作,都是一个方法。
但是目前我们看到这个Greeter里面一共有3个方法,还有个initialize方法。这个方法是在初始化Greeter的实例的时候用到的。
如果你要获得一个接待员的实例,那么你就要Greeter.new。意思是新建一个Greeter的实例。(实例和类的区别是什么?就好像人和吉姆的区别,动物和兔子的区别。恩,具体我也说不清,目前我也没有查书,你们意会吧。。)
在你使用Greeter.new的时候,调用了Greeter的initialize方法。initialize是在新建实例的时候一定要执行的方法。
方法是怎么回事呢?你可以简单的理解成我们学的方程,函数y=f(x)=4x+6
把这个函数写成Ruby的方法就是
def f(x)
4*x+6
end
如果你想要调用这个方法计算变量为10的结果,就直接写f(10),
你可以写n个变量
def 方法名(变量1,变量2..变量n)
方法执行过程
end
也可以不要变量
def 方法名
方法执行过程
end
在这个Greeter的initialize方法中,我们看到括号里写的是name = "world"。意思是这个name默认是world。(学习所有语言的最开始都是个Hellow World啊)
意思就是,如果你写g = Greeter.new,那么g在打招呼(g.say_hi)的时候,他会说"Hi world"。如果你写g = Greeter.new("asd11000"),他打招呼的时候会说"Hi asd11000"
VA的脚本里也有这种存在默认值的情况,一般有默认值的变量都会出现在方法的括号里的后几位,如果你写(a, b=0, c, d=1),那你调用方法的时候电脑就不知道你写的3个变量究竟是abc还是acd了。
Ruby的变量和常量
Ruby的变量有一定的规则,以$开头的一定是全局变量,以@开头的都是实例变量,而以@@开头的是类变量。常数则以大写字母开头
以上例子里,你可以看到@name,这个就是实例变量,在Greeter的各个方法里都可以使用这个变量。
全局变量嘛,VA里的$game_party什么的就是,你可以在DataManager那个脚本里看到很多很多的全局变量
像Greeter的initialize方法里那个name,是局部变量,只能在initialize的内部使用
类变量目前我改那几个简单脚本的时候还没用到过,如果我没记错的话,如果你给Greeter设计了一个类变量@@a(原谅我贫瘠的想象力吧。。我不知道起个啥名字,就叫a好了),那么你要使用它的时候,直接写Greeter.@@a(如果我记错了,请大家纠正。。我懒得查了呢。。)
关于常量嘛,我们在写代码的过程中,可能会以不同数值代表不同的意思,但是有的时候记不住倒是哪个数字对应哪个意思,那么你可以定义常量
比如VA的脚本Game_BattlerBase,写了一排常量,到时候调用它们只要写前面的常量名即可,记数字什么的太麻烦了。
顺便提以下这两个东西(我从Game_Temp复制出来的)
attr_reader :common_event_id # 公共事件ID
attr_accessor :fade_type # 场所移动时的淡出类型
Game_Temp里有@common_event_id和@fade_type这两个实例变量,只能在Game_Temp里面使用。如果你希望其他不属于Game_Temp的方法也能使用这两个实例变量的话,就可以写attr_reader和attr_accessor
这两个的区别是,设置了attr_reader的实例变量只能被读取。
比如你g = Game_Temp,你就可以使用g.common_event_id来读取。
而设置了attr_accessor你不仅可以读取他,还可以给他重新赋值:g.fade_type = 2(太二了- -!)
继承
再来个例子
class Person def initialize(person_name ) @person_name = person_name end def talk(content) puts content end def say_hi talk("Hi, I am #{@person_name }!") end def say_bye talk("Bye!") end end class Greeter < Person def initialize(person_name, name = "world") super() @name = name end def say_hi talk("Hi #{@name }! I'm #{@person_name }.") end def say_bye puts "Bye #{@name}, come back soon!" end end
class Person
def initialize(person_name )
@person_name = person_name
end
def talk(content)
puts content
end
def say_hi
talk("Hi, I am #{@person_name }!")
end
def say_bye
talk("Bye!")
end
end
class Greeter < Person
def initialize(person_name, name = "world")
super()
@name = name
end
def say_hi
talk("Hi #{@name }! I'm #{@person_name }.")
end
def say_bye
puts "Bye #{@name}, come back soon!"
end
end
以上的两个类,未经运行测试。。
首先那个Person,就是最上面的Greeter改了一下。打招呼的时候会报上自己的名字。我添加了一个talk的方法,在打招呼和说再见的时候进行调用。一般编程的时候,每一个方法里的代码行数最好不要多,方便自己阅读和修改。
下面的Greeter继承了Person(class Greeter < Person)。继承了以后,Greeter就拥有Person的所有变量和方法。所以你看到Greeter里没有写talk这个方法,但是它还是可以用。而say_hi和say_bye两个方法都被重写了,意思是Greeter的实例调用say_hi的时候,运行的是下面这个新写的say_hi。
好了,基础知识就讲到这里。。(尼玛。。语法什么的就讲这么点。。)
不管,改个脚本瞅瞅
前几天看到有人求改暴击率。这脚本简单,我们来改一下。
以下是思路:
1 先找找暴击率这玩意在哪里吧。。哎。。这么多代码啊~还好有备注。(#后面跟的是备注,绿色字,这个知道吧~)
既然是队伍成员的暴击率,当然得找队伍成员啦~在对象这个分类下的脚本瞅瞅,有个Game_Actor,看注释是管理角色的类!就看这个。
看完脚本的注释发现居然没有提到暴击率!
那么我们去看看他继承的父类吧,没准在父类里面定义了。。class Game_Actor < Game_Battler,去找Game_Battler看看。
.....................................还是没找到!继续看父类!class Game_Battler < Game_BattlerBase
在可爱的Game_BattlerBase的第67行!我找到了!
def cri; xparam(2); end # 必杀几率 CRItical rate
def cri; xparam(2); end # 必杀几率 CRItical rate
cri这个方法返回了一个xparam(2)
这又是个什么玩意?
2 调查xparam
使用Ctrl+F。。。。搜索一下Game_BattlerBase有木有叫做xparam的方法。。结果找到啦!
#-------------------------------------------------------------------------- # ● 获取添加能力 #-------------------------------------------------------------------------- def xparam(xparam_id) features_sum(FEATURE_XPARAM, xparam_id) end
#--------------------------------------------------------------------------
# ● 获取添加能力
#--------------------------------------------------------------------------
def xparam(xparam_id)
features_sum(FEATURE_XPARAM, xparam_id)
end
恩。。又来了个features_sum,这是个什么?
3 调查features_sum
继续Ctrl+F,找到方法如下:
#-------------------------------------------------------------------------- # ● 计算特性值的总和(指定数据ID) #-------------------------------------------------------------------------- def features_sum(code, id) features_with_id(code, id).inject(0.0) {|r, ft| r += ft.value } end
#--------------------------------------------------------------------------
# ● 计算特性值的总和(指定数据ID)
#--------------------------------------------------------------------------
def features_sum(code, id)
features_with_id(code, id).inject(0.0) {|r, ft| r += ft.value }
end
恩。。这个语法上面没讲。所以说LZ就比较弱。。
当时看这个脚本的时候我也是搜索了一下的。。哎~语法背不过啊~
先看看features_with_id是什么吧。。
4 调查features_with_id
找到features_with_id
#-------------------------------------------------------------------------- # ● 获取特性实例的数组(限定特性代码和数据ID) #-------------------------------------------------------------------------- def features_with_id(code, id) all_features.select {|ft| ft.code == code && ft.data_id == id } end
#--------------------------------------------------------------------------
# ● 获取特性实例的数组(限定特性代码和数据ID)
#--------------------------------------------------------------------------
def features_with_id(code, id)
all_features.select {|ft| ft.code == code && ft.data_id == id }
end
这个方法获取的是特性实例的数组。
select方法就是返回一个数组,这个数组里的每个东西都是一个ft,而这个ft符合后面那些要求 ft.code == code && ft.data_id == id (尼玛,LZ连运算符号都没讲过!"="的意思是复制,a=b意思是a的值变成b的值;而==是判断符号两边的值是否相等,相等的话返回true,不相等返回false。原来LZ也没讲过boolean啊。。而&&的意思是要满足&&左右的所有条件,只要有一个条件不满足就返回false。所以说,还是得先看编程的基本语法知识啊~)
5 大概了解一下暴击率是怎么得到的
最开始是xparam(2),然后是features_sum(FEATURE_XPARAM, xparam_id),调用了features_with_id(code, id)。既然features_with_id(code, id)这个方法是获取特性实例的数组,那就是读的数据库。
所以暴击率是这么来的,用features_with_id读取数据库里跟暴击率有关的数据,然后用features_sum方法把数据统计起来。最后返回给xparam,被cri调用了。
更改暴击率
改数据库什么的我不想玩哎(根本没研究过怎么改数据库的LZ实在是没资格这么说)。。自己加个变量什么的好啦。
于是我是这么想的,给Game_BattlerBase多加一个实例变量,我们更改暴击率的时候,就是更改这个变量,到时候计算暴击率把这个变量算进去就好了~
于是开始动手,新建一个脚本“更改暴击率”
然后
class Game_BattlerBase end
class Game_BattlerBase
end
然后我们添加变量!我给他起名叫@cri,当然得在initialize方法里加上啦~
为了让系统本身的Game_BattlerBase初始化方法能正常运行,我们给这个老的initialize加个新名字,叫old_init。然后在我们自己的initialize方法里调用old_init,这样就不误事了
class Game_BattlerBase #-------------------------------------------------------------------------- # ● 初始化对象 #-------------------------------------------------------------------------- alias old_init initialize def initialize old_init @cri=0 end end
class Game_BattlerBase
#--------------------------------------------------------------------------
# ● 初始化对象
#--------------------------------------------------------------------------
alias old_init initialize
def initialize
old_init
@cri=0
end
end
很好!现在我们需要一个给@cri赋值的方法!不然我们没有办法改它!不改它的话加了它也没用!
因为我们可能会不止一次更改这个值,所以我们要把更改的结果累积下来,这里用了+=,意思是@cri= @cri + cri,原先@cri的值加上新的更改,最后赋值给@cri
class Game_BattlerBase #-------------------------------------------------------------------------- # ● 初始化对象 #-------------------------------------------------------------------------- alias old_init initialize def initialize old_init @cri=0 end #-------------------------------------------------------------------------- # ● 更改暴击率 #-------------------------------------------------------------------------- def set_cri(cri) @cri += cri end end
class Game_BattlerBase
#--------------------------------------------------------------------------
# ● 初始化对象
#--------------------------------------------------------------------------
alias old_init initialize
def initialize
old_init
@cri=0
end
#--------------------------------------------------------------------------
# ● 更改暴击率
#--------------------------------------------------------------------------
def set_cri(cri)
@cri += cri
end
end
现在我们已经可以在事件的脚本里调用更改暴击率的方法了!$game_actors[成员ID].set_cri(增量)
$game_actors是一个全局变量,包含了所有的Game_Actor的实例,在DataManager这个脚本里你可以看到它的初始化。
Game_Actor有继承Game_BattlerBase,所以我们在Game_BattlerBase里写的方法,Game_Actor是可以使用的~
敌人Game_Enemy也继承了Game_BattlerBase,所以如果现在其实你也可以给敌人这么设置一下暴击率。
当然你把这些代码写到Game_Actor里也是可以的,这样一来就不能给敌人设暴击率了。。不过我估计也没几个人想给敌人改暴击率把。。
接下来,要修改获得暴击率的方法,把我们刚才更改的@cri计算进去
class Game_BattlerBase #-------------------------------------------------------------------------- # ● 初始化对象 #-------------------------------------------------------------------------- alias old_init initialize def initialize old_init @cri=0 end #-------------------------------------------------------------------------- # ● 获得暴击率 #-------------------------------------------------------------------------- def cri # 必杀几率 CRItical rate xparam(2) + @cri end #-------------------------------------------------------------------------- # ● 更改暴击率 #-------------------------------------------------------------------------- def set_cri(cri) @cri += cri end end
class Game_BattlerBase
#--------------------------------------------------------------------------
# ● 初始化对象
#--------------------------------------------------------------------------
alias old_init initialize
def initialize
old_init
@cri=0
end
#--------------------------------------------------------------------------
# ● 获得暴击率
#--------------------------------------------------------------------------
def cri # 必杀几率 CRItical rate
xparam(2) + @cri
end
#--------------------------------------------------------------------------
# ● 更改暴击率
#--------------------------------------------------------------------------
def set_cri(cri)
@cri += cri
end
end
搞定啦!
你可以运行一下试试~
在脚本里调用msgbox可以弹出小窗口显示变量的值,这是一个还不错的调试方法。
所以你可以在设置了暴击率以后调用msgbox($game_actors[成员ID].cri)来瞅瞅你更改暴击率之后的结果~
很好,本教程写完了。
我的主旨是希望各位想要学习脚本的童鞋们知道学习脚本的思路。
VA本身的脚本是个很好的范例,看看注释,一个一个方法去追踪,遇到不懂的东西就去google百度,然后自己给自己一两个小题目,改一改试一试,脚本什么的其实挺容易的。
以上的内容不知道各位能看懂多少。。哎。。虽然我代码写得不多,但是也算是科班出身的。。所以有些我理所当然认为应该知道的东西你们可能不知道,又或者我觉得你们可能不知道的其实你们都知道。。总之有啥问题就问吧。。哪里写错了也请给我提出来,有空的话我会进行补充的。。 |