Page 1 of 5

love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 8:38 am
by ivan
Love2D Scene Graph
This is a tiny (~10K) scene graph compatible with Love2D 11.3. This library is used to power all of the games behind 2dengine.com so the code is generalized and fairly well tested.

Features
- View or a "viewport" is a clipped rectangular area where the scene is rendered.
- Cameras allow you to pan, zoom and transform the view
- Sprites are nodes in the scene which can be translated, scaled or rotated. Each sprite is assigned a drawable graphic, usually an image, quad or text. Sprites can also be assigned a specific color, alpha value and blending mode
- Layers are basically groups of nodes, containing either sprites or other nested layers. Layers are helpful in ordering nodes along the Z-axis. Layers are used to build things like parallax, huds, minimaps and so on.

Repository and docs
https://github.com/2dengine/love.scene
https://2dengine.com/?p=scene

Example

Code: Select all

love.scene = require("scene")
local view = love.scene.newView()
local sprite = view:newSprite(0, 0)

local image = love.graphics.newImage("myimage.png")
sprite:setGraphic(image)

function love.draw()
  view:draw()
end

Re: love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 3:30 pm
by yetneverdone
Cool! I'm thinking if i could easily implement it for my game. Im in need of this for z-sorting feature.

Can you give an example or explanation on how to use the z ordering of layers based on sprite's y-position.

Re: love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 3:46 pm
by ivan
Thanks for taking a look yetneverdone!
It really depends on how you want to handle this.
Most of the time you want to use multiple layers:

Code: Select all

local background = view:newLayer(0, 0)
local middleground = view:newLayer(0, 0)
local foreground = view:newLayer(0, 0)

local bgsprite = background:newSprite(0, 0)
Note that sprites are sorted in the order they are created so:

Code: Select all

local under = view:newSprite(0, 0)
local above = view:newSprite(0, 0)
The easiest option is to create your sprites in the desired order.
In the rare event you want to change the depth dynamically you can use "setIndex":

Code: Select all

sprite:setIndex(1) --moves it to the bottom
or you can switch layers:

Code: Select all

sprite:setParent(foreground)
There is also a sorting function for layers.
This is useful for isometric games where the depth is affected by the Y position.

Code: Select all

layer:sort(function(a, b)
  -- return true if a is below b
end)
Thanks again for taking a look!

Re: love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 3:51 pm
by yetneverdone
Thank you!

How about integrating this with another camera lib?

Also i see that

Code: Select all

view:newSprite()
is a special case like

Code: Select all

love.graphics.newSprite()
?

Re: love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 4:09 pm
by ivan
I have never used any camera libs, so I'm not sure.
I should mention that the "view" object works very much like the viewport of a camera.
You can adjust the size and position of the viewport on the screen by setting its bounds:

Code: Select all

view:setBounds(vx, vy, vw, vh)
Typically you want to set this to the size of your game window.

You can change what is displayed inside the viewport using the "setScene" method:

Code: Select all

view:setScene(x, y, w, h) -- where w(idth) and h(eight) are optional
x and y is the scene origin which is the same as moving/panning the camera. The scene origin is typically the center of the viewport, and NOT the upper left corner!
w and h is the section of the scene (frustum) which is displayed inside the viewport.

Naturally, you can scale and rotate the view object too.

Re: love.scene (yet another scene graph library)

Posted: Tue Aug 25, 2020 4:13 pm
by ivan
The following two lines do the same thing:

Code: Select all

view:newSprite(0, 0)
love.scene.newSprite(view, 0, 0)
It's just a question of whatever syntax you prefer.

Re: love.scene (yet another scene graph library)

Posted: Thu Dec 31, 2020 3:00 am
by yetneverdone
Hi, taking a look at this library again as I am experiencing issue with my rendering system.

So is `view` the same as what camera provides?

So as I understand it, one `scene.sprite` can only have one `sprite/image`?

My project is ECS-based so the `images` in my game are passed as reference to a `sprite` component and then my `RenderSprite` system handles drawing them. So Im thinking that if I am going to integrate this library instead of my own, I would need my `RenderSprite` system to handle the creation of `layers` and then when `entities` are passed into the system, i would register the `images` to the `sprite` right? On the top of my head something like:

Code: Select all

local spr_player = love.graphics.newImage("sprite.png")
local spr_enemy = love.graphics.newImage("enemy.png")
local e_player = Entity():give("sprite", spr_player) --also other components
local e_enemy = Entity():give("sprite", spr_enemy) --also other components

--in RenderSprite
--in init
self.view = love.scene.newView()
self.layers = {
  background = self.view:newLayer(),
  main = self.view:newLayer(),
  foreground = self.view:newLayer()
}

--when entities are registered
self.layers.main:newSprite(e_player.sprite.sprite) --e_player is registered first
self.layer.main:newSprite(e_enemy.sprite.sprite) 

--in update
self.layers.main:sort(function(a, b)
  -- sort by entity's z-component, higher z should be behind lower z as z corresponds to the y-position in the screen.
end)

--in draw
self.layers.background:draw()
self.layers.main:draw()
self.layers.foreground:draw()

Re: love.scene (yet another scene graph library)

Posted: Thu Dec 31, 2020 4:00 pm
by ivan
yetneverdone wrote: Thu Dec 31, 2020 3:00 am So is `view` the same as what camera provides?
view is like the "viewport" of a camera. You can move it around and resize it using:

Code: Select all

view:setScene(x, y, w, h)
So as I understand it, one `scene.sprite` can only have one `sprite/image`?
You can assign ONE drawable object to each sprite. This could be an image, mesh, text, particlesystem, etc.
Assigning a drawable to a sprite is very similar to love.draw:

Code: Select all

love.graphics.draw(img, x, y, r, sx, sy, ox, oy)
sprite:setGraphic(img, x, y, r, sx, sy, ox, oy)
Your code looks fine, except for the last part.
We only "draw" the view object:

Code: Select all

view:draw()

Re: love.scene (yet another scene graph library)

Posted: Sat Jan 02, 2021 7:07 am
by yetneverdone
Ive started testing this lib and it's kinda tricky integrating this with an existing camera system.

Also, no `setScale` for view? Also can you elaborate more on the `setScene`? Thank you

Re: love.scene (yet another scene graph library)

Posted: Sat Jan 02, 2021 8:10 am
by ivan
yetneverdone wrote: Sat Jan 02, 2021 7:07 am Ive started testing this lib and it's kinda tricky integrating this with an existing camera system.
You don't need a separate camera system - the "view" object works as a camera.
yetneverdone wrote: Sat Jan 02, 2021 7:07 am Also, no `setScale` for view? Also can you elaborate more on the `setScene`? Thank you
setScene determines the visible range of the viewport. So if you write:

Code: Select all

view:setScene(0, 0, 800, 600)
The viewport will cover an area of 800 by 600 centered around 0, 0. This will change the scale of the viewport automatically.
If you want to set the scale by hand, then don't use the last two parameters:

Code: Select all

view:setScene(0, 0)
view:setScale(2, 2)
If you want to change the actual size of the viewport within the game window you can use "setDimensions" or "setBounds":

Code: Select all

view:setDimensions(200, 200)

Code: Select all

view:setBounds(0, 0, 200, 200)
Either one of these functions will create a rectangular viewport 200 by 200 pixels in the top-left corner of the game window (0, 0).