Rive is a real-time interactive design and animation tool by Rive Inc.. Use the Rive editor to create vector based motion graphics that respond to different states and user inputs. Rive lets you create advanced timeline animations through animation mixing, interpolation and inverse-kinematics. Transition between animations usingState Machines.
In order to use Rive content, you will need to run Defold 1.9.5 or higher.
Rive animation support in Defold is provided through an official Rive extension. To use Rive animations in a Defold project, add the following URL to the list ofgame.project
dependencies:
https://github.com/defold/extension-rive/archive/main.zip
We recommend using a link to a zip file of aspecific release.
To use Rive on Windows, you need to make sure OpenGL 4.2 or later is used in the engine. To do this, set theOpenGL version hint
to either 4.2 orUse highest available
:
The Rive extension is using a native renderer from theRive runtimehttps://github.com/rive-app/rive-runtime itself by issuing raw graphics API calls behind the scenes.The low-level renderer doesn’t rasterize rive paths using regular triangles - instead a complex series of draw commands are issued that will produce smooth vector graphics.With this in mind, there are a few caveats for how the renderer works together with the regular Defold rendering.
The extension exposes two different coordinate systems that can be used to position the Rive content on screen:
Fit
andAlignment
modes on the Rive model component.When using theRive
coordinate system, theFit
andAlignment
settings affect how the Rive content is rendered.
TheFit
parameter determines how the Rive content will be fitted to the view. There are a number of options available:
TheAlignment
parameter determines how the content aligns with respect to the view bounds. The following options are available:
Center (Default)TopLeftTopCenterTopRightCenterLeftCenterRightBottomLeftBottomCenterBottomRight
The Rive API does not have an exposed projection matrix that can be set, which means that in order to match the Rive coordinate space, a fullscreen projection is used in the render script.To help with mixing Defold and Rive cxontent, the extension provides the helper functionrive.get_projection_matrix()
that can be used as the projection matrix in the render script:
render.set_projection_matrix(rive.get_projection_matrix())render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())-- The rive component and sprite components will now be in the same coordinate system,-- as long as the coordinate system for Rive model used in the scene is set to "fullscreen"!render.draw(self.rive_pred)render.draw(self.sprite_pred)
If you want to mix Defold and Rive content, you will need to set theCoordinate system
field on the Rive component to “Fullscreen” in order to be able to place components in the same space.
For convenience, there is a modified render script included with the projection matrix extension. Open yourgame.project file and modify theRender
field in theBootstrap
section to use thedefold-rive/lua/rive.render
file from this extension.
View matrices are supported, but only in 2D space since Rive content is essentially orthographic by design.For example, using the view matrix from a camera component can be used to implement camera effects, such as screen shakes or as a regular game camera in 2D.
Note! Support for using a view matrix / camera component to display Rive content is currently considered a work-in-progress and might not work as expected yet.
If you want to use a view matrix in 3D space, you will need to set theCoordinate system
field on the Rive component to “Rive” in order to be able to place components in the same space.
Blending is currently only supported from within the .riv files themselves. Changing the blend mode on the component or the render script will have no effect.
Create a Rive scene by (right click a location in theAssets browser, then selectNew... ▸ Rive Scene from the context menu). Select the Rive data file to use from the Rive File field in theProperties panel.
Once a Rive file has been selected a preview will be shown in the mainEditor scene view and the bone hierarchy (see below) will be shown in theOutline panel.
If your Rive scene contains multipleArtboards the Rive integration in Defold will automatically select the Main Artboard from your Rive scene.
Select a game object to hold the new component:
Either create the component in-place (right click the game object and selectAdd Component ▸ Rive Model)
Or create it on file first (right click a location in theAssets browser, then selectNew... ▸ Rive Model from the context menu), then add the file to the game object byright clicking the game object and selectingAdd Component File).
The Rive model can now be viewed in the editor:
Apart from the propertiesId,Position andRotation the following component specific properties exist:
Rive Model components can be manipulated at runtime through a number of different functions and properties (refer to theAPI docs for usage).
To play animations on aRive Model component, simply call therive.play_anim()
function:
functioninit(self)-- Play the "run" animation on the component "rivemodel"localoptions={offset=0.2,-- start 20% into the animationplayback_rate=1.5,-- play the animation at 150% speed}rive.play_anim("#rivemodel","run",go.PLAYBACK_ONCE_FORWARD,options,function(self,message_id,message,sender)run()end)end
In addition to using therive.play_anim()
to advance a Rive animation,Rive Model components expose a “cursor” property that can be manipulated withgo.animate()
(more aboutproperty animations):
-- Set the animation on the spine model but don't run it.rive.play_anim("#rivemodel","run",go.PLAYBACK_NONE)-- Set the cursor to position 0go.set("#rivemodel","cursor",0)-- Tween the cursor slowly between 0 and 1 pingpong with in-out quad easing.go.animate("#rivemodel","cursor",go.PLAYBACK_LOOP_PINGPONG,1,go.EASING_INOUTQUAD,6)
ARive Model component also has a number of different properties that can be manipulated usinggo.get()
andgo.set()
:
animation
hash
) (READ ONLY). You change animation usingrive.play_anim()
.cursor
number
).material
hash
). You can change this using a material resource property andgo.set()
. Refer to theAPI reference for an example.playback_rate
number
).Inputs are used to control the transitions in a State Machine by assigning them as conditions in the Rive editor. At runtime it is possible to tie into these inputs from your game logic. In order to modify the inputs the State Machine needs to be started usingrive.play_state_machine()
. Once it has been started it can be interacted with usinggo.set()
:
-- Start the State Machine named "State Machine 1"rive.play_state_machine("#rivemodel","State Machine 1")-- Set the boolean value "Trigger 1" to truego.set("#rivemodel","Trigger 1",true)-- Set the numeric value "Number 1" to 0.8go.set("#rivemodel","Number 1",0.8)-- Read the input value of the current State Machinelocalv=rive.get_state_machine_input("#rivemodel","Number 1")-- Read the input value of a nested artboard from the current State Machinelocalv=rive.get_state_machine_input("#rivemodel","Number 1","My_Nested_Artboard")-- To go deeper into the nested hierarchy, you can add slashes between each scopelocalv=rive.get_state_machine_input("#rivemodel","Number 1","My_Nested_Artboard/My_Inner_Nested_Artboard")-- Set the input value of the current State Machinerive.set_state_machine_input("#rivemodel","Number 1",0.5)-- Set the input value of a nested artboardrive.set_state_machine_input("#rivemodel","Number 1",0.5,"My_Nested_Artboard")-- Same as the example above, to go even deeper, separate the scopers with slashes!rive.set_state_machine_input("#rivemodel","Number 1",0.5,"My_Nested_Artboard/My_Inner_Nested_Artboard")
Listeners can be used to define click, hover, and mouse move actions that can change State Machine Inputs at runtime. You can forward mouse and touch actions to a State Machine in aRive Model component like this:
functionon_input(self,action_id,action)ifnotaction_idoraction_id==hash("touch")thenifaction.pressedthenrive.pointer_down("#rivemodel",action.x,action.y)elseifaction.releasedthenrive.pointer_up("#rivemodel",action.x,action.y)elserive.pointer_move("#rivemodel",action.x,action.y)endendend
Events that trigger while a State Machine is playing are sent to the callback function provided when callingrive.play_state_machine(url, state_machine_id, options, callback
):
localfunctionrive_event_handler(self,message_id,message)print("received event",message.name)pprint(message)endfunctioninit(self)rive.play_state_machine("#rivemodel","State Machine 1",nil,rive_event_handler)end
If no callback is provided the events will be sent to the calling script asrive_event_trigger
messages:
functioninit(self)rive.play_state_machine("#rivemodel","State Machine 1")endfunctionon_message(self,message_id,message,sender)ifmessage_id==hash("rive_event_triggered")thenprint("received event",message.name)pprint(message)endend
The individual bones in theRive Scene skeleton are represented internally as game objects. In theOutline view of theRive Scene the full hierarchy is visible.
With the bone name at hand, it is possible to retrieve the instance id of the bone in runtime. The functionrive.get_go()
returns the id of the specified bone and it is, for instance, possible to child other game objects under the animated game object:
-- Attach pistol game object to the left forearmlocalforearm=rive.get_go("#rivemodel","Left forearm")msg.post("pistol","set_parent",{parent_id=forearm})
To set and getText Runs, you can use the following functions:
localtext=rive.get_text_run("#rivemodel","my_text_run")-- change the text to something elserive.set_text_run("#rivemodel","my_text_run","Hello, World!")-- you can also access text runs in nested artboards by passing in the artboard name:rive.get_text_run("#rivemodel","my_text_run","my_nested_artboard")-- accessing nested artboards within nested artboards is also possiblerive.get_text_run("#rivemodel","my_text_run","my_nested_artboard/my_other_nested_artboard")-- the same works with set_text_run:rive.set_text_run("#rivemodel","my_text_run","Hello, World!","my_nested_artboard")
Note! You need to export all the names from within Rive to use these functions:
The source code is available onGitHub
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB