惯用的clojure范围/碰撞检查?

时间:2014-12-27 20:27:04

标签: clojure collision-detection

回到clojure,我写了这个小东西来检查两个盒子是否发生碰撞,检查一个盒子的顶点是否在另一个盒子里面:

(defn around
  [val radius]
  (let [half (/ radius 2)
        low (- val half)
        high (+ val half)]
    [low high]))

(defn colliding?
  [this that]
  (let [[this-x1 this-x2] (around (:x this) (:w this))
        [this-y1 this-y2] (around (:y this) (:h this))
        [this-z1 this-z2] (around (:z this) (:l this))
        [that-x1 that-x2] (around (:x that) (:w that))
        [that-y1 that-y2] (around (:y that) (:h that))
        [that-z1 that-z2] (around (:z that) (:l that))]
    (or (and (or (<= that-x1 this-x1 that-x2)
                 (<= that-x1 this-x2 that-x2))
             (or (<= that-y1 this-y1 that-y2)
                 (<= that-y1 this-y2 that-y2))
             (or (<= that-z1 this-z1 that-z2)
                 (<= that-z1 this-z2 that-z2)))
        (and (or (<= this-x1 that-x1 this-x2)
                 (<= this-x1 that-x2 this-x2))
             (or (<= this-y1 that-y1 this-y2)
                 (<= this-y1 that-y2 this-y2))
             (or (<= this-z1 that-z1 this-z2)
                 (<= this-z1 that-z2 this-z2))))))
由于重复,这闻起来很糟糕,但我不确定清理它的最佳方法是什么。有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

您可以使用在一个方向上发生碰撞的事实来简化代码,除非一个对象的起始坐标高于另一个对象的结束坐标。 即足够的测试是

(not (or (> this-x1 that-x2)
         (> that-x1 this-x2)))

相当于

(and (<= this-x1 that-x2)
     (<= that-x1 this-x2))

使用此功能,您的colliding?可能会简化为

(defn colliding?
  [this that]
  (let [[this-x1 this-x2] (around (:x this) (:w this))
        [this-y1 this-y2] (around (:y this) (:h this))
        [this-z1 this-z2] (around (:z this) (:l this))
        [that-x1 that-x2] (around (:x that) (:w that))
        [that-y1 that-y2] (around (:y that) (:h that))
        [that-z1 that-z2] (around (:z that) (:l that))]
     (and (<= this-x1 that-x2)
          (<= that-x1 this-x2)
          (<= this-y1 that-y2)
          (<= that-y1 this-y2)
          (<= this-z1 that-z2)
          (<= that-z1 this-z2))))

如果您然后分解出检查一维中重叠的函数conflicting?

(defn conflicting?
  [this that coordinate size]
  (let [[this-c1 this-c2] (around (coordinate this) (size this))
        [that-c1 that-c2] (around (coordinate that) (size that))]
    (and (<= this-c1 that-c2)
         (<= that-c1 this-c2)))
通过使用尺寸和大小的映射可以进一步简化

colliding?

(defn colliding?
  [this that]
  (every? true? (map #(conflicting? this that %1 %2)
                     [:x :y :z]
                     [:w :h :l])))

修改

此外,conflicting?可以简化为

(defn conflicting?
  [this that coordinate size]
  (<= (math/abs (- (coordinate this) (coordinate that)))
      (/ (+ (size this) (size that)) 2)))

使函数around过时以便检测冲突。