mirror of
https://github.com/richardharrington/robotwar.git
synced 2024-05-28 23:41:31 +00:00
got billiard ball collision detection almost working (still wonky)
This commit is contained in:
parent
a7cb6a58da
commit
8e70c42e3d
|
@ -25,8 +25,14 @@
|
||||||
:shot-timer 0.0
|
:shot-timer 0.0
|
||||||
:brain (brain/init-brain src-code (register/init-registers idx))})
|
:brain (brain/init-brain src-code (register/init-registers idx))})
|
||||||
|
|
||||||
|
(defn update-robots
|
||||||
|
"takes a world and a function, and returns a world
|
||||||
|
with its robots updated by passing them through the function"
|
||||||
|
[world f]
|
||||||
|
(update-in world [:robots] f))
|
||||||
|
|
||||||
(defn update-robot
|
(defn update-robot
|
||||||
"takes a robot, a world, and a function, and returns a world
|
"takes a robot index, a world, and a function, and returns a world
|
||||||
with the robot updated by passing it through the function"
|
with the robot updated by passing it through the function"
|
||||||
[robot-idx world f]
|
[robot-idx world f]
|
||||||
(update-in world [:robots robot-idx] f))
|
(update-in world [:robots robot-idx] f))
|
||||||
|
@ -60,56 +66,67 @@
|
||||||
:v-x new-v-x
|
:v-x new-v-x
|
||||||
:v-y new-v-y})))
|
:v-y new-v-y})))
|
||||||
|
|
||||||
(defn collide-or-not
|
(defn collide-two-robots
|
||||||
"takes a robot and a world and returns the world, with the
|
"takes a vector of robots, two robot-indexes (an acting robot
|
||||||
velocities of robots altered if they have collided with
|
and a target robot), and returns a vector of robots with those
|
||||||
each other. Does not currently calculate damage to robots."
|
two altered if the actor has collided with the target.
|
||||||
; TODO: This is terrible and needs to be rewritten soon. The whole last
|
Right now they're just behaving like square billiard balls --
|
||||||
; two-thirds consists of code that would be a lot shorter even in JavaScript,
|
all momentum from one is transferred to the other when they collide.
|
||||||
; for Christ's sake. And it's really inefficient -- calculates
|
To account for overshoot during the tick, the position of the actor
|
||||||
; a lot of x and y stuff twice.
|
is set to but up against the target.
|
||||||
[robot-idx {robots :robots :as world}]
|
Does not currently calculate damage. when it does, it will
|
||||||
(let [robot (get-in world [:robots robot-idx])
|
need to only assign each robot half the damage, because the other
|
||||||
other-robot-idxs (filter #(not= robot-idx %) (range (count robots)))
|
half will be assigned when the other robot it ticks through its own turn."
|
||||||
enemy-dist-x (fn [other-robot-idx]
|
[robots actor-idx target-idx]
|
||||||
(let [other-robot (get-in world [:robots other-robot-idx])]
|
(let [actor (get robots actor-idx)
|
||||||
(Math/abs (- (:pos-x robot) (:pos-x other-robot)))))
|
target (get robots target-idx)
|
||||||
enemy-dist-y (fn [other-robot-idx]
|
dist-x (- (:pos-x target) (:pos-x actor))
|
||||||
(let [other-robot (get-in world [:robots other-robot-idx])]
|
dist-y (- (:pos-y target) (:pos-y actor))
|
||||||
(Math/abs (- (:pos-y robot) (:pos-y other-robot)))))
|
min-dist (* ROBOT-RADIUS 2)
|
||||||
close? (fn [dist]
|
colliding (and (< dist-x min-dist)
|
||||||
(< dist (* ROBOT-RADIUS 2)))
|
(< dist-y min-dist)
|
||||||
enemy-colliding (fn [other-robot-idx]
|
(if (> dist-x dist-y) :x :y))]
|
||||||
(let [dist-x (enemy-dist-x other-robot-idx)
|
(if colliding
|
||||||
dist-y (enemy-dist-y other-robot-idx)]
|
(let [new-actor (case colliding
|
||||||
(and (close? dist-x)
|
:x (assoc
|
||||||
(close? dist-y)
|
actor
|
||||||
(if (> dist-x dist-y)
|
:v-x (:v-x target)
|
||||||
:x
|
:pos-x (- (:pos-x target)
|
||||||
:y))))
|
(Math/copySign min-dist (:v-x actor))))
|
||||||
enemy-colliding-x? (fn [other-robot-idx]
|
:y (assoc
|
||||||
(= (enemy-colliding other-robot-idx) :x))
|
actor
|
||||||
enemy-colliding-y? (fn [other-robot-idx]
|
:v-y (:v-y target)
|
||||||
(= (enemy-colliding other-robot-idx) :y))
|
:pos-y (- (:pos-y target)
|
||||||
colliding-enemy-idxs-x (set (filter enemy-colliding-x? other-robot-idxs))
|
(Math/copySign min-dist (:v-y actor)))))
|
||||||
colliding-enemy-idxs-y (set (filter enemy-colliding-y? other-robot-idxs))
|
new-target (case colliding
|
||||||
total-colliding-idxs-x (if (not-empty colliding-enemy-idxs-x)
|
:x (assoc target :v-x (:v-x actor))
|
||||||
(conj colliding-enemy-idxs-x robot-idx)
|
:y (assoc target :v-y (:v-y actor)))]
|
||||||
#{})
|
{colliding (assoc robots actor-idx new-actor, target-idx new-target)})
|
||||||
total-colliding-idxs-y (if (not-empty colliding-enemy-idxs-y)
|
{nil robots})))
|
||||||
(conj colliding-enemy-idxs-y robot-idx)
|
|
||||||
#{})
|
(defn collide-all-robots
|
||||||
new-robots-v-x (mapv (fn [{rob-idx :idx :as rob}]
|
"takes a vector of robots and an actor-idx,
|
||||||
(if (get total-colliding-idxs-x rob-idx)
|
and returns a vector of robots with any collisions that have occurred
|
||||||
(assoc rob :v-x 0.0)
|
(may be at most one x-collision and at most one y-collision)."
|
||||||
rob))
|
; TODO: this is remarkably inefficient, and checks the collisions
|
||||||
robots)
|
; twice in a lot of cases. Sort this out when we sort out the whole :x and :y issue.
|
||||||
new-robots-v-y (mapv (fn [{rob-idx :idx :as rob}]
|
[robots actor-idx]
|
||||||
(if (get total-colliding-idxs-y rob-idx)
|
(let [target-idxs (filter #(not= actor-idx %) (range (count robots)))
|
||||||
(assoc rob :v-y 0.0)
|
collided-robots-x (or (some (fn [target-idx]
|
||||||
rob))
|
(:x (collide-two-robots
|
||||||
new-robots-v-x)]
|
robots
|
||||||
(assoc world :robots new-robots-v-y)))
|
actor-idx
|
||||||
|
target-idx)))
|
||||||
|
target-idxs)
|
||||||
|
robots)
|
||||||
|
collided-robots-y (or (some (fn [target-idx]
|
||||||
|
(:y (collide-two-robots
|
||||||
|
collided-robots-x
|
||||||
|
actor-idx
|
||||||
|
target-idx)))
|
||||||
|
target-idxs)
|
||||||
|
collided-robots-x)]
|
||||||
|
collided-robots-y))
|
||||||
|
|
||||||
(defn tick-robot
|
(defn tick-robot
|
||||||
"takes a robot and a world and returns the new state of the world
|
"takes a robot and a world and returns the new state of the world
|
||||||
|
@ -120,12 +137,21 @@
|
||||||
[{robot-idx :idx :as robot} world]
|
[{robot-idx :idx :as robot} world]
|
||||||
(if (<= (:damage robot) 0)
|
(if (<= (:damage robot) 0)
|
||||||
world
|
world
|
||||||
(let [ticked-world (brain/tick-brain
|
(let [ticked-world (brain/tick-brain
|
||||||
robot
|
robot
|
||||||
world
|
world
|
||||||
register/read-register
|
register/read-register
|
||||||
register/write-register)
|
register/write-register)
|
||||||
shot-timer-updated-world (update-robot robot-idx ticked-world update-shot-timer)
|
shot-timer-updated-world (update-robot
|
||||||
collision-detected-world (collide-or-not robot-idx shot-timer-updated-world)]
|
robot-idx
|
||||||
(update-robot robot-idx collision-detected-world move-robot))))
|
ticked-world
|
||||||
|
update-shot-timer)
|
||||||
|
moved-world (update-robot
|
||||||
|
robot-idx
|
||||||
|
shot-timer-updated-world
|
||||||
|
move-robot)
|
||||||
|
collision-detected-world (update-robots
|
||||||
|
moved-world
|
||||||
|
#(collide-all-robots % robot-idx))]
|
||||||
|
collision-detected-world)))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user