设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 4861|回复: 3
打印 上一主题 下一主题

[已发主站] 【VA】【新手教程】改个简单的脚本

[复制链接]

Lv1.梦旅人

梦石
0
星屑
60
在线时间
79 小时
注册时间
2007-2-11
帖子
140
跳转到指定楼层
1
发表于 2012-6-1 13:03:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 Sion 于 2013-12-17 15:56 编辑

我在某群看到有人问,如何开始学习脚本
这个问题不是问我的,其实我脚本也不算多厉害,只自己写过几个简单的,不过在这里共享一下自己的思路。
我首先想到的是,学习Ruby。不过有人说,他最开始改脚本,没学Ruby,后来才看的。
我是这么想的,看Ruby的过程,不一定要把它全部学会,但是至少你得知道编程是个怎么回事,知道Ruby有什么东西可以用。就算你一时没记住,在你看脚本的时候看到了这玩意,你也大概知道是什么,去查查就明白了。

以下是我想到什么写什么的无条理Ruby介绍,都是理论知识,可以直接转到下面看更改脚本去。

Ruby是面向对象的
什么叫面向对象?
首先根据客户需求抽象出业务对象;然后对需求进行合理分层,构建相对独立的业务模块;之后设计业务逻辑,利用多态、继承、封装、抽象的编程思想,实现业务需求;最后通过整合各模块,达到高内聚、低耦合的效果,从而满足客户要求。

如果你不是学计算机的,上面这么说简直看不懂。所以我们来看例子
RUBY 代码复制
  1. class Greeter
  2.   def initialize(name = "world")
  3.     @name = name
  4.   end
  5.   def say_hi
  6.     puts "Hi #{@name}!"
  7.   end
  8.   def say_bye
  9.     puts "Bye #{@name}, come back soon!"
  10.   end
  11. 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(太二了- -!)


继承
再来个例子
RUBY 代码复制
  1. class Person
  2.   def initialize(person_name )
  3.     @person_name = person_name
  4.   end
  5.   def talk(content)
  6.     puts content
  7.   end
  8.   def say_hi
  9.     talk("Hi, I am #{@person_name }!")
  10.   end
  11.   def say_bye
  12.     talk("Bye!")
  13.   end
  14. end
  15. class Greeter < Person
  16.   def initialize(person_name, name = "world")
  17.     super()
  18.     @name = name
  19.   end
  20.   def say_hi
  21.     talk("Hi #{@name }! I'm #{@person_name }.")
  22.   end
  23.   def say_bye
  24.     puts "Bye #{@name}, come back soon!"
  25.   end
  26. 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行!我找到了!
RUBY 代码复制
  1. def cri;  xparam(2);  end    # 必杀几率        CRItical rate

cri这个方法返回了一个xparam(2)
这又是个什么玩意?

2 调查xparam
使用Ctrl+F。。。。搜索一下Game_BattlerBase有木有叫做xparam的方法。。结果找到啦!
RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2.   # ● 获取添加能力
  3.   #--------------------------------------------------------------------------
  4.   def xparam(xparam_id)
  5.     features_sum(FEATURE_XPARAM, xparam_id)
  6.   end

恩。。又来了个features_sum,这是个什么?

3 调查features_sum
继续Ctrl+F,找到方法如下:
RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2.   # ● 计算特性值的总和(指定数据ID)
  3.   #--------------------------------------------------------------------------
  4.   def features_sum(code, id)
  5.     features_with_id(code, id).inject(0.0) {|r, ft| r += ft.value }
  6.   end

恩。。这个语法上面没讲。所以说LZ就比较弱。。
当时看这个脚本的时候我也是搜索了一下的。。哎~语法背不过啊~
先看看features_with_id是什么吧。。

4 调查features_with_id
找到features_with_id
RUBY 代码复制
  1. #--------------------------------------------------------------------------
  2.   # ● 获取特性实例的数组(限定特性代码和数据ID)
  3.   #--------------------------------------------------------------------------
  4.   def features_with_id(code, id)
  5.     all_features.select {|ft| ft.code == code && ft.data_id == id }
  6.   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多加一个实例变量,我们更改暴击率的时候,就是更改这个变量,到时候计算暴击率把这个变量算进去就好了~
于是开始动手,新建一个脚本“更改暴击率”
然后
RUBY 代码复制
  1. class Game_BattlerBase
  2. end


