aboutsummaryrefslogtreecommitdiff
path: root/animation.scm
blob: c8f4497976b0f9ab73afb7939554370d59d9088c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
(module downstroke-animation *
(import scheme
        (chicken base)
        (chicken keyword)
	(only srfi-1 filter)
        downstroke-entity
        downstroke-world)

;; ---- Animation data accessors ----

(define (animation-frames anim)
  (get-keyword #:frames anim))
(define (animation-duration anim)
  (get-keyword #:duration anim))

(define (frame-by-idx frames frame-idx)
  (list-ref frames (modulo frame-idx (length frames))))

;; The tile ID is 1-indexed.
(define (frame->tile-id frames frame-idx)
  (let ((frame-def (frame-by-idx frames frame-idx)))
    (if (list? frame-def)
	(car frame-def)
	frame-def)))

(define (frame->duration frames frame-idx)
  (let ((frame-def (frame-by-idx frames frame-idx)))
    (if (list? frame-def)
	(cadr frame-def)
	10)))

;; ---- set-animation ----
;; Switch to a new animation, resetting frame and tick counters.
;; No-op if the animation is already active (avoids restart mid-loop).

(define (set-animation entity name)
  (if (eq? (entity-ref entity #:anim-name #f) name)
      entity
      (entity-set (entity-set (entity-set entity #:anim-name name)
                              #:anim-frame 0)
                  #:anim-tick 0)))


(define (animation-by-name animations name)
  (let ((matching-anims (filter (lambda (anim) (eq? (get-keyword #:name anim) name)) animations)))
    (if matching-anims
	(car matching-anims)
	#f)))

;; ---- animate-entity ----
;; Advance the animation tick/frame counter for one game tick.
;; Pass the animation table for this entity's type.
;; Entities without #:anim-name are returned unchanged.

(define (advance-animation entity anim)
  (let* ((tick     (+ 1 (entity-ref entity #:anim-tick 0)))
         (duration (animation-duration anim))
         (frames   (animation-frames anim))
         (frame    (entity-ref entity #:anim-frame 0)))
    (if (>= tick duration)
        (let ((new-frame-id (modulo (+ frame 1) (length frames))))
          (entity-set-many entity
			   (list (cons #:anim-tick 0)
				 (cons #:anim-frame new-frame-id)
				 (cons #:tile-id (frame->tile-id frames new-frame-id))
				 (cons #:duration (frame->duration frames new-frame-id)))))
        (entity-set-many entity
			 (list (cons #:anim-tick tick)
			       (cons #:tile-id (frame->tile-id frames frame)))))))

(define (animate-entity entity animations)
  (let* ((anim-name (entity-ref entity #:anim-name #f))
         (anim      (and anim-name (animation-by-name animations anim-name))))
    (if anim
        (advance-animation entity anim)
        entity)))

(define-pipeline (apply-animation animation) (scene entity dt)
  guard: (entity-ref entity #:animations #f)
  (let ((animations (entity-ref entity #:animations #f)))
    (animate-entity entity animations)))

) ;; End of animation module