Since you haven't provided any code (please do so next time), I am going to provide a solution which should point you in the right direction.
Lets begin by creating a PathItem Class
which we will use to make a complete path e.g. a line of them:
/// Path Item Node
class PathItem: SCNNode{
/// Creates A PathItem
///
/// - Parameters:
/// - size: CGFloat (Defaults To 20cm)
/// - texture: UIColour
/// - position: SCNVector3
init(size: CGFloat = 0.2, texture: UIColor, position: SCNVector3){
super.init()
//1. Create Our Path Geometry
let pathGeometry = SCNPlane(width: size, height: size)
//2. Assign The Colour To The Geoemtry
pathGeometry.firstMaterial?.diffuse.contents = texture
//3. Assign The Geometry, Position The Node & Rotate The Node So It Is Horizontal
self.geometry = pathGeometry
self.position = position
self.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
required init?(coder aDecoder: NSCoder) { fatalError("Path Item Coder Has Not Been Implemented") }
}
Now having done this, lets create a func
which will create a line of PathItem
(a Path).
First create a Global variable like so which references the size of each PathItem
:
let pathItemSize: CGFloat = 0.2
Then we create our function which alternates the colour of each PathItem
as well as providing them with a unique name
or index which we will use later in our animation:
/// Create A Path With A Number Of Elements
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//2. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//c. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//d. Set It To Hidden Initially
pathItem.isHidden = true
//e. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
}
To generate a Path
we can now do something like so:
override func viewDidLoad() {
super.viewDidLoad()
//1. Set Up Our ARSession
augmentedRealityView.session = augmentedRealitySession
sessionConfiguration.planeDetection = .horizontal
augmentedRealityView.debugOptions = .showFeaturePoints
augmentedRealitySession.run(sessionConfiguration, options: [.resetTracking, .removeExistingAnchors])
//2. Create A Path Of 10 PathItems
createdPathOfSize(10)
}
Whereby I have the following Global variables
:
@IBOutlet var augmentedRealityView: ARSCNView!
let augmentedRealitySession = ARSession()
let sessionConfiguration = ARWorldTrackingConfiguration()
Now we have generated our Path we need to animate it!
To provide a bit of diversity let's create an Enum
which we can use to create different PathAnimations:
/// Path Item Animation
///
/// - UnHide: UnHides The Path Item
/// - FadeIn: Fades The Path Item In
/// - FlipIn: Flips The Path Item In
enum AnimationType{
case UnHide
case FadeIn
case FlipIn
}
No since we will be doing some animations lets create 2 more Global variables which will be used to run our animation on a Timer and keep track of where we are up to:
var pathAnimationTimer: Timer?
var time: Int = 0
Now lets create our animation function:
/// Animates The Laying Of The Path
///
/// - Parameters:
/// - numberOfElements: Int
/// - animation: AnimationType
func animatePathElements(_ numberOfElements: Int, withAnimation animation: AnimationType ){
//1. If We Are Flipping The PathItems In We Need To 1st Unhide Them All & Rotate Them To A Vertical Postions
if animation == .FlipIn {
let pathItems = self.augmentedRealityView.scene.rootNode.childNodes
pathItems.forEach({ (pathItemToAnimate) in
pathItemToAnimate.isHidden = false
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(0)
})
}
//2. Create Our Time Which Will Run Every .25 Seconds
pathAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
//3. Whilst Our Time Doesnt Equal The Number Of Path Items Then Continue Our Animation
if self.time != numberOfElements{
//a. Get The Current Node Remembering Each One Has A Unique Name (Index
guard let pathItemToAnimate = self.augmentedRealityView.scene.rootNode.childNode(withName: "\(self.time)", recursively: false) else { return }
//b. Run The Desired Animation Sequence
switch animation{
case .UnHide:
//Simply Unhide Each PathItem
pathItemToAnimate.isHidden = false
case .FadeIn:
//1. Unhide The Item & Sets It's Opacity To 0 Rendering It Invisible
pathItemToAnimate.isHidden = false
pathItemToAnimate.opacity = 0
//2. Create An SCNAction To Fade In Our PathItem
let fadeInAction = SCNAction.fadeOpacity(to: 1, duration: 0.25)
pathItemToAnimate.runAction(fadeInAction)
case .FlipIn:
//Simply Rotate The Path Item Horizontally
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
self.time += 1
}else{
//4. Our Animation Has Finished So Invalidate The Timer
self.pathAnimationTimer?.invalidate()
self.time = 0
}
}
}
We then need to add this to the end of our createPathOfSize function like so:
/// Create A Path With A Number Of Elements Which Can Be Animated
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//1. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//b. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//c. Set It To Hidden Initially
pathItem.isHidden = true
//d. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
//2. Animate The Path
animatePathElements(10, withAnimation: .FlipIn)
}
And here is the full example:
import UIKit
import ARKit
//----------------------
//MARK: - Path Animation
//----------------------
/// Path Item Animation
///
/// - Show: UnHides The Path Item
/// - FadeIn: Fades The Path Item In
enum AnimationType{
case UnHide
case FadeIn
case FlipIn
}
//-----------------
//MARK: - Path Item
//-----------------
/// Path Item Node
class PathItem: SCNNode{
/// Creates A PathItem
///
/// - Parameters:
/// - size: CGFloat (Defaults To 20cm)
/// - texture: UIColour
/// - position: SCNVector3
init(size: CGFloat = 0.2, texture: UIColor, position: SCNVector3){
super.init()
//1. Create Our Path Geometry
let pathGeometry = SCNPlane(width: size, height: size)
//2. Assign The Colour To The Geoemtry
pathGeometry.firstMaterial?.diffuse.contents = texture
//3. Assign The Geometry, Position The Node & Rotate The Node So It Is Horizontal
self.geometry = pathGeometry
self.position = position
self.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
required init?(coder aDecoder: NSCoder) { fatalError("Path Item Coder Has Not Been Implemented") }
}
class ViewController: UIViewController {
typealias PATH = SCNNode
@IBOutlet var augmentedRealityView: ARSCNView!
let augmentedRealitySession = ARSession()
let sessionConfiguration = ARWorldTrackingConfiguration()
var pathPlaced = false
let pathItemSize: CGFloat = 0.2
var pathAnimationTimer: Timer?
var time: Int = 0
//----------------------
//MARK: - View LifeCycle
//----------------------
override func viewDidLoad() {
super.viewDidLoad()
//1. Set Up Our ARSession
augmentedRealityView.session = augmentedRealitySession
sessionConfiguration.planeDetection = .horizontal
augmentedRealityView.debugOptions = .showFeaturePoints
augmentedRealitySession.run(sessionConfiguration, options: [.resetTracking, .removeExistingAnchors])
//2. Create A Path Of 10 Path Items
createdPathOfSize(10)
}
//---------------------------------
//MARK: - Path Creation & Animation
//---------------------------------
/// Animates The Laying Of The Path
///
/// - Parameters:
/// - numberOfElements: Int
/// - animation: AnimationType
func animatePathElements(_ numberOfElements: Int, withAnimation animation: AnimationType ){
if animation == .FlipIn {
let pathItems = self.augmentedRealityView.scene.rootNode.childNodes
pathItems.forEach({ (pathItemToAnimate) in
pathItemToAnimate.isHidden = false
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(0)
})
}
pathAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
//1. Whilst Our Time Doesnt Equal The Number Of Path Items Then Continue Our Animation
if self.time != numberOfElements{
guard let pathItemToAnimate = self.augmentedRealityView.scene.rootNode.childNode(withName: "\(self.time)", recursively: false) else { return }
//2. Run The Desired Animation Sequence
switch animation{
case .UnHide:
pathItemToAnimate.isHidden = false
case .FadeIn:
pathItemToAnimate.isHidden = false
pathItemToAnimate.opacity = 0
let fadeInAction = SCNAction.fadeOpacity(to: 1, duration: 0.3)
pathItemToAnimate.runAction(fadeInAction)
case .FlipIn:
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
self.time += 1
}else{
self.pathAnimationTimer?.invalidate()
self.time = 0
}
}
}
/// Create A Path With A Number Of Elements Which Can Be Animated
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//1. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//b. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//c. Set It To Hidden Initially
pathItem.isHidden = true
//d. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
//2. Animate The Path
animatePathElements(10, withAnimation: .FlipIn)
}
}
This should be more than enough to point you in the right direction ^__________^.