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

Project1

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

关于FE行动范围显示

 关闭 [复制链接]

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
跳转到指定楼层
1
发表于 2008-5-14 20:56:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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

x
以下为本人在制作RMXP的FE脚本时遇到的问题,脚本苦手请无视。

玩过FE的都知道,光标套在为行动角色上按下确认键会显示行动以及攻击范围。行动范围决定于角色移动力与地形,攻击范围决定于身上携带武器以及杖的攻击/作用范围。

就功能本身,实现并不困难,但是,本人试过采用各种算法,始终无法达到理想效果。比如一种普遍算法(从“高考狂想曲”应用的脚本改造而来)如下:

    @position = [[@battler.x, @battler.y ,battler.mov]]
    @position0 = [[@battler.x, @battler.y]]
    @route = [[]]
    more_step = [0]
   
    for i in more_step
      x = @position[0]
      y = @position[1]
      @move = @position[2]
      # 下
      if  @battler.passable?(x, y, 2) and !(@move < battler.need_mov[$game_map.terrain_tag(x,y + 1)])
        @move1 = @move - battler.need_mov[$game_map.terrain_tag(x,y + 1)]
        @position.push([x, y + 1,@move1])
        @position0.push([x, y + 1]) if [email protected]?([x, y + 1])
        @route.push(@route + [2])
        more_step.push(@route.index(@route + [2]))
      end
      if @battler.passable?(x, y, 4) and !(@move < battler.need_mov[$game_map.terrain_tag(x - 1,y)])
        @move2 = @move - battler.need_mov[$game_map.terrain_tag(x - 1,y)]
        @position.push([x - 1, y, @move2])
        @position0.push([x - 1, y]) if [email protected]?([x - 1, y])
        @route.push(@route + [4])
        more_step.push(@route.index(@route + [4]))
      end
      if  @battler.passable?(x, y, 6) and !(@move < battler.need_mov[$game_map.terrain_tag(x + 1,y)])
        @move3 = @move - battler.need_mov[$game_map.terrain_tag(x + 1,y)]
        @position.push([x + 1, y, @move3])
        @position0.push([x + 1, y]) if [email protected]?([x + 1, y])
        @route.push(@route + [6])
        more_step.push(@route.index(@route + [6]))
      end
      if @battler.passable?(x, y, 8) and !(@move < battler.need_mov[$game_map.terrain_tag(x,y - 1)])
        @move4 = @move - battler.need_mov[$game_map.terrain_tag(x,y - 1)]
        @position.push([x, y - 1,@move4])
        @position0.push([x, y - 1]) if [email protected]?([x, y - 1])
        @route.push(@route + [8])
        more_step.push(@route.index(@route + [8]))
      end
    end
   
    for i in [email protected]
      x0 = @position0[0]
      y0 = @position0[1]
      area = Sprite_Area.new(@spriteset.viewport1, x0, y0)
      @spriteset.area_sprites.push(area)
    end

现在存在的问题是,随着移动力的增大,计算量会有级数级增长,移动力为5以内,攻击范围在2以内时可以即时显示(虽然此处未给出供给范围选定的脚本)……移动达到7时,计算就会造成5秒以上延迟(应该与机器有关,难不成一个同人还要要求夸张配置?囧rz)。但是,按照GBA版的要求,最大移动力有12……RMXP并不是高明的编译器,Ruby也不是快速的汇编,要增加脚本执行速度,就要减少条件与迭代的层数与复杂度。

本人对数据结构不擅长,希望有高手能提供一种更巧妙简练的算法(嗯,发现网站上一个原创FE游戏的截图貌似不错,龟速下载中)。网站上有一些其它的脚本,但是下载速度太慢,而且貌似都不算成熟,有FE高手路过的话就请不吝赐教一下。
此贴于 2008-5-22 23:43:20 被版主禾西提醒,请楼主看到后对本贴做出回应。

Lv3.寻梦者

酱油的

梦石
0
星屑
1685
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

2
发表于 2008-5-14 21:15:10 | 只看该作者
SLG 嗎?
感覺上只要需要確定地形,速度就不能很快(近來做鼠標尋路的體會)

上述腳本有幾個可以加快速度的地方。
比如 for i in [email protected]
可以把size的計算分散到建立的@position0的時候,search array size 需要不少時間的。
還有其他開始的幾個 if 語法的結尾需要加上 next

include? 語句是用歷遍的,應該可以有方法避免坐標的重複而不使用include...

其實思維很重要。Ruby 的速度雖然差強人意,但是其實也不存在明顯的感覺
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
3
 楼主| 发表于 2008-5-14 22:04:34 | 只看该作者
嗯,谢谢禾西兄的指引。

不使用遍历,又要避免重复……把数组改成哈希表怎么样?
用坐标作为哈希表的主键,指向剩余移动力……嗯

