查看: 6069|回复: 10

[通用发布] 突破RMXP动画192x192大小限制

[复制链接]
梦石
1
星屑
24088
在线时间
3339 小时
注册时间
2011-7-8
回帖
3862

开拓者

发表于 2017-3-2 12:21:02 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 guoxiaomi 于 2017-3-3 11:54 编辑

一、 动机和背景
主要动机是 @89444640 在水区里的“无缝特效”主题,提到RMXP的动画图块只能是192x192大小,无法展示更高清晰度的动画。
@soulsaga 提出了解决方案的关键是修改:
[pre lang="ruby"]sprite.src_rect.set(pattern % 5 * 192, pattern / 5 * 192, 192, 192)[/pre]
在得到这一提示之后我找到了这一行的代码在脚本中的位置是在 RPG::Sprite 的 animation_set_sprites(sprites, cell_data, position) 方法内,此方法用于获取每一帧展示动画的内容。从这里着手修改就可以突破192x192的限制。但是无法对编辑器进行修改,所以编辑器里看上去是乱的。

在解决这个问题后,我在6R上搜索“动画 大小”。截至目前可以看到有14个主题,时间跨度从2006年一直到2016年。大部分主题的解决方案是多图拼合,但是2016年的主题“如何调整技能动画默认读取的大小”中 @魔法丶小肉包 在 2 楼给出了同样的思路。

所以在 VA 修改 animation_set_sprites 是可行的,这也是主题为通用发布的原因。

二、解决方案
先上脚本,在给说明,本脚本只是 XP 适用:
[pre lang="ruby"]#==============================================================================
# 全图动画 (突破 RMXP 动画 192 * 192 限制)
#==============================================================================
# 用法:
# 1. 动画图片设置:
#    1.1 宽度 640
#    1.2 所有的子图片竖着排列
#    1.3 图片名包含 ★全图320★ 这里 320 是单张高度值
#    1.4 图片名包含 ★全图320YS160★ 则播放的动画会向下移动 160 像素
# 2. 数据库动画设置
#    2.1 选择一帧,添加一个单元
#    2.2 位置:上 在正常动画上方(z=3000);
#        位置:中 在正常动画下方(z=1500)
#        位置:下 在敌人下方(z=0);
#        位置:画面 z = x 坐标* y 坐标 * 放大率
#    2.3 式样:此帧播放的子图片位置
#    2.4 左右反转、不透明度和合成方式可以正常使用
#    2.5 X坐标、Y坐标、放大率、旋转角度不可以正常使用
#==============================================================================
# 作者:guoxiaomi 脚本来自 rpg.blue
#==============================================================================

