defun-games / claylib

A Common Lisp 2D/3D game toolkit built on top of Raylib 4.5.
zlib License
69 stars 4 forks source link

Implement "scene parameters" #40

Closed mjkalyan closed 1 year ago

mjkalyan commented 2 years ago

As mentioned in this thread: https://github.com/defun-games/claylib/pull/24#issuecomment-1201837681

Where scene parameters are things associated with a scene, are neither drawn nor loaded, but still may need to be freed according to the scene's freeing logic.

In the case of the thread above (model example 2), we would add the camera as a scene parameter so that the billboard object can be initialized with said camera without making it global or using manual special declarations.

Another case we might use scene parameters for is audio. We make an audio asset (music stream, sound, audio buffer), then, for example, an rl-music object as a parameter. The alternative is what I'm doing now: just make a music-asset, then let-bind its %asset to access the rl-music like so:

(let ((music (asset (gethash 'music (claylib::assets *scene*))))) 
  ...)

But it's rather ugly. Better would be something like (with-scene-params (cam music) *scene* ...).

Both situations imply a set up order for scenes of: assets -> parameters -> objects

shelvick commented 2 years ago

Both situations imply a set up order for scenes of: assets -> parameters -> objects

Okay, I'll see your music parameter and raise you with:

(make-scene
  ((asset-path "my-game/assets/level-1"))
  ((enemy-1 (make-enemy asset-path ...))))

In my mind the majority of parameters will end up being variables unrelated to Claylib assets or objects, and defining the parameters first is more intuitive. But clearly there is at least one case where different ordering makes sense. What's the simplest path to arbitrary ordering rather than enforcing specific categories in a specific order?

mjkalyan commented 2 years ago

Okay I've thought about it a bit. If we want an arbitrary load+bind order in make-scene, we need a way to pass arbitrary "groups" of things which could be anything (assets, objects, parameters, or anything else we may want to add to scenes later on) to make-scene.

So make-scene calls might look something like this:

;; (make-scene groups-plist ...) 
(make-scene (:assets                                   
             ((my-tex (make-texture-asset "aoeu.png")) 
              (song1-ass (make-music-asset ...)))      
             :parameters                               
             ((camera (make-camera-3d ...))            
              (song1 (make-music song1-ass)))          
             :objects                                  
             (bill (make-billboard my-tex camera ...)))
            :free :later)

Use (getf groups :objects) when creating futures for the objects. Then splice in the groups in order (so the order is controlled by the group order you give in make-scene):

`(let ((,scene ...))
   (let* ,(reduce #'append (loop for (_ group) on groups by #'cddr collect group))
     ...))

Lastly change the freeing functions to deal with parameters.

Thoughts?

shelvick commented 2 years ago

Yeah, your make-scene example is starting to look a lot like ASDF syntax. That's probably where we'll need to go in the end, though I propose just doing everything serially and not implementing dependency definitions.

With as complex as it's getting though, we might want two separate scene def functions. make-scene could be kept as is and then another function that's more customizable; make-scene-custom or make-scene-with-params or some better name.