Starly

Starly is an orthographic camera library for Defold.

Its goal is to provide a feature-rich orthographic camera solution, confined to a single Lua module, where all properties can be edited or animated at runtime. By virtue of focusing solely on 2D, it’s able to implement much more creative and scenario-specific features that a more generalized library would be rightfully hesitant to attempt, due to added complexity and redundancy. In the future, I may add a Starly3D extension to the same repository that focuses solely on 3D.

Although many features are still in the works, here are some of the highlights:

  • All camera properties are able to be edited or animated at any time, with immediate updates.
  • Four viewport and projection behaviors, suitable to every type of game: center, expand, mixed, and stretch.
  • All camera logic and state management is handled in a single Lua module, which means your render script contains exactly 0 lines of camera library code.
  • The render script template contains convenience functions for organized predicate and target configuration, automatic predicate and target creation, automatic and custom target resize logic, etc. Despite these features, Starly makes no assumptions about whatever render script you decide to use, and does not require a single line of code to be included in your render script for the library to work.
  • Provides proven features you might see in successful games, such as starly.get_tight_world_area(), which matches how the camera in Super Smash Bros maintains visibility of all characters and follows their movements.

Note that Starly doesn’t provide a pre-written update() function in its render script template, should you choose to use it. You can learn more about that decision in the GitHub documentation.

Thanks for reading, and happy Defolding.

GitHub: https://github.com/VowSoftware/starly

21 Likes

Will be using this in future projects. A little suggestion to expose the margin size, would be great to know when objects are offscreen :slight_smile:

2 Likes

The margin size isn’t related to the visibility of an object.

There are two ways to achieve this:

  • Call m_starly.get_world_area(id), then check if your object’s position falls within those bounds.
  • Call m_starly.world_to_screen(id, world_position, [visible]) with visible set to true. This function will return screen coordinates if the object is visible, otherwise it will return nil.

The first method is less computationally expensive, since it only requires recalculating the viewport bounds. The second method recalculates the viewport, view, projection, and frustum. Therefore, I’d recommend using the first one.

I suppose there could be a separate m_starly.is_visible() function, however this would simply call m_starly.get_world_area() and check its bounds, which is a one-liner that throws away the opportunity to save the world area for further work.

2 Likes

Do you have a render script example for the gui? [sorry, solved this, so easily too!]

2 Likes

Great, good job. The solution should be to simply include the gui predicate in a draw call, while a camera is activated with the appropriate projection behavior.

Do you mind sharing your solution so others might benefit from it?

1 Like

Of course. Rendering GUI only needs one line in the demo’s camera.render_script

	-- Draw all sprites.
render.draw(g_predicates.tile.handle, { frustum = frustum })

	-- Draw the GUI
render.draw(g_predicates.gui.handle, { frustum = frustum })

-- Disable alpha blending.
render.disable_state(graphics.STATE_BLEND)
2 Likes