module RPG
  class Sprite < ::Sprite
    def animation_set_sprites(sprites, cell_data, position)
      # --------------------------------------------------------
      # 图片文件名里包含★全图320★
      # --------------------------------------------------------
      if @_animation && @_animation.animation_name =~ /★全图(\d+).*★/
        full_screen = true
        width = 640
        height = $1.to_i
        y_shift = 0
        if @_animation.animation_name =~ /★全图\d+YS(\d+)★/
          y_shift = $1.to_i
        end
      else
        full_screen = false
      end
      # --------------------------------------------------------
      # 这 16 个点是动画上的单元数,最多 16 个,然后每个进行处理
      for i in 0..15
        sprite = sprites
        # cell_data[i, 0] 是该单元的图片在动画图片中的位置
        pattern = cell_data[i, 0]
        # 如果 patten = -1, or nil,本帧画面上不显示,处理下一个单元
        # 如果 sprite == nil,处理下一个单元
        if sprite == nil or pattern == nil or pattern == -1
          sprite.visible = false if sprite != nil
          next
        end        
        sprite.visible = true

        if full_screen
          # --------------------------------------------------------
          # 全图的情况
          # --------------------------------------------------------
          sprite.src_rect.set(0, pattern * height, width, height)
          sprite.x = width / 2
          sprite.y = height / 2 + y_shift
          sprite.ox = width / 2
          sprite.oy = height / 2
          # 高度:位置为 上中下高度分别是 3000/1500/0(敌人背后)
          # 位置为 画面 时,高度为 x 坐标* y 坐标 * 放大率
          case position
          when 0
            sprite.z = 3000 # 普通动画上方
          when 1
            sprite.z = 1500 # 普通动画下方
          when 2
            sprite.z = 0 # 敌人下方
          when 3
            sprite.z = cell_data[i, 1] * cell_data[i, 2] * cell_data[i, 3] # 自定义高度
          end
          sprite.mirror = (cell_data[i, 5] == 1) # 镜像
          sprite.opacity = cell_data[i, 6] * self.opacity / 255.0 # 透明度
          sprite.blend_type = cell_data[i, 7] # 混合方式
        else
          # --------------------------------------------------------
          # 正常的情况
          # --------------------------------------------------------
          # 这里找到该单元的图片在动画图片中的位置和大小                  
          sprite.src_rect.set(pattern % 5 * 192, pattern / 5 * 192, 192, 192)                  
          # 位置:画面的情况
          if position == 3
            # 无论是战斗中还是地图上,尚未发现self.viewport为nil的情况  
            # self 是显示动画的 Sprite
            if self.viewport != nil
              # viewport存在,x 为viewport中心,y 为viewport高 - 160
              sprite.x = self.viewport.rect.width / 2
              sprite.y = self.viewport.rect.height - 160
            else
              # viewport不存在,中心设于游戏窗口中心(标准640*480)
              sprite.x = 320
              sprite.y = 240
            end
          else
            # 位置:上中下的情况
            # 中的情况,图片中心位置和显示动画的 Sprite中心重合
            sprite.x = self.x - self.ox + self.src_rect.width / 2
            sprite.y = self.y - self.oy + self.src_rect.height / 2
            # 上的情况,图片上移自身 1/4 的高度
            sprite.y -= self.src_rect.height / 4 if position == 0
            # 下的情况,图片下移自身 1/4 的高度
            sprite.y += self.src_rect.height / 4 if position == 2
          end
          # cell_data[i, 1] 是该单元的图片的
          sprite.x += cell_data[i, 1] # x 偏移量
          sprite.y += cell_data[i, 2] # y 偏移量
          sprite.z = 2000 # 高度
          sprite.ox = 96 # 图片的 中心 位置 x
          sprite.oy = 96 # 图片的 中心 位置 y,中心位置要和画面的中心位置重合
          sprite.zoom_x = cell_data[i, 3] / 100.0 # x 放大率
          sprite.zoom_y = cell_data[i, 3] / 100.0 # y 放大率
          sprite.angle = cell_data[i, 4] # 旋转
          sprite.mirror = (cell_data[i, 5] == 1) # 镜像
          sprite.opacity = cell_data[i, 6] * self.opacity / 255.0 # 透明度
          sprite.blend_type = cell_data[i, 7] # 混合方式
        end
      end
    end
  end
end
#==============================================================================
# 作者:guoxiaomi 脚本来自 rpg.blue
#==============================================================================
[/pre]

从这个方法的构造中可以看出,方法把原来的动画图片进行了切割,并且读入数据库里的数据来控制每一帧。方法的参数是:sprites, cell_data, position。
sprites 是待修改的 sprites,这个方法利用编辑器里的设置,修改了数组 sprites 的值,在方法后面的处理中,sprites 数组里的内容进行闪烁更新,从而在图片上显示动画。
cell_data 是每一帧里的各单元设置,cell_data 是二维数组(Table),第一索引是单元的编号,第二索引是不同的设置选项,值为设置的值。
position 是动画的位置“上、中、下、画面”,这个值是整个动画共享的。

下面介绍如何改写方法:
1. 在方法的开始,读取动画的文件名,@_animation.animation_name 判断是否有特别的标记。然后根据标记,决定后面是按照正常动画播放(full_screen = false),还是特殊处理(full_screen = true)。由于某些时候 @_animation = nil,这里添加了一句避免报错。
2. 判断 full_screen 的值,正常播放的部分一个字不改,特殊处理的部分要按照约定的格式来处理。约定的格式是图片宽度为 640,且每个子图片是竖着排列的,子图片的高度也写在文件名里。
3. 按照约定,首先根据 pattern 的值设置 sprite.src_rect ,其次设置sprite的 x, y, ox, oy 四个属性;关于 z 属性,我做了一些处理,利用了编辑器里对 position 的设置,让动画位于敌人背后,普通动画背后或前方。此外,编辑器里的镜像、不透明度和混合方式是照常使用。
4. 由于本来就是全图的动画,所以编辑器里的x坐标、y坐标、缩放和旋转被弃用了。关于这些数据要怎么用起来,可以自行定义。我的用法是在 position == 3 的时候,用 x坐标、y坐标、缩放三者的乘积决定 z 属性。

三、结论
修改 animation_set_sprites 是可行的,也是各版本通用的。由于这个方法直接关系到编辑器里的数据,而且不在F11里显示,所以很少会被别的脚本修改。忽视了这个方法,也可能是一直未能突破192x192限制的原因。

四、水区原帖
无缝特效,包含了范例和Q&A

评分

参与人数 3星屑 +252 收起 理由
89444640 + 120 非常感谢。
soulsaga + 66 支持大神
MeowSnow + 66 厉害

查看全部评分

熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
梦石
0
星屑
4549
在线时间
1923 小时
注册时间
2010-8-16
回帖
786

短篇八RM组季军

发表于 2017-3-2 19:28:44 | 显示全部楼层
大佬你看我都跪下了!!!

点评

大佬我不是基佬!我喜欢妹子!我没有不良嗜好!我是既单纯又不做作的男子汉,和外面那些妖艳贱货不一样!既然大佬执意,那我就用邮箱联系大佬吧   发表于 2017-3-2 21:47
感觉gay里gay气的,而且我不是什么dalao……邮件联系吧,我这几年已经习惯用邮件了……  发表于 2017-3-2 21:40
大佬我并没有什么机密,我就是想和你进行一些身心之间的交流,而且我觉得QQ可以很好的把我们的思路融汇贯通,还望大佬恩准!  发表于 2017-3-2 21:35
hhh~如果涉及到机密无法在论坛上公开,邮件联系我吧iamguoxiaomi@sina.com,我平时不上QQ。  发表于 2017-3-2 21:16
Steam页面:
http://store.steampowered.com/app/486850
https://store.steampowered.com/app/865180/
志同道合QQ&E-mail:707429539@qq.com
回复

使用道具 举报

梦石
0
星屑
52
在线时间
4 小时
注册时间
2017-11-26
回帖
7
发表于 2017-12-14 23:23:24 | 显示全部楼层
真厉害
回复

使用道具 举报

梦石
0
星屑
52
在线时间
4 小时
注册时间
2017-11-26
回帖
7
发表于 2017-12-15 21:57:08 | 显示全部楼层
我想问一下,动画帧数如果超过16个咋办,能否突破帧数限制?

点评

动画帧数不是没有上限吗?  发表于 2017-12-16 11:48
回复

使用道具 举报

梦石
0
星屑
15041
在线时间
2230 小时
注册时间
2019-1-24
回帖
964

R考场第七期纪念奖

发表于 2019-6-8 18:36:05 | 显示全部楼层
有3个疑问请教下。
第一、原图我标记了下,标记红色点的位置是每一帧的初始位置,每张大小是640*320像素大小
第二、我在动画编辑器里面,看你制作的例子是13帧,并且是用了前13个192*192图块,我就很不理解了,不应该用我标记红点的位置,每隔3张点一下吗?
第三、我画方框的位置,因为在动画编辑器里面显示不完全,这13帧你是怎么调的?13帧都重合在左上角吗?
1 (2).png
2.png
3.png
回复

使用道具 举报

梦石
0
星屑
3905
在线时间
1972 小时
注册时间
2013-1-3
回帖
9146
发表于 2020-4-6 23:06:35 | 显示全部楼层
今天发现的问题,战斗者有状态动画时会与全屏动画冲突
推荐把loop_animation也重新定义一下
我的做法是重新定义了update_animation
补充一下啊,挖坟什么的别在意

评分

参与人数 1赞 +1 收起 理由
guoxiaomi + 1 我很赞同

查看全部评分

《宿愿·寻剑篇》正式版已经发布!快去看看!点击进入论坛发布贴
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部