lordmauve / wasabi2d

Cutting-edge 2D game framework for Python
https://wasabi2d.readthedocs.io/
GNU Lesser General Public License v3.0
156 stars 24 forks source link

Add ability to include camera-independent elements [feature] #22

Open dmoisset opened 4 years ago

dmoisset commented 4 years ago

The camera attribute in the scene is really useful, especially for any kind of scrolling games. When working on my pyweek entry I found that it was really hard to use when I also want some kind of "HUD" that doesn't scroll (a time counter, a hit points meter, a sidebar with help....).

My way to deal with it was implemented here: https://github.com/dmoisset/pyweek28/blob/c1ee5b49bfb5f51c9b5bb539d043f5bd8c21e961/src/hudscene.py ; I defined my own HUDScene where I extend wasabi's Scene with a separate camera and layergroup for the HUD, (lines 10-11), which are rendered on the drawmethod (line 20.... the rest was copied paste from wasabi, you can ignore it). I would have loved to have this within wasabi2d (other uses like parallax scrolling could benefit from something like this)

The approach worked fine for me (and makes layers in the HUD always above any layer in the other group). I've been thinking that this could be design in a different way (for example, adding an optional camera to a layer that overrides the one in the scene, or making easier for the user to define layer groups, each one with its own camera).

I'm happy to submit a PR with my code, or with any of the approaches above, I'm not sure what design you prefer for this.

lordmauve commented 4 years ago

I think that's actually issue #4. I would love a PR. I have thought about how to do more clever things with cameras (and multiple cameras) but I haven't come up with anything that's a good blend of powerful and general but also obvious for the simple cases.

dmoisset commented 4 years ago

You're right, it's the same issue....

One option I can envision is having the camera attached to the LayerGroup instead of the Scene (actually the layer group has a camera attribute already, although it's not used in rendering).

With that done, some Scene API to create and attach layer groups with a given z-index should be easy to add. Scene.layers can still be an alias to a single default LayerGroup that's created on startup, so that wouldn't change the "simple" use case, do you think that would work?

I imagine using this as:

s = Scene()
hud = s.add_layer_group(z_index = 1) # Creates a hud in front of s.layers, which has z-index==0
s.layers[42].add_sprite(....)  # This is the normal wasabi usage
hud[2].add_text(...)  # This is above the sprite, and doesn't move with the camera
s.layers.camera.pos = ...  # This moves the sprite, but the text stays still

I'm guessing the last step would be to have some sort of ParallaxCamera object that can be tied to another camera, and moves proportionally.

lordmauve commented 4 years ago

I think maybe the layers system needs to change totally anyway. I put some thoughts here but I'm now thinking of shaders that act on multiple layers - eg. "mask" operation.

And in PyWeek 28 Larry ended up defining an enum for layer indices to make draw order more manageable in a bigger game, and I think that points to the current design being wrong.

I quite like