2014-12-27 2 views
0

получить обратно в Clojure, и я написал эту маленькую вещь, чтобы проверить, если две коробки сталкиваясь, проверяя, если вершины одного внутри другого:идиоматический диапазон 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

Вы можете упростить код, используя тот факт, что есть столкновение в одном направлении , если стартовая координата одного объекта выше конечной координаты другой. I.e. достаточного испытание

(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 устаревшими с целью обнаружения столкновений.

+0

Это определенно то, что я думал, возможно, спасибо! он чувствует намного лучше обрабатывать параметры xyz/whl на карте. упрощение математики также помогает. – xen

Смежные вопросы