查看: 5939|回复: 3

[已经解决] 禁止卷动脚本更新Scene_Map时报错

[复制链接]
梦石
0
星屑
29901
在线时间
5734 小时
注册时间
2016-3-8
回帖
1653
发表于 2021-2-1 00:00:25 | 显示全部楼层 |阅读模式
悬赏125星屑已解决
本帖最后由 alexncf125 于 2021-2-1 00:27 编辑

这脚本用F9开啟3号变量, 回地图, 再用F9关闭3号变量, 最后回地图报错disposed window/disposed tilemap
我只找到原因出自这两三句:
scene = SceneManager.scene
scene.update_basic
scene.instance_variable_get(:@spriteset).update

平常用事件开关3,4号变量是会没事, 我就只想了解一下F9的BUG能修好的不?
脚本[pre lang="ruby"]#==============================================================================
# ★スクロール禁止 ver1.0 by USK
#------------------------------------------------------------------------------
# ・特定のスイッチがオンのときスクロールを禁止します。
#==============================================================================
=begin
・21行目のFixDisplayFlagVで設定した番号のスイッチがオンのとき
  縦スクロールが禁止されます。
・22行目のFixDisplayFlagHで設定した番号のスイッチがオンのとき
  横スクロールが禁止されます。
=end

#==============================================================================
# ■ Game_Map
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  # ● 設定
  #--------------------------------------------------------------------------
  FixDisplayFlagV = 3 #禁止Y轴卷动的开关编号
  FixDisplayFlagH = 4 #禁止X轴卷动的开关编号
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  alias :fix_display_scroll_down  :scroll_down
  alias :fix_display_scroll_left  :scroll_left
  alias :fix_display_scroll_right :scroll_right
  alias :fix_display_scroll_up    :scroll_up
  alias :fix_display_refresh      :refresh
  alias :fix_display_valid?       :valid?
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def fix_display?
    $game_switches[FixDisplayFlagV] || $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def need_centering?
    ret = !fix_display? &&
          SceneManager.scene.is_a?(Scene_Map) &&
          @on_fix_display
    @on_fix_display = fix_display?
    ret
  end
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def centering
    div = 20
    x = @display_x
    dx = $game_player.x - (Graphics.width / 32 - 1) / 2.0 - x
    dx /= div
    y = @display_y
    dy = $game_player.y - (Graphics.height / 32 - 1) / 2.0 - y
    dy /= div
    div.times do
      set_display_pos(x, y)
      x += dx
      y += dy
      scene = SceneManager.scene
      scene.update_basic
      scene.instance_variable_get(:@spriteset).update
    end
  end
  #--------------------------------------------------------------------------
  # ● リフレッシュ
  #--------------------------------------------------------------------------
  def refresh
    centering if need_centering?
    fix_display_refresh
  end
  #--------------------------------------------------------------------------
  # ● 下にスクロール
  #--------------------------------------------------------------------------
  def scroll_down(distance)
    fix_display_scroll_down(distance) unless $game_switches[FixDisplayFlagV]
  end
  #--------------------------------------------------------------------------
  # ● 左にスクロール
  #--------------------------------------------------------------------------
  def scroll_left(distance)
    fix_display_scroll_left(distance) unless $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ● 右にスクロール
  #--------------------------------------------------------------------------
  def scroll_right(distance)
    fix_display_scroll_right(distance) unless $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ● 上にスクロール
  #--------------------------------------------------------------------------
  def scroll_up(distance)
    fix_display_scroll_up(distance) unless $game_switches[FixDisplayFlagV]
  end
  #--------------------------------------------------------------------------
  # ● 有効座標判定
  #--------------------------------------------------------------------------
  def valid?(x, y)
    ret = fix_display_valid?(x, y)
    if $game_switches[FixDisplayFlagV]
      ret &&= y >= @display_y && y < @display_y + (Graphics.height >> 5)
    end
    if $game_switches[FixDisplayFlagH]
      ret &&= x >= @display_x && x < @display_x + (Graphics.width >> 5)
    end
    ret
  end
end[/pre]

最佳答案

查看完整内容

