;;;; wh-engine/scene.lisp (in-package wh-engine) (defclass scene () ((id :documentation "This scene's unique ID." :reader id :type fixnum :initarg :id :initform 0) (name :documentation "This scene's human-readable name." :accessor name :type string :initarg :name :initform "") (actors :documentation "A list containing all actors in the scene." :reader actors :type (proper-list actor) :initform nil) (destroyed-p :documentation "If true, this scene will be unloaded." :reader destroyed-p :type boolean :initform nil)) (:documentation "A scene containing game entities.")) (defmethod make-load-form ((this scene) &optional environment) ;(make-load-form-saving-slots this :environment environment) (make-generic-load-form this :environment environment)) (defmethod print-object ((this scene) stream) (print-unreadable-object (this stream :type t :identity t) (prin1 [this :slot id] stream) (princ " ") (prin1 [this :slot name] stream))) (defmethod add-actor ((this scene) actor) "Add an actor to this scene." (when [actor scene] (error "~S is already in scene ~S" actor [actor scene])) (push actor [this :slot actors]) (setf [actor :slot scene] (make-weak-pointer this)) actor) (defmethod remove-actor ((this scene) actor) "Remove an actor from this scene." (unless (eq [actor scene] this) (error "~S is not in scene ~S" actor this)) (setf [this :slot actors] (delete actor [this :slot actors] :count 1)) (setf [actor :slot scene] nil) actor) (defmethod get-actor ((this scene) actor-id) "Get the actor with the specified ID in this scene." (find-if (lambda (actor) (eq [actor id] actor-id)) [this actors])) (defmethod get-tagged-actors ((this scene) tags) "Get all actors tagged with the given set of tags." (loop for actor in [this actors] if (subsetp tags [actor tags]) collect actor)) (defmethod update ((this scene)) "Update all actors in this scene." (loop for actor in [this actors] unless (or [actor destroyed-p] (not [actor tree-active-p])) do [actor (update)])) (defmethod destroy ((this scene)) "Mark this scene for unloading." (unless [this destroyed-p] ; We're dead, clean up actors (loop for actor in [this actors] do [actor (destroy)]) (remove-scene this)) (setf [this :slot destroyed-p] t)) (defmethod resume ((this scene)) "Initialize or restore this scene's state." ; Restore actors (loop for actor in [this actors] do [actor (resume)])) (defmethod suspend ((this scene)) "Prepare this scene for serialization." ; Suspend actors (loop for actor in [this actors] do [actor (suspend)]))