然后我们添加变量!我给他起名叫@cri,当然得在initialize方法里加上啦~
为了让系统本身的Game_BattlerBase初始化方法能正常运行,我们给这个老的initialize加个新名字,叫old_init。然后在我们自己的initialize方法里调用old_init,这样就不误事了
RUBY 代码复制
  1. class Game_BattlerBase
  2.   #--------------------------------------------------------------------------
  3.   # ● 初始化对象
  4.   #--------------------------------------------------------------------------
  5.   alias old_init initialize
  6.   def initialize
  7.     old_init
  8.     @cri=0
  9.   end
  10. end


很好!现在我们需要一个给@cri赋值的方法!不然我们没有办法改它!不改它的话加了它也没用!
因为我们可能会不止一次更改这个值,所以我们要把更改的结果累积下来,这里用了+=,意思是@cri= @cri + cri,原先@cri的值加上新的更改,最后赋值给@cri
RUBY 代码复制
  1. class Game_BattlerBase
  2.   #--------------------------------------------------------------------------
  3.   # ● 初始化对象
  4.   #--------------------------------------------------------------------------
  5.   alias old_init initialize
  6.   def initialize
  7.     old_init
  8.     @cri=0
  9.   end
  10.   #--------------------------------------------------------------------------
  11.   # ● 更改暴击率
  12.   #--------------------------------------------------------------------------
  13.   def set_cri(cri)
  14.     @cri += cri
  15.   end
  16. 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计算进去
RUBY 代码复制
  1. class Game_BattlerBase
  2.   #--------------------------------------------------------------------------
  3.   # ● 初始化对象
  4.   #--------------------------------------------------------------------------
  5.   alias old_init initialize
  6.   def initialize
  7.     old_init
  8.     @cri=0
  9.   end
  10.   #--------------------------------------------------------------------------
  11.   # ● 获得暴击率
  12.   #--------------------------------------------------------------------------
  13.   def cri  # 必杀几率        CRItical rate
  14.     xparam(2) + @cri
  15.   end   
  16.   #--------------------------------------------------------------------------
  17.   # ● 更改暴击率
  18.   #--------------------------------------------------------------------------
  19.   def set_cri(cri)
  20.     @cri += cri
  21.   end
  22. end


搞定啦!
你可以运行一下试试~
在脚本里调用msgbox可以弹出小窗口显示变量的值,这是一个还不错的调试方法。
所以你可以在设置了暴击率以后调用msgbox($game_actors[成员ID].cri)来瞅瞅你更改暴击率之后的结果~


很好,本教程写完了。
我的主旨是希望各位想要学习脚本的童鞋们知道学习脚本的思路。
VA本身的脚本是个很好的范例,看看注释,一个一个方法去追踪,遇到不懂的东西就去google百度,然后自己给自己一两个小题目,改一改试一试,脚本什么的其实挺容易的。
以上的内容不知道各位能看懂多少。。哎。。虽然我代码写得不多,但是也算是科班出身的。。所以有些我理所当然认为应该知道的东西你们可能不知道,又或者我觉得你们可能不知道的其实你们都知道。。总之有啥问题就问吧。。哪里写错了也请给我提出来,有空的话我会进行补充的。。

评分

参与人数 1+6 收起 理由
Shy07 + 6 主站收录

查看全部评分

Lv1.梦旅人

追从自然的旅行者
奇特空·煦

梦石
0
星屑
107
在线时间
1387 小时
注册时间
2010-12-31
帖子
4944

开拓者贵宾

2
发表于 2012-6-2 15:16:34 | 只看该作者
我了个去这哪里是新手教程了,理论知识讲的太多了

如果要学脚本,这个理论知识太少了,如果是单纯来讲脚本,这个知识又太多了,估计没多少新手去看的

直接把最基本的操作方式告诉大家就可以了,
有些人不想学理论,只是想单纯地实现这么个玩意,不会看那些其他玩意的
而有些人想学脚本会直接找脚本教程来看
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
79 小时
注册时间
2007-2-11
帖子
140
3
 楼主| 发表于 2012-6-2 15:18:42 | 只看该作者
Kimu 发表于 2012-6-2 15:16
我了个去这哪里是新手教程了,理论知识讲的太多了

如果要学脚本,这个理论知识太少了,如果是单纯来讲脚本,这 ...

我发现了。。
如果真心想学脚本的根本不需要有人这么写,自己就去看了

我这个是写给异形看的。不知道他能看懂不- -!

点评

我的感觉里面我个人果然是属于异形……  发表于 2012-10-28 19:24
他说他打印下来慢慢看。。这孩子特乖。。  发表于 2012-6-2 15:40
@他一下  发表于 2012-6-2 15:38
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
109 小时
注册时间
2011-3-29
帖子
17
4
发表于 2012-9-12 14:41:46 | 只看该作者
LZ 跟他们将面向对象么。。。。。。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-15 17:17

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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