diff --git a/defold-rive/commonsrc/rive_ddf.proto b/defold-rive/commonsrc/rive_ddf.proto index 99a7d3f..fd28c76 100644 --- a/defold-rive/commonsrc/rive_ddf.proto +++ b/defold-rive/commonsrc/rive_ddf.proto @@ -54,6 +54,14 @@ message RiveAnimationDone required uint32 playback = 2; // matches dmGameObject::Playback in gameobject.h } +message RiveEventTrigger +{ + required string name = 1; + optional float number = 2; + optional bool trigger = 3; + optional string text = 4; +} + // Function wrapper documented in gamesys_script.cpp message SetConstantRiveModel { diff --git a/defold-rive/src/comp_rive.cpp b/defold-rive/src/comp_rive.cpp index 4797f7f..30112f5 100644 --- a/defold-rive/src/comp_rive.cpp +++ b/defold-rive/src/comp_rive.cpp @@ -520,6 +520,38 @@ namespace dmRive } } + static void CompRiveEventTriggerCallback(RiveComponent& component, const char* name) + { + dmMessage::URL sender; + dmMessage::URL receiver = component.m_Listener; + + if (!GetSender(&component, &sender)) + { + dmLogError("Could not send event_trigger to listener because of incomplete component."); + return; + } + + dmRive::RiveSceneData* data = (dmRive::RiveSceneData*) component.m_Resource->m_Scene->m_Scene; + dmhash_t message_id = dmRiveDDF::RiveEventTrigger::m_DDFDescriptor->m_NameHash; + + dmRiveDDF::RiveEventTrigger message; + message.m_Name = name; + // message.m_Name = "foobar\0"; + // message.m_Trigger = 1; + // message.m_Number = 1234; + // message.m_Text = "Hello"; + + uintptr_t descriptor = (uintptr_t)dmRiveDDF::RiveEventTrigger::m_DDFDescriptor; + uint32_t data_size = sizeof(dmRiveDDF::RiveEventTrigger); + + dmMessage::Result result = dmMessage::Post(&sender, &receiver, message_id, 0, component.m_AnimationCallbackRef, descriptor, &message, data_size, 0); + dmMessage::ResetURL(&component.m_Listener); + if (result != dmMessage::RESULT_OK) + { + dmLogError("Could not send event_trigger to listener. %d", result); + } + } + dmGameObject::UpdateResult CompRiveUpdate(const dmGameObject::ComponentsUpdateParams& params, dmGameObject::ComponentsUpdateResult& update_result) { DM_PROFILE("RiveModel"); @@ -556,6 +588,15 @@ namespace dmRive if (component.m_StateMachineInstance) { component.m_StateMachineInstance->advanceAndApply(dt * component.m_AnimationPlaybackRate); + + size_t event_count = component.m_StateMachineInstance->reportedEventCount(); + for (size_t i = 0; i < event_count; i++) + { + rive::EventReport reported_event = component.m_StateMachineInstance->reportedEventAt(i); + dmLogInfo("reported event count %zu, %s", event_count, reported_event.event()->name().c_str()); + const char* name = reported_event.event()->name().c_str(); + CompRiveEventTriggerCallback(component, name); + } } else if (component.m_AnimationInstance) { @@ -840,8 +881,8 @@ namespace dmRive { bool result = PlayStateMachine(component, data, anim_id, ddf->m_PlaybackRate); if (result) { - //component->m_AnimationCallbackRef = params.m_Message->m_UserData2; - //component->m_Listener = params.m_Message->m_Sender; + component->m_AnimationCallbackRef = params.m_Message->m_UserData2; + component->m_Listener = params.m_Message->m_Sender; } else { dmLogError("Couldn't play state machine named '%s'", dmHashReverseSafe64(anim_id)); } diff --git a/defold-rive/src/script_rive.cpp b/defold-rive/src/script_rive.cpp index 855c493..bfcdc6b 100644 --- a/defold-rive/src/script_rive.cpp +++ b/defold-rive/src/script_rive.cpp @@ -141,16 +141,15 @@ namespace dmRive } } - // Not supported yet - // if (top > 3) // completed cb - // { - // if (lua_isfunction(L, 4)) - // { - // lua_pushvalue(L, 4); - // // NOTE: By convention m_FunctionRef is offset by LUA_NOREF, see message.h in dlib - // functionref = dmScript::RefInInstance(L) - LUA_NOREF; - // } - // } + if (top > 3) // completed cb + { + if (lua_isfunction(L, 4)) + { + lua_pushvalue(L, 4); + // NOTE: By convention m_FunctionRef is offset by LUA_NOREF, see message.h in dlib + functionref = dmScript::RefInInstance(L) - LUA_NOREF; + } + } dmRiveDDF::RivePlayAnimation msg; msg.m_AnimationId = anim_id; diff --git a/main/ac2/ac2.collection b/main/ac2/ac2.collection index 429147a..13f7938 100644 --- a/main/ac2/ac2.collection +++ b/main/ac2/ac2.collection @@ -22,16 +22,33 @@ instances { scale_along_z: 0 embedded_instances { id: "go" - data: "embedded_components {\n" - " id: \"rivemodel\"\n" + data: "components {\n" + " id: \"ac2\"\n" + " component: \"/main/ac2/ac2.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " property_decls {\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"model\"\n" " type: \"rivemodel\"\n" " data: \"scene: \\\"/main/ac2/ac2.rivescene\\\"\\n" "default_animation: \\\"\\\"\\n" "material: \\\"/defold-rive/assets/rivemodel.material\\\"\\n" "blend_mode: BLEND_MODE_ALPHA\\n" - "default_state_machine: \\\"Demo State Machine\\\"\\n" + "default_state_machine: \\\"State Machine 1\\\"\\n" "create_go_bones: false\\n" - "artboard: \\\"\\\"\\n" + "artboard: \\\"Demo\\\"\\n" "\"\n" " position {\n" " x: 0.0\n" @@ -47,8 +64,8 @@ embedded_instances { "}\n" "" position { - x: 959.0 - y: 546.0 + x: 960.0 + y: 540.0 z: 0.0 } rotation { diff --git a/main/ac2/ac2.script b/main/ac2/ac2.script new file mode 100644 index 0000000..3d340db --- /dev/null +++ b/main/ac2/ac2.script @@ -0,0 +1,16 @@ +function init(self) + msg.post(".", "acquire_input_focus") + self.scale = (sys.get_config_int("display.high_dpi") == 1) and 2 or 1 +end + +function on_input(self, action_id, action) + if not action_id or action_id == hash("touch") then + if action.pressed then + rive.pointer_down("#model", action.x * self.scale, action.y * self.scale) + elseif action.released then + rive.pointer_up("#model", action.x * self.scale, action.y * self.scale) + else + rive.pointer_move("#model", action.x * self.scale, action.y * self.scale) + end + end +end diff --git a/main/ghost/event.rivescene b/main/ghost/event.rivescene new file mode 100644 index 0000000..bbdcafc --- /dev/null +++ b/main/ghost/event.rivescene @@ -0,0 +1,2 @@ +scene: "/main/ghost/new_file.riv" +atlas: "/defold-rive/assets/empty.atlas" diff --git a/main/ghost/event.script b/main/ghost/event.script new file mode 100644 index 0000000..1f4afd2 --- /dev/null +++ b/main/ghost/event.script @@ -0,0 +1,56 @@ +function init(self) + --[[rive.play_anim("#rivemodel", "Timeline 1", go.PLAYBACK_ONCE_FORWARD, nil, function(self, message_id, message) + print("play_anim", message_id) + end)--]] + rive.play_state_machine("#rivemodel", "State Machine 1", nil, function(self, message_id, message) + print("play_state_machine", message_id) + end) + -- Add initialization code here + -- Learn more: https://defold.com/manuals/script/ + -- Remove this function if not needed +end + +function final(self) + -- Add finalization code here + -- Learn more: https://defold.com/manuals/script/ + -- Remove this function if not needed +end + +function update(self, dt) + -- Add update code here + -- Learn more: https://defold.com/manuals/script/ + -- Remove this function if not needed +end + +function fixed_update(self, dt) + -- This function is called if 'Fixed Update Frequency' is enabled in the Engine section of game.project + -- Can be coupled with fixed updates of the physics simulation if 'Use Fixed Timestep' is enabled in + -- Physics section of game.project + -- Add update code here + -- Learn more: https://defold.com/manuals/script/ + -- Remove this function if not needed +end + +function on_message(self, message_id, message, sender) + -- Add message-handling code here + -- Learn more: https://defold.com/manuals/message-passing/ + -- Remove this function if not needed +end + +function on_input(self, action_id, action) + -- Add input-handling code here. The game object this script is attached to + -- must have acquired input focus: + -- + -- msg.post(".", "acquire_input_focus") + -- + -- All mapped input bindings will be received. Mouse and touch input will + -- be received regardless of where on the screen it happened. + -- Learn more: https://defold.com/manuals/input/ + -- Remove this function if not needed +end + +function on_reload(self) + -- Add reload-handling code here + -- Learn more: https://defold.com/manuals/hot-reload/ + -- Remove this function if not needed +end diff --git a/main/ghost/ghost.collection b/main/ghost/ghost.collection new file mode 100644 index 0000000..7385a17 --- /dev/null +++ b/main/ghost/ghost.collection @@ -0,0 +1,142 @@ +name: "ghost" +instances { + id: "back" + prototype: "/main/menu/back.go" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"ghost\"\n" + " component: \"/main/ghost/ghost.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " property_decls {\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"ui\"\n" + " type: \"rivemodel\"\n" + " data: \"scene: \\\"/main/ghost/ghost.rivescene\\\"\\n" + "default_animation: \\\"Timeline 1\\\"\\n" + "material: \\\"/defold-rive/assets/rivemodel.material\\\"\\n" + "blend_mode: BLEND_MODE_ALPHA\\n" + "default_state_machine: \\\"State Machine 1\\\"\\n" + "create_go_bones: false\\n" + "artboard: \\\"New Artboard\\\"\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 957.0 + y: 529.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} +embedded_instances { + id: "go1" + data: "components {\n" + " id: \"event\"\n" + " component: \"/main/ghost/event.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " property_decls {\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"rivemodel\"\n" + " type: \"rivemodel\"\n" + " data: \"scene: \\\"/main/ghost/event.rivescene\\\"\\n" + "default_animation: \\\"\\\"\\n" + "material: \\\"/defold-rive/assets/rivemodel.material\\\"\\n" + "blend_mode: BLEND_MODE_ALPHA\\n" + "default_state_machine: \\\"State Machine 1\\\"\\n" + "create_go_bones: false\\n" + "artboard: \\\"New Artboard\\\"\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/main/ghost/ghost.rivescene b/main/ghost/ghost.rivescene new file mode 100644 index 0000000..5f4b029 --- /dev/null +++ b/main/ghost/ghost.rivescene @@ -0,0 +1,2 @@ +scene: "/main/ghost/recreation_game_v2.riv" +atlas: "/defold-rive/assets/empty.atlas" diff --git a/main/ghost/ghost.script b/main/ghost/ghost.script new file mode 100644 index 0000000..b1ff643 --- /dev/null +++ b/main/ghost/ghost.script @@ -0,0 +1,16 @@ +function init(self) + msg.post(".", "acquire_input_focus") + self.scale = (sys.get_config_int("display.high_dpi") == 1) and 2 or 1 +end + +function on_input(self, action_id, action) + if not action_id or action_id == hash("touch") then + if action.pressed then + rive.pointer_down("#ui", action.x * self.scale, action.y * self.scale) + elseif action.released then + rive.pointer_up("#ui", action.x * self.scale, action.y * self.scale) + else + rive.pointer_move("#ui", action.x * self.scale, action.y * self.scale) + end + end +end diff --git a/main/ghost/new_file.riv b/main/ghost/new_file.riv new file mode 100644 index 0000000..a40bdea Binary files /dev/null and b/main/ghost/new_file.riv differ diff --git a/main/ghost/recreation_game_v2.riv b/main/ghost/recreation_game_v2.riv new file mode 100644 index 0000000..584702c Binary files /dev/null and b/main/ghost/recreation_game_v2.riv differ diff --git a/main/loader.collection b/main/loader.collection index b176b06..4a10991 100644 --- a/main/loader.collection +++ b/main/loader.collection @@ -271,6 +271,24 @@ embedded_instances { " w: 1.0\n" " }\n" "}\n" + "embedded_components {\n" + " id: \"ghost\"\n" + " type: \"collectionproxy\"\n" + " data: \"collection: \\\"/main/ghost/ghost.collection\\\"\\n" + "exclude: false\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" "" position { x: 0.0 diff --git a/main/menu/menu.gui_script b/main/menu/menu.gui_script index 4f898fe..df12c14 100644 --- a/main/menu/menu.gui_script +++ b/main/menu/menu.gui_script @@ -11,9 +11,10 @@ local BUTTONS = { { id = "scifihud", text = "Sci-fi" }, --{ id = "circleui", text = "Circle UI" }, { id = "takethis", text = "Take This!" }, - { id = "ac2", text = "AC2" }, + { id = "ac2", text = "Assassin" }, { id = "grimley", text = "Grimley" }, { id = "fighting-game", text = "Fight!" }, + { id = "ghost", text = "Ghost UI" }, } local COLUMNS = 3 local WIDTH = 220