如何在ruby中检查两个范围是否以任何方式相交?

f87krz0w  于 2023-06-29  发布在  Ruby
关注(0)|答案(5)|浏览(148)

我试图在Ruby中的Gosu中编写hitboxes,并希望检查2个范围是否满足(范围是坐标),我希望它简单地给予true或false
我查过了,找到了射程。掩护?代码,但在测试后,这表明它只检查一个范围是否完全适合另一个范围,而不是如果它们只是部分连接。

#both sprites are arrays, with the following structure
#[image_data, sprite_x, sprite_y]
#image_data.width would return how wide the image is
#The x and y is the top left of the sprite
  def hit_scan(sprite1, sprite2)
    x_connect = (sprite1[1]..sprite1[1] + sprite1[0].width).cover?(sprite2[1]..(sprite2[1] + sprite2[0].width))
    y_connect = (sprite1[2]..sprite1[2] + sprite1[0].height).cover?(sprite2[2]..(sprite2[2] + sprite2[0].height)
    if x_connect == true
      if y_connect == true
        return true
      else
        return false
      end
    else
      return false
    end
  end

这就是我尝试的,只有当整个精灵都在另一个精灵中时才返回true。
我期望每当精灵接触时,它会返回一个true语句,但只有当一个精灵在另一个精灵中时,它才会返回true。

bmvo0sr5

bmvo0sr51#

您可以检查一个范围是否包含另一个范围的开始或结束:

r1 = (1..5)
r2 = (4..8)

r1.include?(r2.begin) || r1.include?(r2.end) || r2.include?(r1.begin) || r2.include?(r1.end)

在您的案例中:

r1 = (sprite1[1]..sprite1[1] + sprite1[0].width)
r2 = (sprite2[1]..sprite2[1] + sprite2[0].width)
r1.include?(sprite2[1]) || r1.include?(sprite2[1] + sprite2[0].width) || 
  r2.include(sprite1[1]) || r2.include(sprite1[1] + sprite1[0].width)

假设范围不是无限的。

vqlkdk9b

vqlkdk9b2#

正如@muistooshort在评论中指出的那样,有许多情况需要考虑。
我假设范围的元素是整数,如示例中所示。

编码

确定两个范围是否相交的最简单方法是对确定它们是否不相交的表达式求反。

def overlap?(r1, r2)
  return false if r1.size.zero? || r2.size.zero?
  !(range_last(r1) < r2.begin || range_last(r2) < r1.begin) 
end

def range_last(r)
  return Float::INFINITY if r.end==Float::INFINITY || r.end.nil?
  r.include?(r.end) ? r.end : r.end-1  
end

示例

overlap? 1..3, 2..5                               #=> true 
overlap? 1..3, 4..5                               #=> false 
overlap? 3..1, 0..5                               #=> false 
overlap? 1..4, 4..8                               #=> true 
overlap? 1...4, 4..8                              #=> false 
overlap? 4.., 1..4                                #=> true 
overlap? 4.., 1...4                               #=> false 
overlap? -Float::INFINITY..Float::INFINITY, 1..1  #=> true
overlap? -Float::INFINITY..7, 7..8                #=> true
overlap? -Float::INFINITY...7, 7..8               #=> false 
overlap? -4..Float::INFINITY, -6..-4              #=> true 
overlap? -4..Float::INFINITY, 6...-4              #=> false

观察第3个示例中的范围3..1为空。
另请注意:

range_last(1..)                                   #=> Infinity 
range_last(1..Float::INFINITY)                    #=> Infinity 
range_last(1..3)                                  #=> 3 
range_last(1...3)                                 #=> 2

如果两个值域r1r2是有限的,并且是两点簇,则可以用r.last替换range_last(r)

j91ykkif

j91ykkif3#

如果你没有无限的范围,也许你可以考虑使用Set交集方法Set#&:

require 'set'

def overlap?(a, b)
  (a.to_set & b.to_set).any?
end
ycl3bljg

ycl3bljg4#

如果使用Rails,请使用.overlaps?

Rails从Rails 3开始就在Range上有了一个名为overlaps?的方法:

r1 = (1..5)
r2 = (4..8)
r1.overlaps?( r2 ) #=> true

r3 = (6..10)
r1.overlaps?( r3 ) #=> false
r2.overlaps?( r3 ) #=> true

如果你正在使用Rails或者想看看它的实现,这是非常方便的。

xtfmy6hx

xtfmy6hx5#

你们是不是太为难我了?也许我错过了一些东西,但检查交叉点的简单方法如下。

#use the splat operator `*` to change our range to an array
r1 = *(1..5) # [1 , 2 , 3 , 4, 5]
r2 = *(4..8) # [4, 5, 6, 7, 8]
# and give the intersection with the intersection operator &
# if it is an empty array, they don't intersect
r1 & r2 # [4, 5]
# or 
(r1 & r2).any? # true

注意:数组的顺序对结果没有影响。

相关问题