;;;; examples/06-sprite.lisp (defpackage #:ww.examples/6 (:use #:cl) (:export #:start)) (in-package #:ww.examples/6) (defclass sprite-example (ww::application) ()) (defclass dude (ww::sprite) ((walkingp :accessor walkingp :initform nil) (walking-speed :accessor walking-speed :initform 5))) (defun set-key-if-not (sprite key ) "Sets the frame kyey for sprite if that key is not already set. Also sets the frameset's RUNNINGP to T if it is not already." (unless (eql key (ww::frameset-key sprite)) (setf (ww::runningp (ww::current-frameset sprite)) nil) (setf (ww::frameset-key sprite) key)) (unless (ww::runningp (ww::current-frameset sprite)) (setf (ww::runningp (ww::current-frameset sprite)) t))) (define-symbol-macro +walking-speed+ 5) (ww::defhandler move-by-face (ww::on-perframe (sprite) "When the sprite is walking, adjust its position." (with-slots (walkingp walking-speed) sprite (when walkingp (case (ww::frameset-key sprite) (:left (decf (ww::x sprite) walking-speed)) (:right (incf (ww::x sprite) walking-speed)) (:back (incf (ww::y sprite) walking-speed)) (:front (decf (ww::y sprite) walking-speed))))))) (ww::defhandler move-dude (ww::on-keydown (sprite scancode) "Set sprite to walking and set the frameset appropriate to its direction." (case scancode (:scancode-left (set-key-if-not sprite :left) (setf (walkingp sprite) t)) (:scancode-right (set-key-if-not sprite :right) (setf (walkingp sprite) t)) (:scancode-up (set-key-if-not sprite :back) (setf (walkingp sprite) t)) (:scancode-down (set-key-if-not sprite :front) (setf (walkingp sprite) t))))) (ww::defhandler speed-control (ww::on-keydown (sprite scancode) "A second keydown handler, for controlling walking speed. " (case scancode (:scancode-u (incf (walking-speed sprite))) (:scancode-d (decf (walking-speed sprite)))))) (ww::defhandler stand (ww::on-keyup (target) "Stop the sprite from walking, and stop its current frameset from animating, setting its frame to the standing position." (setf (walkingp target) nil) (let ((current (ww::current-frameset target))) (setf (ww::runningp current) nil (ww::frameset-index current) 0)))) (defmethod ww::boot ((app sprite-example)) (let* ((front (ww::make-frameset '("dude/Front_Stand.png" ; this is the order in which frames will render "dude/Front_Left.png" "dude/Front_Stand.png" ; reusing assets does not add them twice "dude/Front_Right.png") :fps 3)) (back (ww::make-frameset '("dude/Back_Stand.png" "dude/Back_Left.png" "dude/Back_Stand.png" "dude/Back_Right.png") :fps 3)) (left (ww::make-frameset '("dude/Left_Stand.png" "dude/Left_Left.png" "dude/Left_Stand.png" "dude/Left_Right.png") :fps 3)) (right (ww::make-frameset '("dude/Right_Stand.png" "dude/Right_Left.png" "dude/Right_Stand.png" "dude/Right_Right.png") :fps 3)) (dude (make-instance 'dude :framesets (list :front front ; a sprite has many framesets :back back ; and are kept in a plist :left left :right right) :frameset-key :front))) ; initial frameset to use (setf (ww::runningp (ww::current-frameset dude)) nil) (ww::add-handler dude #'move-by-face ) (ww::add-handler dude #'move-dude) (ww::add-handler dude #'stand) (ww::add-handler dude #'speed-control) (ww::refocus-on dude) (ww::add-unit app dude))) (defun start () (ww::start (make-instance 'sprite-example :fps 60 :width 800 :height 600 :title "Wheelwork Example: An Animated Sprite" :asset-root (merge-pathnames "examples/" (asdf:system-source-directory :wheelwork)))))