A graphics library that simplifies drawing sprites on to the game screen.
This project is deprecated. This repo will be closed. You may still fork it for viewing and editing. The latest version is 1.1.3_dev.
This library depends on the latest version of FTL Hyperapce to function, please install the latest extension files that enables Lua.
Install FTL Hyperspace or found in the FTL-Multiverse Discord server.
- Utility functions for displaying all kinds of sprite images
- Support for playing whole animation sheets
- Highly customizable placements, sizes, time, and more
- Also allows drawing of shapes to accompany your sprites
This library was made to provide an abstraction over the raw exposed functions that Hyperspace offers, which is hard to read and lacks documentation. Because of the nature of the graphics functions, they must run on render events. Which often leads to hard-to-understand code. Therefore, this also provides modders with a consistent syntax for displaying sprite images.
Special thanks to vertaalfout#3043 for providing with the first versions of the functions that renders animations.
- Download the distribution build.
If you plan to use only part of the functionalities, downloadSimpleSprite.lua
plus whichever files you need. - Include the file in your mods'
<scripts>
section found insidehyperspace.xml
.
<scripts>
<script>data/SimpleGraphics_dist_min.lua</script>
<!-- make sure to place it above your other scripts -->
<script>data/my_amazing_script.lua</script>
</scripts>
- Inside a script file, initiate a sprite by calling
new()
, then assigning it to a local variable. In thenew
constructor, pass in a string representing the path to your image, relative to theimg
folder of your mod. Be sure that the image is in.png
format.
local SimpleSprite = mods.libs.SG.SimpleSprite -- get the class from the "mods" global table
local bacon = SimpleSprite:new("bacon") -- root/img/bacon.png
- In the same script file, add an event callback for any of the render events. The render events decides which layer your graphics will be drawn on. For example, the
LAYER_PLAYER
value draws at the player ships's layer.
Functions are first class objects in Lua, so other than creating them anonymously, they can also be defined elsewhere and passed toon_render_event
.
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function()
-- things here will happen BEFORE the selected layer renders.
-- so they will render below the objects drawn here
end,
function()
-- things here will happen AFTER the selected layer renders.
-- so they will render above the objects drawn here
end
)
- Pick when your sprite will be drawn. Then, inside the callback function, call
show()
on the sprite to make it appear. You can also pass various parameters, or modifiers, toshow()
as a table, in order to customize the sprite. A full list of allowed modifiers can be found in the documentations page.
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function() end,
function()
bacon:show({Xalign = 100, Yalign = 100})
end
)
-
Now patch your mod and run the game. Start a new game. If all goes well, the image will show up in the place a bit right and above the game window's center.
-
To make the sprite go away, call
hide()
on it. However,hide
will immediately hide your sprite, resulting in nothing showing up. To prevent this, callwait()
and pass in a number representing the amount of seconds to wait before the sprite hides itself.
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function() end,
function()
bacon:show({Xalign = 100, Yalign = 100})
bacon:wait(5)
bacon:hide()
end
)
-
Now try and run the game again. Sprite
bacon
should show up for 5 seconds, then hide itself. -
One thing to beware of, is that
wait
does not pause the execution of the function. Therefore, they do not work as they seem to be inside loops. This is also becauseon_render_event
callbacks runs many times per second, which means your loop is also ran many times.
Loops can be used to show an amount of sprites at once, or hide them at once, but never a mixture of these actions.
-- this will only show up for 1 second:
function()
for i=0, 10 do
bacon:show({Xalign = 100, Yalign = 100})
bacon:wait(1)
bacon:hide()
end
bacon:hide()
end
- As mentioned, the looping nature of
on_render_event
callbacks can be used in our favour. You can use local variables outside of the callback to keep track of things, then increment/decrement them inside the function, allowings interesting interactions.
For example, this will move the sprite to the top-right corner rapidly , then hide if it is out of sight.
local x = 0
local y = 0
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function() end,
function()
bacon:show({Xalign = x, Yalign = y})
x = x + 1
y = y + 1
if x > 680 and y > 360 then
bacon:hide()
end
end
)
- In most cases, you will not want the sprite to show up right when the game starts, and rather when a certain event runs. Sprites provide a property
state
for this purpose. You can do a conditional check inside the callback for this property.
It can also be toggled by calling thetoggleState()
method inside aon_game_event
callback.
Thestate
isoff
by default.
Note that the state does not effect the displaying of the sprite, it simply provides a mean to conditionally run the sprite's functions.
script.on_game_event("TEST_LUA", false, function()
bacon:toggleState()
end)
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function() end,
function()
if bacon:getState() == "off" then return end -- skips the rest if off
bacon:show({Xalign = 100, Yalign = 100})
bacon:wait(5)
bacon:hide()
end
)
- When a sprite has hidden, any subsequent
show
calls will not do anything. In the previous example, ifTEST_LUA
is ran again, nothing will display.
To make sprites reusable, callreset()
on the sprite. This needs to be done inside the state checking condition, otherwise it will reset the wait timer with every render.
Lastly, to make sure the event turns off the sprite after it is ran, add a named nested event as well as a callback registered onto it.
<event name="TEST_LUA_2">
<text>Something Happens</text>
<choice>
<text>Continue</text>
<event name="TEST_LUA_2_END">
<text>and something else</text>
<choice>
<text>Continue</text>
<event></event>
</choice>
</event>
</choice>
</event>
script.on_game_event("TEST_LUA_2", false, function()
bacon:toggleState()
end)
script.on_game_event("TEST_LUA_2_END", false, function()
bacon:toggleState()
end)
script.on_render_event(Defines.RenderEvents.LAYER_PLAYER,
function() end,
function()
if bacon:getState() == "off" then
bacon:reset() -- resets timer and flags to initial
return
end -- skips the rest if off
bacon:show({Xalign = 100, Yalign = 100})
bacon:wait(5)
bacon:hide()
end
)