差点被日本人做的脚本绑住脑袋了……
回复 支持 反对

使用道具 举报

Lv3.寻梦者

酱油的

梦石
0
星屑
1685
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

4
发表于 2008-5-14 22:16:49 | 只看该作者
具體不清楚,聽沉影說 hash 表是歷遍的。其實我比較偏向使用 table 判斷坐標數值是否爲 nil 就OK。size 用另外一個變量來控制。最好不要拋出大量地圖數據,這個很吃力的。
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
5
 楼主| 发表于 2008-5-14 22:27:35 | 只看该作者
果然不行吗……嗯

http://rpg.blue/web/htm/down381.htm

貌似这个是做好的,但是偶下不来……
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
6
 楼主| 发表于 2008-5-14 22:57:36 | 只看该作者
怎么用table?囧rz

对于编程偶还是新手,很多功能/函数都未用过

...

偶还是自己看帮助文件吧……
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
7
 楼主| 发表于 2008-5-15 06:55:09 | 只看该作者
经过算法调整(table),有了一定程度的优化,但行动力到12时还是会有3秒的延迟,还不算攻击范围。如果加上3~15的远程魔法效果,囧rz

由于开的讨论帖,我就边优化边更新,希望能给RGSS初学者一点经验,也能获得高手达人的进一步指教。这个FE系统我一定会坚持做完的,而且会尽量向加贺风格看齐。

    @position = Table.new($game_map.data.xsize,$game_map.data.ysize)
    @position[@battler.x, @battler.y] = battler.mov
    @areas = [[@battler.x, @battler.y,battler.mov + 1]]
#    @areas2 = [[@battler.x, @battler.y]]
    @route = [[]]
    more_step = [0]
   
    for i in more_step
      x = @areas[0]
      y = @areas[1]
      @move = @areas[2]
      if  @battler.passable?(x, y, 2) and
        (@move - battler.need_mov[$game_map.terrain_tag(x,y + 1)]) > @position[x,y + 1]
        @move2 = @move - battler.need_mov[$game_map.terrain_tag(x,y + 1)]
        @areas.push([x,y + 1,@move2])
        @position[x,y + 1] = @move2 - 1
        @route.push(@route + [2])
        more_step.push(@route.index(@route + [2]))
      end
      if  @battler.passable?(x, y, 4) and
        (@move - battler.need_mov[$game_map.terrain_tag(x - 1,y)]) > @position[x - 1,y]
        @move4 = @move - battler.need_mov[$game_map.terrain_tag(x - 1,y)]
        @areas.push([x - 1,y,@move4])
        @position[x - 1,y] = @move4 - 1
        @route.push(@route + [4])
        more_step.push(@route.index(@route + [4]))
      end
      if  @battler.passable?(x, y, 6) and
        (@move - battler.need_mov[$game_map.terrain_tag(x + 1,y)]) > @position[x + 1,y]
        @move4 = @move - battler.need_mov[$game_map.terrain_tag(x + 1,y)]
        @areas.push([x + 1,y,@move4])
        @position[x + 1,y] = @move4 - 1
        @route.push(@route + [6])
        more_step.push(@route.index(@route + [6]))
      end
      if  @battler.passable?(x, y, 8) and
        (@move - battler.need_mov[$game_map.terrain_tag(x,y - 1)]) > @position[x,y - 1]
        @move2 = @move - battler.need_mov[$game_map.terrain_tag(x,y - 1)]
        @areas.push([x,y - 1,@move2])
        @position[x,y - 1] = @move2 - 1
        @route.push(@route + [8])
        more_step.push(@route.index(@route + [8]))
      end
    end
    @areas2 = []
    for j in @areas
      a = j[0]
      b = j[1]
      c = [[a,b]]
      @areas2 = @areas2 | c
    end
   
    for area in @areas2
      x = area[0]
      y = area[1]
      @area = Sprite_Area.new(@spriteset.viewport1, x, y)
      @spriteset.area_sprites.push(@area)
    end
回复 支持 反对

使用道具 举报

Lv3.寻梦者

酱油的

梦石
0
星屑
1685
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

8
发表于 2008-5-15 07:25:24 | 只看该作者
稍微放出個工程給禾西一同測試吧。對於這個稍微有點興趣。


