查看: 2588|回复: 4

[已经过期] A*寻路的卡顿问题

[复制链接]
梦石
0
星屑
170
在线时间
13 小时
注册时间
2022-8-3
回帖
1
发表于 2023-2-2 23:43:06 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 Atea 于 2023-2-2 23:43 编辑

在游戏中,当玩家在一个事件到达不了的位置时,游戏会变的很卡顿

有大佬知道怎么解决吗?
[fold=A*寻路]#==================================================================#
# AStar Core v1.01 by 禾西
#==================================================================#
class AStar
  Point = Struct.new(:x, :y)
  public
  def initialize(map)
    @map_width  = map.width
    @map_height = map.height
    @g_data = Table.new(@map_width, @map_height)
    @f_data = Table.new(@map_width, @map_height)
    @p_data = Table.new(@map_width, @map_height)
    @ox = 0; @oy = 0
    @tx = 0; @ty = 0
    @openList = []
    @g = 0
    @search_done = false
    @execute_character = nil
  end
  def set_origin(ox, oy)
    @ox = ox; @oy = oy
    if is_Overmap(ox, oy)
      raise RuntimeError, "Origin location is overmap!"
    end
  end
  def set_target(tx, ty)
    @tx = tx; @ty = ty
    if is_Overmap(tx, ty)
      raise RuntimeError, "Target location is overmap!"
    end
  end
  def set_character(character)
    @execute_character = character
  end
  def do_search
    x = @ox; y = @oy
    @g_data[x, y] = 2; @f_data[x, y] = 1
    @openList << [x, y]
    t = 0
    begin
      t += 1
      point = @openList.shift
      return [] if point == nil
      check_4dir point[0], point[1]
    end until @search_done
    if @g_data[@tx, @ty] == 1
      @tx = point[0]; @ty = point[1]
    end
    make_path
    return @path
  end

  private
  def check_4dir(x, y)
    @g = @g_data[x, y] + 1
    mark_point(x, y - 1, 8)
    mark_point(x, y + 1, 2)
    mark_point(x - 1, y, 4)
    mark_point(x + 1, y, 6)
  end
  def mark_point(x, y, dir)
    if is_Overmap(x, y)
      return
    end
    if @g_data[x, y] > 1
      return
    end
    if check_passibility(x, y, dir)
      f = _f(x, y)
      @g_data[x, y] = @g
      @f_data[x, y] = f
      point = @openList[0]
      if point.nil?
        @openList.push [x, y]
      elsif (f <= @f_data[point[0], point[1]])
        @openList.unshift [x, y]
      else
        @openList.push [x, y]
      end
    else
      @g_data[x, y] = 1
      @f_data[x, y] = _f(x, y)
    end
    if x == @tx && y == @ty
      @search_done = true
    end
  end
  def make_path
    x = @tx;y = @ty
    @path = []
    stack_depth = 0
    while !(x == @ox && y == @oy)
      stack_depth += 1
      break if stack_depth >= 0xff
      @g = @g_data[x, y]
      @best_f = 0
      dir = 0
      dir = make_step(x, y - 1, 2)||dir
      dir = make_step(x, y + 1, 8)||dir
      dir = make_step(x - 1, y, 6)||dir
      dir = make_step(x + 1, y, 4)||dir
      @path.unshift(dir)
      case dir
      when 2 then y -= 1;
      when 8 then y += 1;
      when 6 then x -= 1;
      when 4 then x += 1;
      end
      @p_data[x, y] = 1
    end
  end
  def make_step(x, y, dir)
    if @g_data[x, y].nil? || @p_data[x, y] == 1
      return nil
    end
    if (@g - @g_data[x, y]) == 1 || @g == 1
      f = @f_data[x, y]
      if f > 0 && (@best_f == 0 || f < @best_f)
        @best_f = f
        return dir
      end
    end
    return nil
  end
  def check_passibility(x, y, dir)
    case dir
    when 2 then y -= 1;
    when 8 then y += 1;
    when 4 then x += 1;
    when 6 then x -= 1;
    end
    return @execute_character.passable?(x, y, dir)
  end
  def is_Overmap(x, y)
    return (x|y|(@map_width - x - 1)|(@map_height - y - 1)) < 0
  end
  def _f(x, y)
    return ((x - @tx).abs + (y - @ty).abs) + @g
  end
end

class Game_Character
  alias old_move_toward_character move_toward_character
  def move_toward_character(character)
    astr = AStar.new($game_map)
    astr.set_origin(@x, @y)
    astr.set_target(character.x, character.y)
    astr.set_character(self)
    path = astr.do_search
    pass = [2, 4, 6, 8].any? {|d| self.passable?(character.x, character.y, d) }
    if path.empty? || !pass
      old_move_toward_character(character)
    else
      move_straight(path.shift)
    end
  end
end
[/fold]
QQ截图20230202233610.png

老鹰

梦石
40
星屑
37812
在线时间
7091 小时
注册时间
2012-5-26
回帖
3297

极短24评委极短23参与极短22参与极短21评委老司机慢点开短篇十吟唱者组别冠军开拓者剧作品鉴家

发表于 2023-2-3 20:52:01 | 显示全部楼层
本帖最后由 百里_飞柳 于 2023-2-4 09:57 编辑

最后一段,在实际应用a星时,加个冷却时间咯

  1. class Game_Character
  2.   alias old_move_toward_character move_toward_character
  3.   def move_toward_character(character)
  4.     @astar_wait ||= 0
  5.     if @astar_wait <= 0
  6.       astr = AStar.new($game_map)
  7.       astr.set_origin(@x, @y)
  8.       astr.set_target(character.x, character.y)
  9.       astr.set_character(self)
  10.       path = astr.do_search
  11.       pass = [2, 4, 6, 8].any? {|d| self.passable?(character.x, character.y, d) }
  12.       if path.empty? || !pass
  13.         @astar_wait = 10
  14.         old_move_toward_character(character)
  15.       else
  16.         move_straight(path.shift)
  17.       end
  18.     else
  19.       @astar_wait -= 1
  20.       old_move_toward_character(character)
  21.     end
  22.   end
  23. end
复制代码
回复

使用道具 举报

梦石
0
星屑
170
在线时间
13 小时
注册时间
2022-8-3
回帖
1
 楼主| 发表于 2023-2-4 01:47:50 | 显示全部楼层
百里_飞柳 发表于 2023-2-3 20:52
最后一段,在实际应用a星时,加个冷却时间咯

还是会卡顿

点评

已经改了,重新复制下  发表于 2023-2-4 12:54
额,我才发现打错了字,atar_wait 都要改成 astar_wait  发表于 2023-2-4 09:56
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部