Skip to content

Commit

Permalink
Implemented StateMachine touch events and a Magic 8 Ball example to d…
Browse files Browse the repository at this point in the history
…emonstrate them. Removed old RArtboardDelegate now that the touch events are handled by the StateMachine.
  • Loading branch information
duncandoit authored and mikerreed committed Apr 29, 2022
1 parent f7b8da9 commit 9d9d1b9
Show file tree
Hide file tree
Showing 36 changed files with 297 additions and 113 deletions.
Binary file added Example-iOS/Assets/leg_day_events_example.riv
Binary file not shown.
Binary file added Example-iOS/Assets/magic_8-ball_v2.riv
Binary file not shown.
Binary file added Example-iOS/Assets/play_button_event_example.riv
Binary file not shown.
Binary file added Example-iOS/Assets/switch_event_example.riv
Binary file not shown.
Binary file added Example-iOS/Assets/watch_v1.riv
Binary file not shown.
50 changes: 43 additions & 7 deletions Example-iOS/RiveExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
C3D187F3280751A8008B739A /* RiveProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D187F2280751A8008B739A /* RiveProgressBar.swift */; };
C3D187F728075B6C008B739A /* riveslider.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3D187F628075B6C008B739A /* riveslider.riv */; };
C3D187F9280770EA008B739A /* truck.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3D187F8280770EA008B739A /* truck.riv */; };
C3ECAC252817BE1100A81123 /* magic_8-ball_v2.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3ECAC222817BE1100A81123 /* magic_8-ball_v2.riv */; };
C3ECAC272817BE4600A81123 /* SwiftTouchEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECAC262817BE4600A81123 /* SwiftTouchEvents.swift */; };
C3ECAC2B281837B300A81123 /* play_button_event_example.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3ECAC28281837B300A81123 /* play_button_event_example.riv */; };
C3ECAC2C281837B300A81123 /* leg_day_events_example.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3ECAC29281837B300A81123 /* leg_day_events_example.riv */; };
C3ECAC2D281837B300A81123 /* switch_event_example.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3ECAC2A281837B300A81123 /* switch_event_example.riv */; };
C3ECAC2F281840A300A81123 /* ClockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECAC2E281840A300A81123 /* ClockViewModel.swift */; };
C3ECAC31281840EF00A81123 /* watch_v1.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3ECAC30281840EF00A81123 /* watch_v1.riv */; };
C9BD3926263B5FC700696C37 /* truck_v7.riv in Resources */ = {isa = PBXBuildFile; fileRef = C9BD3925263B5FC700696C37 /* truck_v7.riv */; };
C9C73E9824FC471E00EF9516 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C73E9724FC471E00EF9516 /* AppDelegate.swift */; };
C9C73E9A24FC471E00EF9516 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C73E9924FC471E00EF9516 /* SceneDelegate.swift */; };
Expand Down Expand Up @@ -147,6 +154,13 @@
C3D187F2280751A8008B739A /* RiveProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiveProgressBar.swift; sourceTree = "<group>"; };
C3D187F628075B6C008B739A /* riveslider.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = riveslider.riv; sourceTree = "<group>"; };
C3D187F8280770EA008B739A /* truck.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = truck.riv; sourceTree = "<group>"; };
C3ECAC222817BE1100A81123 /* magic_8-ball_v2.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = "magic_8-ball_v2.riv"; sourceTree = "<group>"; };
C3ECAC262817BE4600A81123 /* SwiftTouchEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTouchEvents.swift; sourceTree = "<group>"; };
C3ECAC28281837B300A81123 /* play_button_event_example.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = play_button_event_example.riv; sourceTree = "<group>"; };
C3ECAC29281837B300A81123 /* leg_day_events_example.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = leg_day_events_example.riv; sourceTree = "<group>"; };
C3ECAC2A281837B300A81123 /* switch_event_example.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = switch_event_example.riv; sourceTree = "<group>"; };
C3ECAC2E281840A300A81123 /* ClockViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClockViewModel.swift; sourceTree = "<group>"; };
C3ECAC30281840EF00A81123 /* watch_v1.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = watch_v1.riv; sourceTree = "<group>"; };
C9BD3925263B5FC700696C37 /* truck_v7.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = truck_v7.riv; sourceTree = "<group>"; };
C9C73E9424FC471E00EF9516 /* RiveExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RiveExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
C9C73E9724FC471E00EF9516 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -176,7 +190,7 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
042C88862643DB2200E7DBB2 /* UIkit */ = {
042C88862643DB2200E7DBB2 /* Storyboard */ = {
isa = PBXGroup;
children = (
042C88872643DB7100E7DBB2 /* SimpleAnimation.swift */,
Expand All @@ -186,7 +200,7 @@
046AFA722673B00B004ED497 /* BlendModes.swift */,
04C4C83D2646FE410047E614 /* StateMachine.swift */,
);
path = UIkit;
path = Storyboard;
sourceTree = "<group>";
};
04A8F6B826452E10002C909A /* Products */ = {
Expand All @@ -206,20 +220,36 @@
path = lib;
sourceTree = "<group>";
};
C324DB592807202A0060589F /* Widgets */ = {
C3ECAC322818608B00A81123 /* Examples */ = {
isa = PBXGroup;
children = (
C3ECAC33281860E900A81123 /* ViewModel */,
042C88862643DB2200E7DBB2 /* Storyboard */,
C9A84F342644931E0014D8E0 /* SwiftUI */,
);
path = Examples;
sourceTree = "<group>";
};
C3ECAC33281860E900A81123 /* ViewModel */ = {
isa = PBXGroup;
children = (
C324DB5C280728690060589F /* RiveButton.swift */,
C324DB5528071EB80060589F /* RiveSwitch.swift */,
C324DB5A2807216B0060589F /* RiveSlider.swift */,
C3D187F2280751A8008B739A /* RiveProgressBar.swift */,
C3ECAC2E281840A300A81123 /* ClockViewModel.swift */,
);
path = Widgets;
path = ViewModel;
sourceTree = "<group>";
};
C9696B0E24FC6FD10041502A /* Assets */ = {
isa = PBXGroup;
children = (
C3ECAC30281840EF00A81123 /* watch_v1.riv */,
C3ECAC29281837B300A81123 /* leg_day_events_example.riv */,
C3ECAC28281837B300A81123 /* play_button_event_example.riv */,
C3ECAC2A281837B300A81123 /* switch_event_example.riv */,
C3ECAC222817BE1100A81123 /* magic_8-ball_v2.riv */,
C3D187F628075B6C008B739A /* riveslider.riv */,
C324DB5E280740FB0060589F /* rbutton.riv */,
C34609FD2800A6CE002DBCB7 /* bird.riv */,
Expand Down Expand Up @@ -268,6 +298,7 @@
04026DCB27CE3F03002B3DBF /* SwiftLoopMode.swift */,
04026DCD27CE3F0F002B3DBF /* SwiftStateMachine.swift */,
E5CD7D7027DC331900BFE5E2 /* SwiftMeshAnimation.swift */,
C3ECAC262817BE4600A81123 /* SwiftTouchEvents.swift */,
);
path = SwiftUI;
sourceTree = "<group>";
Expand Down Expand Up @@ -295,9 +326,7 @@
children = (
042C88822643D6B900E7DBB2 /* Main.storyboard */,
C3357CA0280F42EC00F03B6F /* ExamplesMaster.swift */,
C324DB592807202A0060589F /* Widgets */,
C9A84F342644931E0014D8E0 /* SwiftUI */,
042C88862643DB2200E7DBB2 /* UIkit */,
C3ECAC322818608B00A81123 /* Examples */,
C9C73E9D24FC471E00EF9516 /* Assets.xcassets */,
C9C73E9F24FC471E00EF9516 /* Preview Content */,
04A8F6C226452F25002C909A /* lib */,
Expand Down Expand Up @@ -414,9 +443,11 @@
042C88DC2644447500E7DBB2 /* pull.riv in Resources */,
042C88E32644447500E7DBB2 /* flux_capacitor.riv in Resources */,
C9CE8266263B90E000F98DDB /* juice_v7.riv in Resources */,
C3ECAC2B281837B300A81123 /* play_button_event_example.riv in Resources */,
042C88E42644447500E7DBB2 /* neostream.riv in Resources */,
042C88E82644447500E7DBB2 /* loopy.riv in Resources */,
042C88E02644447500E7DBB2 /* progress.riv in Resources */,
C3ECAC252817BE1100A81123 /* magic_8-ball_v2.riv in Resources */,
04D5B06C266A460C004ACA5B /* nothing.riv in Resources */,
042C88E92644447500E7DBB2 /* off_road_car_blog.riv in Resources */,
042C88832643D6B900E7DBB2 /* Main.storyboard in Resources */,
Expand All @@ -425,8 +456,11 @@
042C88E62644447500E7DBB2 /* artboard_animations.riv in Resources */,
042C88E72644447500E7DBB2 /* trailblaze.riv in Resources */,
C3D187F728075B6C008B739A /* riveslider.riv in Resources */,
C3ECAC2C281837B300A81123 /* leg_day_events_example.riv in Resources */,
C3ECAC31281840EF00A81123 /* watch_v1.riv in Resources */,
042C88E12644447500E7DBB2 /* basketball.riv in Resources */,
042C88DE2644447500E7DBB2 /* rope.riv in Resources */,
C3ECAC2D281837B300A81123 /* switch_event_example.riv in Resources */,
0480028B2729AA4400F7132B /* clean_icon_set.riv in Resources */,
04F1C80B26A8442300CEE6BE /* two_bone_ik.riv in Resources */,
C3D187F9280770EA008B739A /* truck.riv in Resources */,
Expand Down Expand Up @@ -463,6 +497,8 @@
C3468E6227FDCBC6008652FD /* SimpleSlider.swift in Sources */,
C3357CA1280F42EC00F03B6F /* ExamplesMaster.swift in Sources */,
C324DB5628071EB80060589F /* RiveSwitch.swift in Sources */,
C3ECAC272817BE4600A81123 /* SwiftTouchEvents.swift in Sources */,
C3ECAC2F281840A300A81123 /* ClockViewModel.swift in Sources */,
04026DC827CE3EE6002B3DBF /* SwiftLayout.swift in Sources */,
04026DCC27CE3F03002B3DBF /* SwiftLoopMode.swift in Sources */,
C9C73E9A24FC471E00EF9516 /* SceneDelegate.swift in Sources */,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
40 changes: 40 additions & 0 deletions Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// SwiftTouchEvents.swift
// RiveExample
//
// Created by Zachary Duncan on 4/26/22.
// Copyright © 2022 Rive. All rights reserved.
//

import SwiftUI
import RiveRuntime

struct SwiftTouchEvents: DismissableView {
var dismiss: () -> Void = {}

var body: some View {
ScrollView {
VStack {
RiveViewModel(fileName: "play_button_event_example", stateMachineName: "State Machine")
.view()
.aspectRatio(1, contentMode: .fit)

// RiveViewModel(fileName: "switch_event_example", stateMachineName: "Main State Machine")
// .view()
// .aspectRatio(1, contentMode: .fit)

RiveViewModel(fileName: "magic_8-ball_v2", stateMachineName: "Main State Machine")
.view()
.aspectRatio(1, contentMode: .fit)

RiveViewModel(fileName: "leg_day_events_example", stateMachineName: "Don't Skip Leg Day")
.view()
.aspectRatio(1, contentMode: .fit)

ClockViewModel()
.view()
.aspectRatio(1, contentMode: .fit)
}
}
}
}
39 changes: 39 additions & 0 deletions Example-iOS/Source/Examples/ViewModel/ClockViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// TouchEvents.swift
// RiveExample
//
// Created by Zachary Duncan on 4/26/22.
// Copyright © 2022 Rive. All rights reserved.
//

import SwiftUI
import RiveRuntime

class ClockViewModel: RiveViewModel {
var timer: Timer!
var hours: Double = 0 {
didSet {
try? setInput("isTime", value: hours > 12 ? hours-12 : hours)
}
}

convenience init() {
self.init(fileName: "watch_v1", stateMachineName: "Time")
print("Clock widget init'd")

timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
let date = Date()
let calendar = Calendar.current

let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)

self.hours = Double(hour) + Double(minute)/60 + Double(second)/1200
}
}

deinit {
timer.invalidate()
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 4 additions & 5 deletions Example-iOS/Source/ExamplesMaster.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ExamplesMasterTableViewController: UITableViewController {
// MARK: SwiftUI View Examples
/// Made from custom `Views`
private lazy var swiftViews: [(String, AnyView)] = [
("Touch Events!", typeErased(dismissableView: SwiftTouchEvents())),
("Widget Collection", typeErased(dismissableView: SwiftWidgets())),
("Simple Animation", typeErased(dismissableView: SwiftSimpleAnimation())),
("Layout", typeErased(dismissableView: SwiftLayout())),
Expand All @@ -42,11 +43,9 @@ class ExamplesMasterTableViewController: UITableViewController {
private let viewModels: [(String, RiveViewModel)] = [
("Slider Widget", RiveSlider())
]


// MARK: -


}

extension ExamplesMasterTableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()

Expand Down
10 changes: 5 additions & 5 deletions Example-iOS/Source/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Examples-->
<!--Rive Examples-->
<scene sceneID="XV1-T1-lAJ">
<objects>
<tableViewController id="oFD-NX-sZZ" customClass="ExamplesMasterTableViewController" customModule="RiveExample" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController title="Rive Examples" id="oFD-NX-sZZ" customClass="ExamplesMasterTableViewController" customModule="RiveExample" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" estimatedSectionHeaderHeight="-1" sectionFooterHeight="18" estimatedSectionFooterHeight="-1" id="WCh-4c-dF3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
Expand All @@ -31,16 +31,16 @@
<outlet property="delegate" destination="oFD-NX-sZZ" id="el9-mJ-yKI"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Examples" prompt="Discover Ways to Use Rive" id="D8Z-my-oJi"/>
<navigationItem key="navigationItem" title=" " prompt="Discover Ways to Use Rive" id="D8Z-my-oJi"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HFb-68-BQh" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1274" y="-23"/>
</scene>
<!--Navigation Controller-->
<!--Examples Nav Controller-->
<scene sceneID="foC-i9-QZA">
<objects>
<navigationController id="0Wt-ue-AAA" sceneMemberID="viewController">
<navigationController title="Examples Nav Controller" id="0Wt-ue-AAA" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="pOo-q8-9Up">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
Expand Down
42 changes: 31 additions & 11 deletions Source/Components/RiveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ extension RiveView {
} else if let stateMachineName = configOptions?.stateMachineName {
try play(animationName: stateMachineName, isStateMachine: true)
} else {
// DELETE THIS: Zach - playingAnimations.insert() is called through this
try play()
}
} else {
Expand Down Expand Up @@ -537,6 +538,10 @@ extension RiveView {
}

for stateMachine in stateMachines where playingStateMachines.contains(stateMachine) {
// TODO: Needs potential fix
// We get a false returned in certain unexpected situations
// in state_machine_instance.cpp, StateMachineLayerInstance, .advance()
// The instance is removed from the playable state machines
let stillPlaying = stateMachine.advance(by: delta)

stateMachine.stateChanges().forEach { stateChangeDelegate?.stateChange(stateMachine.name(), $0) }
Expand Down Expand Up @@ -565,6 +570,7 @@ extension RiveView {
}
}

// DELETE THIS: Zach - playingAnimations.insert() is called through this
/// Play the first animation of the loaded artboard
/// - Parameters:
/// - loop: provide a `Loop` to overwrite the loop mode used to play the animation.
Expand All @@ -576,6 +582,7 @@ extension RiveView {
runTimer()
}

// DELETE THIS: Zach - playingAnimations.insert() is called through this
/// Plays the specified animation or state machine with optional loop and directions
/// - Parameters:
/// - animationName: name of the animation to play
Expand All @@ -592,6 +599,7 @@ extension RiveView {
runTimer()
}

// DELETE THIS: Zach - playingAnimations.insert() is called through this
/// Plays the list of animations or state machines with optional loop and directions
/// - Parameters:
/// - animationNames: list of names of the animations to play
Expand Down Expand Up @@ -856,41 +864,53 @@ extension RiveView {
}

// MARK: - Artboard Events
extension RiveView: RArtboardDelegate {
// MARK: RArtboardDelegate

/// Events triggered in the RiveArtboard by user input
public func artboard(_ artboard: RiveArtboard, didTriggerEvent event: String) {
// Touch events generated by the hit detection in rive-cpp are given to the artboard
}
extension RiveView {
// TODO: Delegate on RiveStateMachineInstance for touch response

// MARK: UIResponder

open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self)

artboard?.touched(at: location, info: 0)
handleTouch(location: location) { $0.touchBegan(atLocation: $1) }
touchDelegate?.touchBegan?(onArtboard: artboard, atLocation: location)
}

open override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self)

artboard?.touched(at: location, info: 0)
handleTouch(location: location) { $0.touchMoved(atLocation: $1) }
touchDelegate?.touchMoved?(onArtboard: artboard, atLocation: location)
}

open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self)

artboard?.touched(at: location, info: 0)
handleTouch(location: location) { $0.touchEnded(atLocation: $1) }
touchDelegate?.touchEnded?(onArtboard: artboard, atLocation: location)
}

open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self)

artboard?.touched(at: location, info: 0)
handleTouch(location: location) { $0.touchCancelled(atLocation: $1) }
touchDelegate?.touchCancelled?(onArtboard: artboard, atLocation: location)
}

/// Sends incoming touch event to all playing `RiveStateMachineInstance`'s
/// - Parameters:
/// - location: The `CGPoint` where the touch occurred in `RiveView` coordinate space
/// - action: Param1: A playing `RiveStateMachineInstance`, Param2: `CGPoint` location where touch occurred in `artboard` coordinate space
private func handleTouch(location: CGPoint, action: (RiveStateMachineInstance, CGPoint)->Void) {
let artboardLocation = artboardLocation(
fromTouchLocation: location,
inArtboard: artboard!.bounds(),
fit: fit,
alignment: alignment
)

for stateMachine in stateMachines {
action(stateMachine, artboardLocation)
}
}
}
Loading

0 comments on commit 9d9d1b9

Please sign in to comment.