赞 | 75 |
VIP | 0 |
好人卡 | 0 |
积分 | 140 |
经验 | 0 |
最后登录 | 2024-4-21 |
在线时间 | 2070 小时 |
Lv4.逐梦者
- 梦石
- 0
- 星屑
- 14048
- 在线时间
- 2070 小时
- 注册时间
- 2016-9-20
- 帖子
- 844
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 ppspssss 于 2023-10-30 17:42 编辑
用芯☆淡茹水 的 〓 鼠标点击自寻路 〓 改成 NPC追 玩家(NPC追自己) , 但我不知是什么寻路算法来 ,如果知道的人能告诉一下我
只是用于实验,原来是宋乱贼狂的QQT探险游戏没有NPC寻路, 我就想找下有没寻路脚本,找到这个脚本,本来这个是带有鼠标功能,下列的是已去掉无鼠标功能
距离有限, 大慨两目标相距20格, 若有些复杂的距离再短就不能寻到
脚本经过改了只保留单独寻路,有兴趣的看,脚本中有些变量未列出来需自己进行声明
自己坐标是指$game_player.x和$game_player.y
寻路频率是每30帧进行一次, 过于频繁会无法应付而掉帧 , 因此会占用大量算力
除了追玩家想过如果在地图放置一些多个固定点进行寻路或许可以长距离移动 , 不过或许应该要找更好的解决方案
https://rpg.blue/thread-408715-1-1.html 脚本原贴地址
https://www.bilibili.com/video/B ... d2adeb1a2b4281add78 效果视频(NPC追自己
寻路
class Game_Map #-------------------------------------------------------------------------- def distance(x1, y1, x2, y2) return delta_x(x1, x2).abs + delta_y(y1, y2).abs end #-------------------------------------------------------------------------- def loop_horizontal? return false end #-------------------------------------------------------------------------- def loop_vertical? return false end #-------------------------------------------------------------------------- def delta_x(x1, x2) result = x1 - x2 if loop_horizontal? && result.abs > width / 2 result += result < 0 ? width : -width end return result end #-------------------------------------------------------------------------- def delta_y(y1, y2) result = y1 - y2 if loop_vertical? && result.abs > height / 2 result += result < 0 ? height : -height end return result end end #class class Game_Character alias xr_mv_initialize initialize def initialize xr_mv_initialize @search_limit = 15 end #-------------------------------------------------------------------------- def delta_x_from(x) return $game_map.delta_x(@x, x) end #-------------------------------------------------------------------------- def delta_y_from(y) return $game_map.delta_y(@y, y) end #-------------------------------------------------------------------------- def find_direction(x, y) $hi = $hi + 1 #貌似$hi是测试用 # pst"#{$hi}" return 0 if @x == x && @y == y goal_x = x; goal_y = y map_width = $game_map.width node_list = []; open_list = []; closed_list = [] start = {}; best = start start[:parent] = nil; start[:x] = @x; start[:y] = @y; start[:g] = 0 #start[:xr] = $game_map.distance(start[:x], start[:y], goal_x, goal_y); start[:xr] = $game_map.distance(@x, @y, goal_x, goal_y); node_list.push(start) open_list.push(start[:y] * map_width + start[:x]) t = 0 #t若大于1则可寻路到达目标,因此用来判断用 while node_list.size > 0 best_index = 0 node_list.size.times do |i| best_index = i if node_list[i][:xr] < node_list[best_index][:xr] end current = node_list[best_index] x1 = current[:x]; y1 = current[:y] pos1 = y1 * map_width + x1 g1 = current[:g] node_list.delete(current) open_list.delete(pos1) closed_list << pos1 if current[:x] == goal_x && current[:y] == goal_y #到达了目的地返回 #补充:t若大于1则可寻路到达目标,因此用来判断用 t += 1 best = current #pst"no" break else #注:会运行多次, 即使到达目标也要运行,因些不要返回,若返回只會运行一次 #return end next if g1 >= @search_limit 4.times do |j| direction = 2 + j * 2 x2 = x1 + (direction == 6 ? 1 : direction == 4 ? -1 : 0) y2 = y1 + (direction == 2 ? 1 : direction == 8 ? -1 : 0) pos2 = y2 * map_width + x2 next if closed_list.include?(pos2) || !passable?(x1, y1, direction) g2 = g1 + 1 index2 = open_list.index(pos2) if index2 == nil || g2 < node_list[index2][:g] if index2 != nil neighbor = node_list[index2] else neighbor = {}; node_list << neighbor; open_list << pos2 end neighbor[:parent] = current neighbor[:x] = x2 neighbor[:y] = y2 neighbor[:g] = g2 neighbor[:xr] = g2 + $game_map.distance(x2, y2, goal_x, goal_y) if !best || neighbor[:xr] - neighbor[:g] < best[:xr] - best[:g] best = neighbor end end end end node = best while node[:parent] && node[:parent] != start node = node[:parent] end delta_x1 = $game_map.delta_x(node[:x], start[:x]) delta_y1 = $game_map.delta_y(node[:y], start[:y]) if delta_y1 > 0 #以下像之前测试用的,无视, #貌似当初始为下了泡后让怪不移动返回333,但后来好像不用 #因该游戏作者使用了泡泡以地形标志为七实际也是地形,站在泡泡上面就怪寻不到自己 #if @泡泡禁止通行方向 == "下" #@对泡原地思考时间_v = 30 #return 0,333 #end #if return 2 ,t #返回方向以及是否移动,t若大于1则可寻路到达目标,因此用来判断用 #分别为:2下,4左,6右,8上 #(一次只移动一格) elsif delta_x1 < 0 #if @泡泡禁止通行方向 == "左" #@对泡原地思考时间_v = 30 #return 0,333 #end #if return 4 ,t elsif delta_x1 > 0 # if @泡泡禁止通行方向 == "右" #@对泡原地思考时间_v = 30 # return 0,333 # end #if return 6 ,t elsif delta_y1 < 0 # if @泡泡禁止通行方向 == "上" #@对泡原地思考时间_v = 30 #return 0,333 # end #if return 8 ,t end delta_x2 = delta_x_from(goal_x) delta_y2 = delta_y_from(goal_y) if delta_x2.abs > delta_y2.abs return delta_x2 > 0 ? 4 : 6 ,t elsif delta_y2 != 0 return delta_y2 > 0 ? 8 : 2 ,t end return 0 end end #class Game_Character
class Game_Map
#--------------------------------------------------------------------------
def distance(x1, y1, x2, y2)
return delta_x(x1, x2).abs + delta_y(y1, y2).abs
end
#--------------------------------------------------------------------------
def loop_horizontal?
return false
end
#--------------------------------------------------------------------------
def loop_vertical?
return false
end
#--------------------------------------------------------------------------
def delta_x(x1, x2)
result = x1 - x2
if loop_horizontal? && result.abs > width / 2
result += result < 0 ? width : -width
end
return result
end
#--------------------------------------------------------------------------
def delta_y(y1, y2)
result = y1 - y2
if loop_vertical? && result.abs > height / 2
result += result < 0 ? height : -height
end
return result
end
end #class
class Game_Character
alias xr_mv_initialize initialize
def initialize
xr_mv_initialize
@search_limit = 15
end
#--------------------------------------------------------------------------
def delta_x_from(x)
return $game_map.delta_x(@x, x)
end
#--------------------------------------------------------------------------
def delta_y_from(y)
return $game_map.delta_y(@y, y)
end
#--------------------------------------------------------------------------
def find_direction(x, y)
$hi = $hi + 1
#貌似$hi是测试用
# pst"#{$hi}"
return 0 if @x == x && @y == y
goal_x = x; goal_y = y
map_width = $game_map.width
node_list = []; open_list = []; closed_list = []
start = {}; best = start
start[:parent] = nil; start[:x] = @x; start[:y] = @y; start[:g] = 0
#start[:xr] = $game_map.distance(start[:x], start[:y], goal_x, goal_y);
start[:xr] = $game_map.distance(@x, @y, goal_x, goal_y);
node_list.push(start)
open_list.push(start[:y] * map_width + start[:x])
t = 0 #t若大于1则可寻路到达目标,因此用来判断用
while node_list.size > 0
best_index = 0
node_list.size.times do |i|
best_index = i if node_list[i][:xr] < node_list[best_index][:xr]
end
current = node_list[best_index]
x1 = current[:x]; y1 = current[:y]
pos1 = y1 * map_width + x1
g1 = current[:g]
node_list.delete(current)
open_list.delete(pos1)
closed_list << pos1
if current[:x] == goal_x && current[:y] == goal_y
#到达了目的地返回
#补充:t若大于1则可寻路到达目标,因此用来判断用
t += 1
best = current
#pst"no"
break
else
#注:会运行多次, 即使到达目标也要运行,因些不要返回,若返回只會运行一次
#return
end
next if g1 >= @search_limit
4.times do |j|
direction = 2 + j * 2
x2 = x1 + (direction == 6 ? 1 : direction == 4 ? -1 : 0)
y2 = y1 + (direction == 2 ? 1 : direction == 8 ? -1 : 0)
pos2 = y2 * map_width + x2
next if closed_list.include?(pos2) || !passable?(x1, y1, direction)
g2 = g1 + 1
index2 = open_list.index(pos2)
if index2 == nil || g2 < node_list[index2][:g]
if index2 != nil
neighbor = node_list[index2]
else
neighbor = {}; node_list << neighbor; open_list << pos2
end
neighbor[:parent] = current
neighbor[:x] = x2
neighbor[:y] = y2
neighbor[:g] = g2
neighbor[:xr] = g2 + $game_map.distance(x2, y2, goal_x, goal_y)
if !best || neighbor[:xr] - neighbor[:g] < best[:xr] - best[:g]
best = neighbor
end
end
end
end
node = best
while node[:parent] && node[:parent] != start
node = node[:parent]
end
delta_x1 = $game_map.delta_x(node[:x], start[:x])
delta_y1 = $game_map.delta_y(node[:y], start[:y])
if delta_y1 > 0
#以下像之前测试用的,无视,
#貌似当初始为下了泡后让怪不移动返回333,但后来好像不用
#因该游戏作者使用了泡泡以地形标志为七实际也是地形,站在泡泡上面就怪寻不到自己
#if @泡泡禁止通行方向 == "下"
#@对泡原地思考时间_v = 30
#return 0,333
#end #if
return 2 ,t
#返回方向以及是否移动,t若大于1则可寻路到达目标,因此用来判断用
#分别为:2下,4左,6右,8上
#(一次只移动一格)
elsif delta_x1 < 0
#if @泡泡禁止通行方向 == "左"
#@对泡原地思考时间_v = 30
#return 0,333
#end #if
return 4 ,t
elsif delta_x1 > 0
# if @泡泡禁止通行方向 == "右"
#@对泡原地思考时间_v = 30
# return 0,333
# end #if
return 6 ,t
elsif delta_y1 < 0
# if @泡泡禁止通行方向 == "上"
#@对泡原地思考时间_v = 30
#return 0,333
# end #if
return 8 ,t
end
delta_x2 = delta_x_from(goal_x)
delta_y2 = delta_y_from(goal_y)
if delta_x2.abs > delta_y2.abs
return delta_x2 > 0 ? 4 : 6 ,t
elsif delta_y2 != 0
return delta_y2 > 0 ? 8 : 2 ,t
end
return 0
end
end #class Game_Character
□Game_Character怪物接近
#============================================================================== # ■ Game_Character (分割定义 2) #------------------------------------------------------------------------------ # 处理角色的类。本类作为 Game_Player 类与 Game_Event # 类的超级类使用。 #============================================================================== $hi = 0 #测试用的变量,无视 class Game_Character #-------------------------------------------------------------------------- # ● 移动类型 : 接近 #-------------------------------------------------------------------------- def move_type_toward_player # 求得与主角坐标的差 sx = @x - $game_player.x sy = @y - $game_player.y # 求得差的绝对值 abs_sx = sx > 0 ? sx : -sx abs_sy = sy > 0 ? sy : -sy # 如果纵横共计离开 20 个元件 if sx + sy >= 20 #只是人在怪上 (无效) #pst "#{sx + sy}" # 随机 #move_random #return end #return if abs_sx + abs_sy <= 0 #pst "#{abs_sx + abs_sy}" #和主角相同位置 #不懂为什么是小於 return #(返回) end #if abs_sx + abs_sy >= 12 #move_random #return #end #if if (@原地思考时间_v > 0) and (abs_sx + abs_sy >= 12) #b 测试 @原地思考时间_v -= 1 move_random return #t elsif @对泡原地思考时间_v >0 elsif @原地思考时间_v >0 # pst "#{@原地思考时间_v}" @原地思考时间_v -= 1 #t @对泡原地思考时间_v -= 1 #pst "#{@对泡原地思考时间_v},#{@泡泡禁止通行方向}" #t@泡泡禁止通行方向 == "" return end #if # 随机 0~5 的分支 #case rand(6) #when 0..3 # 接近主角 #move_toward_player #$hi = $hi + 1 #pst"#{$hi}" 得到 = test_接近主角 # pst "#{得到}" if 得到 == "等待一段时间" #由于到达不到最终目标, #等待30帧,再执行寻路,防止频繁寻路而造成运行效率低下 @原地思考时间_v = 30 #原地思考 end# #when 4 # 随机 # move_random #when 5 # 前进一步 # move_forward #end end #-------------------------------------------------------------------------- # ● 接近主角 #-------------------------------------------------------------------------- def test_接近主角 #让NPC靠近主角 (一次只移动一格) #这里就是返回t的用处:得到是否行走, direction, 得到是否行走 = find_direction($game_player.x, $game_player.y) if 得到是否行走 == 0 return "等待一段时间" #由于到达不到最终目标 #因此 # elsif 得到是否行走 == 333 #貌似测试用,没实际用途无视 # pst "=3" # return "泡泡不可行走" else #不知为什么会返回这个? 又好像没有触发 #pst "#{得到是否行走}" end #if if direction ==2 move_down elsif direction ==4 move_left elsif direction ==6 move_right elsif direction ==8 move_up end#if direction end #def def move_toward_player if $game_switches[9]#9号开关当2P隐藏了 #双人游戏,但没做双人寻路,无视 # 求得与主角的坐标差 sx = @x - $game_player.x sy = @y - $game_player.y # 求得差的绝对值 abs_sx = sx.abs abs_sy = sy.abs else # 求得与主角的坐标差 sx = @x - $game_player.x sy = @y - $game_player.y sx2 = @x - $game_player2.x sy2 = @y - $game_player2.y # 求得差的绝对值 abs_sx = sx.abs abs_sy = sy.abs abs_sx2 = sx2.abs abs_sy2 = sy2.abs if (abs_sy2 + abs_sx2) < (abs_sy + abs_sx) abs_sx = abs_sx2 abs_sy = abs_sy2 sx = sx2 sy = sy2 end end # 坐标相等情况下 if sx == 0 and sy == 0 return end # 横距离与纵距离相等的情况下 if abs_sx == abs_sy # 随机将边数增加 1 rand(2) == 0 ? abs_sx += 1 : abs_sy += 1 end # 横侧距离长的情况下 if abs_sx > abs_sy # 左右方向优先。向主角移动 sx > 0 ? move_left : move_right if not moving? and sy != 0 sy > 0 ? move_up : move_down end # 竖侧距离长的情况下 else # 上下方向优先。向主角移动 sy > 0 ? move_up : move_down if not moving? and sx != 0 sx > 0 ? move_left : move_right end end end end
#==============================================================================
# ■ Game_Character (分割定义 2)
#------------------------------------------------------------------------------
# 处理角色的类。本类作为 Game_Player 类与 Game_Event
# 类的超级类使用。
#==============================================================================
$hi = 0 #测试用的变量,无视
class Game_Character
#--------------------------------------------------------------------------
# ● 移动类型 : 接近
#--------------------------------------------------------------------------
def move_type_toward_player
# 求得与主角坐标的差
sx = @x - $game_player.x
sy = @y - $game_player.y
# 求得差的绝对值
abs_sx = sx > 0 ? sx : -sx
abs_sy = sy > 0 ? sy : -sy
# 如果纵横共计离开 20 个元件
if sx + sy >= 20 #只是人在怪上 (无效)
#pst "#{sx + sy}"
# 随机
#move_random
#return
end
#return
if abs_sx + abs_sy <= 0
#pst "#{abs_sx + abs_sy}" #和主角相同位置 #不懂为什么是小於
return #(返回)
end
#if abs_sx + abs_sy >= 12
#move_random
#return
#end #if
if (@原地思考时间_v > 0) and (abs_sx + abs_sy >= 12) #b 测试
@原地思考时间_v -= 1
move_random
return
#t elsif @对泡原地思考时间_v >0
elsif @原地思考时间_v >0
# pst "#{@原地思考时间_v}"
@原地思考时间_v -= 1
#t @对泡原地思考时间_v -= 1
#pst "#{@对泡原地思考时间_v},#{@泡泡禁止通行方向}"
#t@泡泡禁止通行方向 == ""
return
end #if
# 随机 0~5 的分支
#case rand(6)
#when 0..3 # 接近主角
#move_toward_player
#$hi = $hi + 1
#pst"#{$hi}"
得到 = test_接近主角
# pst "#{得到}"
if 得到 == "等待一段时间" #由于到达不到最终目标,
#等待30帧,再执行寻路,防止频繁寻路而造成运行效率低下
@原地思考时间_v = 30
#原地思考
end#
#when 4 # 随机
# move_random
#when 5 # 前进一步
# move_forward
#end
end
#--------------------------------------------------------------------------
# ● 接近主角
#--------------------------------------------------------------------------
def test_接近主角
#让NPC靠近主角 (一次只移动一格)
#这里就是返回t的用处:得到是否行走,
direction, 得到是否行走 = find_direction($game_player.x, $game_player.y)
if 得到是否行走 == 0
return "等待一段时间" #由于到达不到最终目标
#因此
# elsif 得到是否行走 == 333 #貌似测试用,没实际用途无视
# pst "=3"
# return "泡泡不可行走"
else
#不知为什么会返回这个? 又好像没有触发
#pst "#{得到是否行走}"
end #if
if direction ==2
move_down
elsif direction ==4
move_left
elsif direction ==6
move_right
elsif direction ==8
move_up
end#if direction
end #def
def move_toward_player
if $game_switches[9]#9号开关当2P隐藏了 #双人游戏,但没做双人寻路,无视
# 求得与主角的坐标差
sx = @x - $game_player.x
sy = @y - $game_player.y
# 求得差的绝对值
abs_sx = sx.abs
abs_sy = sy.abs
else
# 求得与主角的坐标差
sx = @x - $game_player.x
sy = @y - $game_player.y
sx2 = @x - $game_player2.x
sy2 = @y - $game_player2.y
# 求得差的绝对值
abs_sx = sx.abs
abs_sy = sy.abs
abs_sx2 = sx2.abs
abs_sy2 = sy2.abs
if (abs_sy2 + abs_sx2) < (abs_sy + abs_sx)
abs_sx = abs_sx2
abs_sy = abs_sy2
sx = sx2
sy = sy2
end
end
# 坐标相等情况下
if sx == 0 and sy == 0
return
end
# 横距离与纵距离相等的情况下
if abs_sx == abs_sy
# 随机将边数增加 1
rand(2) == 0 ? abs_sx += 1 : abs_sy += 1
end
# 横侧距离长的情况下
if abs_sx > abs_sy
# 左右方向优先。向主角移动
sx > 0 ? move_left : move_right
if not moving? and sy != 0
sy > 0 ? move_up : move_down
end
# 竖侧距离长的情况下
else
# 上下方向优先。向主角移动
sy > 0 ? move_up : move_down
if not moving? and sx != 0
sx > 0 ? move_left : move_right
end
end
end
end
|
|