Added the possibility to add anchors to levels in the editor.
[uxul-world.git] / animation.lisp
1 ;;; Copyright 2009 Christoph Senjak
2
3 ;; Basic definitions for animations. Needs lispbuilder-sdl.
4
5 (in-package :uxul-world)
6
7 (defparameter *graphics-table* nil)
8
9 ;; the functions may assume that the contents of a graphics-file -
10 ;; once read - will not change at any time - so it wont reload
11 ;; graphics with an equivalent path any time you load an image.
12
13 (defclass animation (xy-coordinates)
14   ((images :initarg :images
15                      :initform (make-array (list 0) :element-type 'sdl:surface)
16                      :accessor images
17 ;                    :type (simple-array 'sdl:surface (*))
18                      :documentation "Array with the images")
19    (sprite-image-number :initform 0
20                         :initarg :sprite-image-number
21                         :accessor sprite-image-number
22 ;                       :type xy-struct
23                         :documentation "The Element-Number of the
24                        current image. This slot should not be set
25                        directly.")
26    (sprite-delay :initarg :sprite-delay
27                  :initform 0
28                  :accessor sprite-delay
29 ;                :type integer
30                  :documentation "How much frames to overjump on the
31 whole until changing to the next image of the animation.")
32    (already-jumped :initform 0
33                    :initarg :already-jumped
34                    :accessor already-jumped
35 ;                  :type integer
36                    :documentation "How much frames have been already
37    drawn until the last jump? If this equals to <sprite-delay>, the
38    next image is selected. Dont set this variable yourself." )
39    (visible :initarg :visible
40             :initform T
41             :accessor visible
42 ;           :type boolean
43             :documentation "Should this Animation be visible (i.e. be
44             drawn when the draw-method is called)? Anyway, the
45             draw-method will - even if set to false - \"animate\" the
46             animation, i.e. rotate the image currently drawn, if not
47             paused. It simply wont draw the graphics to the
48             screen.")
49    (reference-to-original :initarg :reference-to-original
50                           :accessor reference-to-original
51                           :initform nil
52                           :documentation "DO NOT SET THIS MANUALLY! DO
53 NOT USE IT! This may not stay in later versions of this Program. It
54 will be used to minimize the number of file-accesses for loading
55 animations. For any animation created from a file by the api from
56 below, this will refer to an animation in the *graphics-table*." )))
57
58 (defmethod draw ((obj animation))
59   (when (not (<= (sprite-delay obj) 0)) ;<=, because -a means "paused,
60                                         ;but a is the delay when
61                                         ;playing again", and 0 means
62                                         ;"no playing"
63     (incf (already-jumped obj))
64     (when (= (sprite-delay obj) (already-jumped obj))
65       (setf (already-jumped obj) 0)
66       (setf (sprite-image-number obj) (mod (+ 1 (sprite-image-number obj)) (length (images obj))))))
67   (when (visible obj)
68     (sdl:draw-surface-at-* (elt (images obj) (sprite-image-number obj))
69                            (+ *current-translation-x* (round (x obj)))
70                            (+ *current-translation-y* (round (y obj))))))
71
72 ;additional methods to make life easier
73 (defmethod pause ((obj animation))
74   "toggle the playing-flag (sgn sprite-delay), see documentation of draw-method."
75   (setf (sprite-delay obj) (- (sprite-delay obj))))
76
77 (defmethod is-paused ((obj animation))
78   "is animation paused?"
79   (< (sprite-delay obj) 0))
80
81 (defmethod is-playing ((obj animation))
82   "is animation playing?"
83   (< 0 (sprite-delay obj)))
84
85 (defmethod ensure-pause ((obj animation))
86   "ensures that the animation is paused if playing, otherwise, nothing is done."
87   (when (is-playing obj) (pause obj)))
88
89 (defmethod ensure-playing ((obj animation))
90   "ensures that the animation is playing if paused, otherwise, nothing is done."
91   (when (is-paused obj) (pause obj)))
92
93 (defmethod rewind ((obj animation))
94   "rewind the animation"
95   (setf (slot-value obj 'sprite-image-number) 0))
96
97 #|(defun load-png-image (filename)
98   (sdl-image:load-image (gethash filename *file-table*) :image-type :PNG :alpha 1 )) ;; :alpha t))
99
100 (defun hashed-load-image (filename)
101   "loads an image by its filename, if it wasnt loaded yet. returns a
102 reference, if the current filename already exists."
103   (let ((ret (gethash filename *graphics-table* nil)))
104     (cond
105       (ret ret)
106       (T
107        (setf ret (load-png-image filename))
108        (setf (gethash filename *graphics-table*) ret)
109        ret))))|#
110
111 (defun make-animation (frame-skip &rest image-list)
112   "Create an animation from the list of animation-names given in the
113 images-variable."
114   (make-instance 'animation
115                  :images (mapcar
116                           #'(lambda (x)
117                               (sdl:convert-surface :surface (sdl-image:load-image
118                                x
119                                :image-type :PNG :alpha 1 )))
120                                  image-list)
121                  :sprite-delay frame-skip))