这波是脚本语言的灵活性以及脚本作者的偷懒二者共同背锅。 因为不到运行时不会检查方法能否运行,所以如果不出现预想以外的使用场景,就没事。 但是这也为脚本制作者提供了一个偷懒的机会,那就是——我可以少加异常处理、错误判断, 反正我只保证在xx条件下不出错,使用脚本出错了就怪使用者操作太骚。 在这里就很明显,大部分的Scene是没有Spriteset的(实际上,也就Scene_Map和Scene_Battle是有的) 所以取@spriteset这个 ...
梦石
0
星屑
29901
在线时间
5734 小时
注册时间
2016-3-8
回帖
1653
 楼主| 发表于 2021-2-1 00:22:48 | 显示全部楼层
本帖最后由 alexncf125 于 2021-2-1 23:18 编辑

试著插入这段[pre lang="ruby"]module SceneManager

  @last_scene = nil
  
  def self.last_scene
    @last_scene
  end

  class << self
    alias last_scene_call call
  end
  def self.call(scene_class)
    @last_scene = @scene
    last_scene_call(scene_class)
  end

  def self.return
    @last_scene = @scene
    @scene = @stack.pop
  end

end[/pre]

和把那段改成
last_scene = SceneManager.last_scene
return if last_scene.is_a?(Scene_Debug)
scene = SceneManager.scene
scene.update_basic
scene.instance_variable_get(:@spriteset).update

好像能解決掉问题

能请大佬们指教一下, 原先那两句有啥用途??是必须写的么??
我这样用return跳过它们没问题吧
回复

使用道具 举报

梦石
10
星屑
39550
在线时间
1919 小时
注册时间
2010-11-14
回帖
3214

R考场第七期纪念奖

发表于 2021-2-1 00:00:26 | 显示全部楼层
本帖最后由 KB.Driver 于 2021-2-1 22:48 编辑
alexncf125 发表于 2021-2-1 00:22
[fold=试著插入这段]module SceneManager

  @last_scene = nil


这波是脚本语言的灵活性以及脚本作者的偷懒二者共同背锅。

因为不到运行时不会检查方法能否运行,所以如果不出现预想以外的使用场景,就没事。

但是这也为脚本制作者提供了一个偷懒的机会,那就是——我可以少加异常处理、错误判断,
反正我只保证在xx条件下不出错,使用脚本出错了就怪使用者操作太骚。

在这里就很明显,大部分的Scene是没有Spriteset的(实际上,也就Scene_Map和Scene_Battle是有的)
所以取@spriteset这个违反OOP的投机写法(虽然ruby就是很灵活,就是可以这样写,但不代表它是好的)
如果不用if语句控制条件或者用begin...end的异常处理包裹,它就是很脆弱的(不具健壮性,robust)

至于出错的原因,个人推理如下:
修改$game_variables(开关也是一样),会触发on_change方法,
从而使$game_map.need_refresh = true,令Game_Map触发refresh方法。
QQ截图20210201224116.jpg

在Scene_Map或者Scene_Battle中这样做没有影响,因为它们有@spriteset变量

但是在Scene_Debug里修改变量,一样触发Game_Map的refresh,
你所用的脚本又修改了这个refresh,让它对当前场景的@spriteset进行更新
这个变量在Scene_Debug里并不存在,这就产生错误了。

===================================================================

这给我们带来什么启示呢?
1、写法投机的脚本往往不具备健壮性,建议自己用或者给身边人玩玩就好,拿出来大规模分享就不必了。
2、如果真要大规模分享,请多从使用者的角度考虑,提高兼容性,减少代码出错的可能。


评分

参与人数 2星屑 +60 赞 +1 收起 理由
fux2 + 60 认可答案
alexncf125 + 1 万分感谢!!!!!!!!!!.

查看全部评分

用头画头像,用脚写脚本
回复

使用道具 举报

梦石
0
星屑
29901
在线时间
5734 小时
注册时间
2016-3-8
回帖
1653
 楼主| 发表于 2021-2-2 00:44:41 | 显示全部楼层
本帖最后由 alexncf125 于 2021-2-26 17:00 编辑

万分感谢!!!!!!!!!!

经过日历大佬的指点, 终于改到没bug了~

