Skip to content

Commit

Permalink
Merge pull request #4 from pocketpixels/patch-1
Browse files Browse the repository at this point in the history
Support animation durations shorter than 1 second

Thanks for the edits @pocketpixels!
  • Loading branch information
maxxfrazer authored Jul 2, 2021
2 parents f223ebf + b9c6a4d commit efe1f0b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 23 deletions.
26 changes: 10 additions & 16 deletions .github/workflows/swift-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@ name: build

on:
push:
branches:
- "master"
tags:
- "!*"
branches: [ master ]
pull_request:
branches:
- "*"
branches: [ master ]

jobs:
build:
runs-on: macOS-latest

runs-on: macos-latest

steps:
- uses: actions/checkout@v1
- name: Build Package
run: |
swift package generate-xcodeproj
xcodebuild clean build -project $PROJECT -scheme $SCHEME -destination "$DESTINATION" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO
env:
PROJECT: SCNBezier.xcodeproj
SCHEME: SCNBezier-Package
DESTINATION: platform=iOS Simulator,name=iPhone Xs
- uses: actions/checkout@v2
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v
9 changes: 7 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import PackageDescription

let package = Package(
name: "SCNBezier",
platforms: [.iOS(.v8), .macOS(.v10_10), .tvOS(.v9), .watchOS(.v3)],
platforms: [.iOS(.v9), .macOS(.v10_10), .tvOS(.v9), .watchOS(.v3)],
products: [.library(name: "SCNBezier", targets: ["SCNBezier"])],
targets: [.target(name: "SCNBezier")],
targets: [
.target(name: "SCNBezier"),
.testTarget(
name: "SCNBezierTests",
dependencies: ["SCNBezier"])
],
swiftLanguageVersions: [.v5]
)
31 changes: 26 additions & 5 deletions Sources/SCNBezier/SCNAction+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,38 @@ public extension SCNAction {
/// - fps: how frequent the position should be updated (default 30)
/// - interpolator: time interpolator for easing
/// - Returns: SCNAction to be applied to a node
class func moveAlong(
static func moveAlong(
path: SCNBezierPath, duration: TimeInterval, fps: Int = 30,
interpolator: ((TimeInterval) -> TimeInterval)? = nil
) -> SCNAction {
let actions = path.getNPoints(count: Int(duration) * fps, interpolator: interpolator).map { (point) -> SCNAction in
let tInt = 1 / TimeInterval(fps)
return SCNAction.move(to: point, duration: tInt)
}
let actions = SCNAction.getActions(
path: path, duration: duration, fps: fps,
interpolator: interpolator
)
return SCNAction.sequence(actions)
}

internal static func getActions(
path: SCNBezierPath, duration: TimeInterval, fps: Int = 30,
interpolator: ((TimeInterval) -> TimeInterval)? = nil
) -> [SCNAction] {
let nPoints = path.getNPoints(
count: max(2, Int(ceil(duration * Double(fps)))), interpolator: interpolator
)
let actions = nPoints.enumerated().map { (iterator) -> SCNAction in
if iterator.offset == 0 {
// The first action should be instant, making sure the
// SCNNode is in the starting position
return SCNAction.move(to: iterator.element, duration: 0)
}
// The duration of each actuion should be a fraction of the full duration
// n points, n - 1 moving actions, so duration / (n - 1)
let tInt = duration / Double(nPoints.count - 1)
return SCNAction.move(to: iterator.element, duration: tInt)
}
return actions
}

/// Move along a Bezier Path represented by a list of SCNVector3
///
/// - Parameters:
Expand Down
57 changes: 57 additions & 0 deletions Tests/SCNBezierTests/SCNBezierTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

import XCTest
@testable import SCNBezier
import SceneKit

internal func - (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
return SCNVector3Make(left.x - right.x, left.y - right.y, left.z - right.z)
}
internal func + (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
}
internal func * (left: SCNVector3, right: VectorVal) -> SCNVector3 {
return SCNVector3Make(left.x * right, left.y * right, left.z * right)
}

internal extension SCNVector3 {
var length_squared: Float {
Float(sqrt(x * x + y * y + z * z))
}
}

final class SCNBezierTests: XCTestCase {
func testBasicBezier() throws {
let bezPositions = [
SCNVector3(-1, 1, 0.01),
SCNVector3(1, 0.5, 0.4),
SCNVector3(1.0, -1, 0.1),
SCNVector3(0.4, -0.5, 0.01)
]

let points = SCNBezierPath(points: bezPositions).getNPoints(count: 100)
XCTAssertTrue(points.count == 100, "Wrong number of points: \(bezPositions.count)")
checkPositionsEqual(bezPositions.first!, points.first!)
checkPositionsEqual(bezPositions.last!, points.last!)
}

func testUnevenValue() throws {
let bezPositions = [
SCNVector3(-1, 1, 0.01),
SCNVector3(1, 0.5, 0.4),
SCNVector3(1.0, -1, 0.1),
SCNVector3(0.4, -0.5, 0.01)
]
let bezPath = SCNBezierPath(points: bezPositions)
let actions = SCNAction.getActions(path: bezPath, duration: 0.3, fps: 1)
let actionSequence = SCNAction.sequence(actions)
XCTAssertTrue(actions.count == 2, "should have at least 2 actions!")
XCTAssertTrue(actionSequence.duration == 0.3, "Action sequence wrong length: \(actionSequence.duration)")
XCTAssertTrue(actions.first!.duration == 0, "Action sequence wrong length: \(actions.first!.duration)")
XCTAssertTrue(actions.last!.duration == 0.3, "Action sequence wrong length: \(actions.last!.duration)")
}

func checkPositionsEqual(_ first: SCNVector3, _ second: SCNVector3, prependMessage: String = "") {
let endDiff = (first - second).length_squared
XCTAssertTrue(endDiff < 1e-5, "\(prependMessage)\nLast point is not correct \(first) vs \(second)")
}
}

0 comments on commit efe1f0b

Please sign in to comment.