7e868ce7595b

Episode 18: Particle Enhancements
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Tue, 03 May 2016 23:59:09 +0000
parents 43ee81d9eec0
children 6c055494d41d
branches/tags (none)
files package.lisp src/main.lisp src/particles.lisp

Changes

--- a/package.lisp	Tue May 03 00:37:05 2016 +0000
+++ b/package.lisp	Tue May 03 23:59:09 2016 +0000
@@ -100,7 +100,13 @@
     #:particle-accelerate!
     #:particle-angle-to
     #:particle-distance-to
-    #:particle-gravitate-to!))
+    #:particle-gravitate-to!
+    #:particle-gravitate-add!
+    #:particle-gravitate-remove!
+    #:particle-spring-to!
+    #:particle-spring-add!
+    #:particle-spring-remove!
+    ))
 
 (defpackage #:coding-math.fps
   (:use
--- a/src/main.lisp	Tue May 03 00:37:05 2016 +0000
+++ b/src/main.lisp	Tue May 03 23:59:09 2016 +0000
@@ -1,9 +1,5 @@
 (in-package #:coding-math)
 
-(declaim (optimize (speed 3)
-                   (safety 1)
-                   (debug 0)))
-
 ;;;; Config
 (defparameter *width* 600)
 (defparameter *height* 400)
@@ -13,49 +9,105 @@
 
 
 ;;;; Sketch
-(defun draw-grid ()
-  (with-pen (make-pen :stroke (gray 0.8))
-    (loop :for x :from 0 :below *width* :by 40
-          :do (line x 0 x *height*))
-    (loop :for y :from 0 :below *height* :by 40
-          :do (line 0 y *width* y))))
+(defun draw-particle (p pen)
+  (with-pen pen
+    (circle (particle-x p) (particle-y p) (particle-radius p))))
+
 
 (defsketch cm (:width *width*
                :height *height*
                :debug :scancode-d)
-    ((mouse)
-     (k)
-     (separation)
-     (particles)
-     (connections)
+    ((ready)
+     (mouse)
+     (sp)
+     (p)
+     (earth)
+     (sun)
+     (emitter)
+     (ps)
+     (particle-pen (make-pen :stroke (gray 0.5) :fill (gray 0.8)))
+     (sp-pen (make-pen :stroke (gray 0.0) :fill (gray 0.0)))
+     (rope-pen (make-pen :stroke (gray 0.0)))
+     (sun-pen (make-pen :fill (rgb 1.0 1.0 0.0) :stroke (gray 0)))
+     (earth-pen (make-pen :fill (rgb 0.0 1.0 0.0) :stroke (gray 0)))
+     (p-pen (make-pen :fill (rgb 1.0 0.0 0.0)))
      )
   (with-fps
     (background (gray 1))
     ;;
+    (when ready
 
-    (draw-grid)
-    (with-pen (make-pen :stroke (gray 0.5) :fill (gray 0.9))
-      (circle (round-to-nearest (getf mouse :x) 40)
-              (round-to-nearest (getf mouse :y) 40)
-              10))
+      (particle-update! p)
+      (mapcar #'particle-update! ps)
+      (draw-particle sun sun-pen)
+      (draw-particle earth earth-pen)
+      (draw-particle emitter sp-pen)
+      (loop :for p :in ps :do (draw-particle p p-pen))
+
+      (draw-particle p particle-pen)
+      (with-pen rope-pen
+        (line (particle-x p) (particle-y p) (vec-x sp) (vec-y sp))
+        (line (particle-x p) (particle-y p) (vec-x mouse) (vec-y mouse)))
+      (with-pen sp-pen
+        (circle (vec-x sp) (vec-y sp) 3)
+        (circle (vec-x mouse) (vec-y mouse) 3))
+
+      )
 
     ;;
     ))
 
 (defun make-cm ()
   (make-sketch 'cm
-    (mouse (list :x 0 :y 0))
-    (k 0.01)
-    (separation 100)
-    ))
+    (mouse (make-vec))))
+
+
+(defun reset (game)
+  (setf (slot-value game 'ready) nil)
+  (setf (slot-value game 'sp)
+        (make-vec (random *width*)
+                  (random *height*))
+        (slot-value game 'p)
+        (make-particle (random *width*)
+                       (random *height*)
+                       :radius 10
+                       :friction (random-range 0.1 0.2)
+                       :gravity (random-range 0.1 0.5))
+        (slot-value game 'sun) (make-particle *center-x* *center-y*
+                                              :mass 500.0
+                                              :radius 20)
+        (slot-value game 'earth) (make-particle 320 80
+                                                :mass 100.0
+                                                :radius 8)
+        (slot-value game 'emitter) (make-particle 100 100 :radius 5)
+        (slot-value game 'ps) nil
+        )
+  (particle-spring-add! (slot-value game 'p)
+                        (slot-value game 'mouse)
+                        0.05
+                        80)
+  (particle-spring-add! (slot-value game 'p)
+                        (slot-value game 'sp)
+                        0.05
+                        80)
+  (loop :repeat 300
+        :for p = (make-particle 100 100
+                                :speed (random 3.0)
+                                :direction (random tau)
+                                :radius 3)
+        :do
+        (push p (slot-value game 'ps))
+        (particle-gravitate-add! p (slot-value game 'sun))
+        (particle-gravitate-add! p (slot-value game 'earth)))
+  (setf (slot-value game 'ready) t))
 
 
 ;;;; Mouse
 (defmethod kit.sdl2:mousemotion-event ((window cm) ts b x y xrel yrel)
   (declare (ignore ts b xrel yrel))
   (with-slots (mouse) window
-    (setf (getf mouse :x) x)
-    (setf (getf mouse :y) y)
+    (setf (vec-x mouse) x)
+    (setf (vec-y mouse) y)
     ;;
     ;;
     ))
@@ -65,8 +117,7 @@
 (defun keydown (instance scancode)
   (declare (ignorable instance))
   (scancode-case scancode
-    (:scancode-space
-     nil)))
+    (:scancode-space (reset instance))))
 
 (defun keyup (instance scancode)
   (declare (ignorable instance))
--- a/src/particles.lisp	Tue May 03 00:37:05 2016 +0000
+++ b/src/particles.lisp	Tue May 03 23:59:09 2016 +0000
@@ -7,7 +7,14 @@
   (grv (make-vec) :type vec)
   (radius 1 :type fixnum)
   (friction 0.0 :type single-float)
-  (mass 1.0 :type single-float))
+  (mass 1.0 :type single-float)
+  (springs nil :type list)
+  (gravitations nil :type list))
+
+(defstruct spring
+  (target (make-vec) :type vec)
+  (constant 0.0 :type single-float)
+  (offset 0.0 :type single-float))
 
 
 (defun make-particle
@@ -74,21 +81,18 @@
                           (particle-pos other-particle))))
 
 
-(defun particle-update! (particle)
-  (with-accessors
-      ((pos particle-pos)
-       (vel particle-vel)
-       (grv particle-grv)
-       (friction particle-friction))
-      particle
-    (vec-add! pos vel)
-    (vec-add! vel grv)
-    (vec-mul! vel (- 1 friction))))
-
 (defun particle-accelerate! (particle acceleration)
   (vec-add! (particle-vel particle)
             acceleration))
 
+
+(defun particle-gravitate-add! (particle target)
+  (push target (particle-gravitations particle)))
+
+(defun particle-gravitate-remove! (particle target)
+  (zap% (particle-gravitations particle)
+        #'remove target %))
+
 (defun particle-gravitate-to! (particle attractor-particle)
   (let ((distance (particle-distance-to particle attractor-particle)))
     (particle-accelerate!
@@ -98,6 +102,42 @@
                    (particle-angle-to particle attractor-particle)))))
 
 
+(defun particle-spring-to! (particle target spring-constant &optional (offset 0))
+  (let ((distance (vec-sub target (particle-pos particle))))
+    (decf (vec-magnitude distance) offset)
+    (vec-add! (particle-vel particle)
+              (vec-mul distance spring-constant))))
+
+(defun particle-spring-add! (particle target spring-constant &optional (offset 0))
+  (push (make-spring :target target
+                     :constant (float spring-constant)
+                     :offset (float offset))
+        (particle-springs particle)))
+
+(defun particle-spring-remove! (particle target)
+  (zap% (particle-springs particle)
+        #'remove target % :key #'spring-target))
+
+
+(defun particle-update! (particle)
+  (with-accessors
+      ((pos particle-pos)
+       (vel particle-vel)
+       (grv particle-grv)
+       (friction particle-friction))
+      particle
+    (vec-add! pos vel)
+    (vec-add! vel grv)
+    (vec-mul! vel (- 1 friction))
+    (loop :for g :in (particle-gravitations particle)
+          :do (particle-gravitate-to! particle g))
+    (loop :for s :in (particle-springs particle)
+          :do (particle-spring-to! particle
+                                   (spring-target s)
+                                   (spring-constant s)
+                                   (spring-offset s)))))
+
+
 (defmethod hitbox-x ((p particle))
   (particle-x p))