[pre lang="ruby"]#==============================================================================
# ★スクロール禁止 ver1.0 by USK
#------------------------------------------------------------------------------
# ・特定のスイッチがオンのときスクロールを禁止します。
#==============================================================================
=begin
・21行目のFixDisplayFlagVで設定した番号のスイッチがオンのとき
  縦スクロールが禁止されます。
・22行目のFixDisplayFlagHで設定した番号のスイッチがオンのとき
  横スクロールが禁止されます。
=end
##########
module SceneManager

  @last_scene = nil
  
  def self.last_scene
    @last_scene
  end
   
  class << self; alias last_scene_call call; end
  def self.call(scene_class)
    @last_scene = @scene
    last_scene_call(scene_class)
  end
   
  def self.return
    @last_scene = @scene
    @scene = @stack.pop
  end
  
  def self.refresh_scene
    @last_scene = @scene
  end
   
end
##########
#==============================================================================
# ■ Game_Map
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  # ● 設定
  #--------------------------------------------------------------------------
  FixDisplayFlagV = 3 #禁止Y轴卷动的开关编号
  FixDisplayFlagH = 4 #禁止X轴卷动的开关编号
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  alias :fix_display_scroll_down  :scroll_down
  alias :fix_display_scroll_left  :scroll_left
  alias :fix_display_scroll_right :scroll_right
  alias :fix_display_scroll_up    :scroll_up
  alias :fix_display_refresh      :refresh
  alias :fix_display_valid?       :valid?
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def fix_display?
    $game_switches[FixDisplayFlagV] || $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def need_centering?
    ret = !fix_display? &&
          SceneManager.scene.is_a?(Scene_Map) &&
          @on_fix_display
    @on_fix_display = fix_display?
    ret
  end
  #--------------------------------------------------------------------------
  # ●
  #--------------------------------------------------------------------------
  def centering
    div = 20
    x = @display_x
    dx = $game_player.x - (Graphics.width / 32 - 1) / 2.0 - x
    dx /= div
    y = @display_y
    dy = $game_player.y - (Graphics.height / 32 - 1) / 2.0 - y
    dy /= div
    div.times do
      set_display_pos(x, y)
      x += dx
      y += dy
      scene = SceneManager.scene
      scene.update_basic
      scene.instance_variable_get(:@spriteset).update
    end
  end
  #--------------------------------------------------------------------------
  # ● リフレッシュ
  #--------------------------------------------------------------------------
  def refresh
    ##########
    last_scene = SceneManager.last_scene
    if last_scene.is_a?(Scene_Debug)
      SceneManager.refresh_scene
      return fix_display_refresh
    end
    ##########
    centering if need_centering?
    fix_display_refresh
  end
  #--------------------------------------------------------------------------
  # ● 下にスクロール
  #--------------------------------------------------------------------------
  def scroll_down(distance)
    fix_display_scroll_down(distance) unless $game_switches[FixDisplayFlagV]
  end
  #--------------------------------------------------------------------------
  # ● 左にスクロール
  #--------------------------------------------------------------------------
  def scroll_left(distance)
    fix_display_scroll_left(distance) unless $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ● 右にスクロール
  #--------------------------------------------------------------------------
  def scroll_right(distance)
    fix_display_scroll_right(distance) unless $game_switches[FixDisplayFlagH]
  end
  #--------------------------------------------------------------------------
  # ● 上にスクロール
  #--------------------------------------------------------------------------
  def scroll_up(distance)
    fix_display_scroll_up(distance) unless $game_switches[FixDisplayFlagV]
  end
  #--------------------------------------------------------------------------
  # ● 有効座標判定
  #--------------------------------------------------------------------------
  def valid?(x, y)
    ret = fix_display_valid?(x, y)
    if $game_switches[FixDisplayFlagV]
      ret &&= y >= @display_y && y < @display_y + (Graphics.height >> 5)
    end
    if $game_switches[FixDisplayFlagH]
      ret &&= x >= @display_x && x < @display_x + (Graphics.width >> 5)
    end
    ret
  end
end
##########
class Scene_Map < Scene_Base
  alias :fix_display_start :start
  def start
    fix_display_start
    $game_map.centering if $game_map.need_centering?
  end
end
##########[/pre]
用两个##########包裹的是新增的內容
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部