From 84ff75e4dad02f1362425d5208b4c57aa237eb39 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Tue, 28 Aug 2018 14:09:51 -0400 Subject: node-2d: Add tweened animations for position, rotation, and scale. --- starling/node-2d.scm | 140 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 49 deletions(-) diff --git a/starling/node-2d.scm b/starling/node-2d.scm index 368e8a2..ccbb17b 100644 --- a/starling/node-2d.scm +++ b/starling/node-2d.scm @@ -21,6 +21,7 @@ ;;; Code: (define-module (starling node-2d) + #:use-module (chickadee math easings) #:use-module (chickadee math matrix) #:use-module (chickadee math rect) #:use-module (chickadee math vector) @@ -59,13 +60,13 @@ rotation skew pivot - move + move-by move-to teleport - rotate + rotate-by rotate-to - zoom - zoom-to + scale-by + scale-to texture @@ -232,6 +233,25 @@ (define (dirty! node) (set! (dirty-matrix? node) #t)) +(define-method (compute-matrices! (node )) + (let ((local (local-matrix node)) + (world (world-matrix node))) + (matrix4-2d-transform! local + #:origin (origin node) + #:position (render-position node) + #:rotation (rotation node) + #:scale (scale node) + #:skew (skew node)) + ;; Compute world matrix by multiplying by the parent node's + ;; matrix, if there is a 2D parent node, that is. + (if (and (parent node) (is-a? (parent node) )) + (matrix4-mult! world local (world-matrix (parent node))) + (begin + (matrix4-identity! world) + (matrix4-mult! world world local))))) + +;; Animation helpers + (define-method (pivot (node ) x y) "Change origin of NODE to (X, Y)." (let ((o (origin node))) @@ -239,75 +259,97 @@ (set-vec2-y! o y) (dirty! node))) -(define-method (move (node ) dx dy) - "Move NODE by (DX, DY)." - (let ((p (position node))) - (set-vec2-x! p (+ (vec2-x p) dx)) - (set-vec2-y! p (+ (vec2-y p) dy)) - (dirty! node))) - (define-method (move-to (node ) x y) - "Move NODE to (X, Y)." (let ((p (position node))) (set-vec2-x! p x) (set-vec2-y! p y) (dirty! node))) +(define-method (move-to (node ) x y duration ease) + (let ((p (position node))) + (move-by node (- x (vec2-x p)) (- y (vec2-y p)) duration ease))) + +(define-method (move-to (node ) x y duration) + (move-to node x y duration smoothstep)) + +(define-method (move-by (node ) dx dy) + (let ((p (position node))) + (move-to node (+ (vec2-x p) dx) (+ (vec2-y p) dy)))) + +(define-method (move-by (node ) dx dy duration ease) + (let* ((p (position node)) + (start-x (vec2-x p)) + (start-y (vec2-y p))) + (tween duration 0.0 1.0 + (lambda (n) + (move-to node + (+ start-x (* dx n)) + (+ start-y (* dy n)))) + #:ease ease))) + +(define-method (move-by (node ) dx dy duration) + (move-by node dx dy duration smoothstep)) + (define-method (teleport (node ) x y) - "Move NODE to (X, Y) without applying animation smoothing." (move-to node x y) (let ((lp (last-position node))) (set-vec2-x! lp x) (set-vec2-y! lp y))) -(define-method (rotate (node ) dtheta) - "Rotate NODE about the Z axis by DTHETA radians." - (set! (rotation node) (+ (rotation node) dtheta)) - (dirty! node)) - (define-method (rotate-to (node ) theta) - "Rotate NODE to THETA radians about the Z axis." (set! (rotation node) theta) (dirty! node)) -(define-method (zoom (node ) dsx dsy) - "Scale NODE by the scaling factor (DSX, DSY)." - (let ((s (scale node))) - (set-vec2-x! s (+ (vec2-x s) dsx)) - (set-vec2-y! s (+ (vec2-y s) dsy)) - (dirty! node))) +(define-method (rotate-to (node ) theta duration ease) + (tween duration (rotation node) theta + (lambda (r) + (rotate-to node r)) + #:ease ease)) + +(define-method (rotate-to (node ) theta duration) + (rotate-to node theta duration smoothstep)) + +(define-method (rotate-by (node ) dtheta) + (rotate-to node (+ (rotation node) dtheta))) + +(define-method (rotate-by (node ) dtheta duration ease) + (rotate-to node (+ (rotation node) dtheta) duration ease)) -(define-method (zoom (node ) ds) - "Scale NODE by the scaling factor (DS, DS)." - (zoom node ds ds)) +(define-method (rotate-by (node ) dtheta duration) + (rotate-by node dtheta duration smoothstep)) -(define-method (zoom-to (node ) sx sy) - "Set the scaling factor for NODE to (SX, SY)." +(define-method (scale-to (node ) sx sy) (let ((s (scale node))) (set-vec2-x! s sx) (set-vec2-y! s sy) (dirty! node))) -(define-method (zoom-to (node ) s) - "Set the scaling factor for node to (S, S)." - (zoom-to node s s)) +(define-method (scale-to (node ) sx sy duration ease) + (let ((s (scale node))) + (scale-by node (- sx (vec2-x s)) (- sy (vec2-y s)) duration ease))) -(define-method (compute-matrices! (node )) - (let ((local (local-matrix node)) - (world (world-matrix node))) - (matrix4-2d-transform! local - #:origin (origin node) - #:position (render-position node) - #:rotation (rotation node) - #:scale (scale node) - #:skew (skew node)) - ;; Compute world matrix by multiplying by the parent node's - ;; matrix, if there is a 2D parent node, that is. - (if (and (parent node) (is-a? (parent node) )) - (matrix4-mult! world local (world-matrix (parent node))) - (begin - (matrix4-identity! world) - (matrix4-mult! world world local))))) +(define-method (scale-to (node ) sx sy duration) + (scale-to node sx sy duration smoothstep)) + +(define-method (scale-by (node ) dsx dsy) + (let ((s (scale node))) + (scale-to node (+ (vec2-x s) dsx) (+ (vec2-y s) dsy)))) + +(define-method (scale-by (node ) dsx dsy duration ease) + (let* ((s (scale node)) + (start-x (vec2-x s)) + (start-y (vec2-y s))) + (tween duration 0.0 1.0 + (lambda (n) + (scale-to node + (+ start-x (* dsx n)) + (+ start-y (* dsy n)))) + #:ease ease))) + +(define-method (scale-by (node ) dsx dsy duration) + (scale-by node dsx dsy duration smoothstep)) + +;; Events (define-method (update* (node ) dt) (vec2-copy! (position node) (last-position node)) -- cgit v1.2.3