發現眞正的問題所在....


  def passable?(x, y, d)
    # 求得新的坐标
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # 坐标在地图外的情况下
    unless $game_map.valid?(new_x, new_y)
      # 不能通行
      return false
    end
    # 调试模式为 ON 并且 按下 CTRL 键的情况下
    if $DEBUG and Input.press?(Input::CTRL)
      # 可以通行
      return true
    end
    super
  end
  def passable?(x, y, d)
    # 求得新的坐标
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # 坐标在地图以外的情况
    unless $game_map.valid?(new_x, new_y)
      # 不能通行
      return false
    end
    # 穿透是 ON 的情况下
    if @through
      # 可以通行
      return true
    end
    # 移动者的元件无法来到指定方向的情况下
    unless $game_map.passable?(x, y, d, self)
      # 通行不可
      return false
    end
    # 从指定方向不能进入到移动处的元件的情况下
    unless $game_map.passable?(new_x, new_y, 10 - d)
      # 不能通行
      return false
    end
    # 循环全部事件
    for event in $game_map.events.values
      # 事件坐标于移动目标坐标一致的情况下
      if event.x == new_x and event.y == new_y
        # 穿透为 ON
        unless event.through
          # 自己就是事件的情况下
          if self != $game_player
            # 不能通行
            return false
          end
          # 自己是主角、对方的图形是角色的情况下
          if event.character_name != ""
            # 不能通行
            return false
          end
        end
      end
    end

    # 主角的坐标与移动目标坐标一致的情况下
    if $game_player.x == new_x and $game_player.y == new_y
      # 穿透为 ON
      unless $game_player.through
        # 自己的图形是角色的情况下
        if @character_name != ""
          # 不能通行
          return false
        end
      end
    end
    # 可以通行
    return true
  end
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
9
 楼主| 发表于 2008-5-16 05:53:48 | 只看该作者
不是这个原因

实际上,我根据FE系统,把所有的脚本都重新写过了,所有与FE无关的函数全都删除了

现在的通行判断,只判断地图范围。图块没有通行判定,只要把经过消耗的移动力设为很高就是了

  def passable?(x, y, d)
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    unless $game_map.valid?(new_x, new_y)
      return false
    end
    return true
  end

由于脚本全部重写过,而且现在系统框架还没有完成,所以禾西兄要帮忙的话可能会消耗较多的精力……如果禾西兄仍然愿意帮手,小弟自然求之不得。

这个FE系统我是打算纯粹FE用,与其他任何脚本都没有兼容性……偶都是直接改的原函数,没有用alias。

这个FE系统我希望能做到可以实现所有的FE功能以及特性。比如预设100位的乱数进行数据计算以及寻路计算(可以像GBAFE一样凹点),只有章节和中断存档,战斗动画前判定战斗结果,进行胜负统计并写入所有档案;实现所有指令功能(对话,支援,救出,偷窃,访问,制压,etc)。实现所有武器法杖以及道具效果;视情况还会加入特技系统……所以数据结构相当的复杂。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1 小时
注册时间
2008-4-17
帖子
12
10
 楼主| 发表于 2008-5-16 16:45:02 | 只看该作者
继续更新

最终脚本

    @move_ability_remain = Table.new($game_map.data.xsize,$game_map.data.ysize)
    @move_ability_remain[@battler.x, @battler.y] = battler.mov
    @movable_flag = Table.new($game_map.data.xsize,$game_map.data.ysize)
    for a in 0..battler.mov
      for b in 0..battler.mov
        for x in [@battler.x + a,@battler.x - a]
          for y in [@battler.y + b,@battler.y - b]
            if a + b <= battler.mov and @move_ability_remain[x, y] != nil and @move_ability_remain[x, y] > 0
              @move = @move_ability_remain[x,y]
              if @move >= battler.need_mov[$game_map.terrain_tag(x + 1,y)] and @battler.passable?(x, y, 6)
                @move_ability_remain[x + 1, y] = @move - battler.need_mov[$game_map.terrain_tag(x + 1,y)]
                @movable_flag[x + 1, y] = 1
              end
              if @move >= battler.need_mov[$game_map.terrain_tag(x - 1,y)] and @battler.passable?(x, y, 4)
                @move_ability_remain[x - 1, y] = @move - battler.need_mov[$game_map.terrain_tag(x - 1,y)]
                @movable_flag[x - 1, y] = 1
              end
              if @move >= battler.need_mov[$game_map.terrain_tag(x,y + 1)] and @battler.passable?(x, y, 2)
                @move_ability_remain[x, y + 1] = @move - battler.need_mov[$game_map.terrain_tag(x,y + 1)]
                @movable_flag[x, y + 1] = 1
              end
              if @move >= battler.need_mov[$game_map.terrain_tag(x,y - 1)] and @battler.passable?(x, y, 8)
                @move_ability_remain[x, y - 1] = @move - battler.need_mov[$game_map.terrain_tag(x,y - 1)]
                @movable_flag[x, y - 1] = 1
              end
            end
          end
        end
      end
    end
    for i in 0..@movable_flag.xsize
      for j in 0..@movable_flag.ysize
        if @movable_flag[i,j] == 1
          @area = Sprite_Area.new(@spriteset.viewport1, i, j)
          @spriteset.area_sprites.push(@area)
        end
      end
    end
延迟为0。。。orz

嗯,思路才是重点……偶终于会用table了……
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2026-6-17 20:34

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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