aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorColin Okay <colin@cicadas.surf>2022-07-09 10:42:42 -0500
committerColin Okay <colin@cicadas.surf>2022-07-09 10:42:42 -0500
commitfa5205509e1e56e8894069d02c44f6e527c07fbd (patch)
tree0771e1c1cf396785aa457c18f16aad983a30befa
parent6897f90e0f3df933b271eadd6a41513c8173c080 (diff)
[example] add collision detection to ghoulspree
-rw-r--r--examples/09-ghoulspree.lisp63
1 files changed, 57 insertions, 6 deletions
diff --git a/examples/09-ghoulspree.lisp b/examples/09-ghoulspree.lisp
index 744397d..9b40605 100644
--- a/examples/09-ghoulspree.lisp
+++ b/examples/09-ghoulspree.lisp
@@ -10,7 +10,8 @@
;;; CLASSES
(defclass/std ghoulspree (ww::application)
- ((ghouls-per-click :std 50)))
+ ((ghouls-per-click :std 10)
+ (collision-on-p :std t)))
(defclass/std ghoul (ww:bitmap)
((dx dy dr :std)))
@@ -21,8 +22,8 @@
(make-instance 'ghoul :texture (ww:get-asset "Fezghoul.png")
:x x :y y
:dr (random-velocity)
- :dx (random-velocity 5)
- :dy (random-velocity 5)))
+ :dx (random-velocity 4)
+ :dy (random-velocity 4)))
(defun out-of-bounds-p (ghoul)
(not
@@ -31,7 +32,7 @@
(< -50 (ww:y ghoul) 650))))
(defun random-velocity (&optional (size 1.0))
- (* size (if (< 0.5 (random 1.0))
+ (* size (if (zerop (random 2))
(random 1.0)
(* -1 (random 1.0)))))
@@ -46,23 +47,73 @@
on which boundary VAL is outside of."
(max lo (min val hi)))
+(defun sign (x)
+ (if (zerop x) 0
+ (/ x (abs x))))
+
+(defmacro with-pairs ((a b) ls &rest body)
+ "run body with a and b bound to unique 2-sets of LS"
+ (let ((more-a (gensym)))
+ `(loop for (,a . ,more-a) on ,ls do
+ (loop for ,b in ,more-a do (progn ,@body)) )))
+
+(defun handle-collision (g1 g2 &optional (friction 0.99))
+ (with-slots ((dx1 dx) (dy1 dy)) g1
+ (with-slots ((dx2 dx) (dy2 dy)) g2
+ (let ((tdx (* friction dx1))
+ (tdy (* friction dy1)))
+ (setf dx1 (* friction dx2)
+ dy1 (* friction dy2)
+ dx2 tdx
+ dy2 tdy)))))
+
(ww:defhandler moveghouls
(ww:on-perframe (app)
+ ;; first handle collisions
+ (when (collision-on-p app)
+ (with-pairs
+ (g1 g2) (ww:container-units app)
+ (when (ww:units-intersect-p g1 g2)
+ (handle-collision g1 g2 0.99)
+ ;; need a "bounce"
+ (advance-pos g1)
+ (advance-pos g1)
+ (advance-pos g2)
+ (advance-pos g2))))
+
+ ;; then update positions and remove the out of bounds
(loop for ghoul in (ww:container-units app)
do (advance-pos ghoul)
when (out-of-bounds-p ghoul)
do (ww:drop-unit ghoul))))
+(defun random-sign ()
+ (if (zerop (random 2)) -1 1))
+
+(defun random-between (lo hi)
+ (+ lo (random (- hi lo))))
+
(ww:defhandler add-ghouls
(ww:on-mousedown (app x y)
(loop repeat (ghouls-per-click app)
- do (ww:add-unit app (make-ghoul x y)))))
+ for rx = (random 800); (+ x (* (random-sign) (random-between 30 60)))
+ for ry = (random 600); (+ y (* (random-sign) (random-between 30 60)))
+ do (ww:add-unit app (make-ghoul rx ry)))
+ (format t "~a ghouls on screen~%"
+ (length (ww:container-units app )))))
+
+(ww:defhandler toggle-collision
+ (ww:on-keydown ()
+ (format t "collision: ~a~%"
+ (setf (collision-on-p target)
+ (not (collision-on-p target))))))
(defmethod ww::boot ((app ghoulspree))
"Adds the intro text and sets up the start button handler."
(ww:add-handler app #'add-ghouls)
- (ww:add-handler app #'moveghouls))
+ (ww:add-handler app #'moveghouls)
+ (ww:add-handler app #'toggle-collision))
(defun start ()
(ww::start