===== SOLVED SOLVED =====
I placed print("pause index =", savedTrainIndex)after pausing the game and got 160, e.g. I also placed print("resume index =", savedTrainIndex) before resuming and got 160 as it should be as the node was moving along the top half of the oval.
Then, as the node was moving along the bottom half of the oval, I got 90.
Here is the response I received from Apple Deve;loper Tech Support - which worked flawlessly:
When you run the follow action on a node, SpriteKit will set the position of the node to the starting position of the provided path.
The issue you are observing (when the train makes large jumps in position) is caused because of large differences in the node’s current position compared to the follow path’s starting position.
This large difference is due to a bug in your code, specifically in the closestPointInPath function, which appears to be an algorithm that tries to determine the point on the path that is closest to the current position of the node, which you then use to calculate the starting point for the new follow path.
If you replace that function with this one (which contains a naive implementation to find the closest point to the target point), you will see that the large position jumps no longer occur:
public func closestPointInPath(_ path:UIBezierPath,
toPoint:CGPoint) -> CGPoint? {
let targetPoint = toPoint
let thePoints = getPointsForPath(path)
var closestPoint = CGPoint.zero
var minDistance = CGFloat.infinity
for point in thePoints {
let distance = distanceBetween(point, targetPoint)
if distance < minDistance {
minDistance = distance
closestPoint = point
}
}
return closestPoint
}
Mr. Chistie from Apple DTS is out-of-sight awesome.
Once again, I labor for 3 weeks and DTS solves the problem in 3 days.
Post
Replies
Boosts
Views
Activity
===== new discovery =====
I placed print("pause index =", savedTrainIndex)after pausing the game and got 160, e.g. I also placed print("resume index =", savedTrainIndex) before resuming and got 160 as it should be as the node was moving along the top half of the oval.
Then, as the node was moving along the bottom half of the oval, I got 90.
I think this is the key to my challenge because I believe after stopping and then restarting along the bottom half of the oval, the stop/restart index should be a number > 160, not 90. In short, shouldn't the index monotonically increase as it is traveling along the whole oval?
Anyway, I am currently investigating this discrepancy. Don't know if it will lead to a solution or not at this time.
SUCCESS!!
Somehow my pdf disappeared from my Copy Bundle Resources. Clicked + to add it back in. Lordy, I cannot possibly thank all of you enough for your extraordinary patience.
I'm getting there ...
Again, I call addPDFView() + displayPDF("ABOUT_OLD_WEST_LOCOMOTIVE.pdf"
within my specific SKScene's sceneDidLoad() because I have multiple SKScenes.
and an empty PDFView shows ... which tells me my Project is not seeing my .pdf file.
I do not understand this because when I select my Target's Build Phases and expand Copy Bundle Resources, the above .pdf file is listed.
???
Please note that the only reason I do not place all the PDFView code in my GameViewController is because I have 3 SKScenes, only one of which uses a PDFDocument. As a result, I add the PDFView to all SKScenes within my GameViewController and then fill it in the one SKScene that will show the PDFDocument.
As long as I am asking for help, how do I successfully place my pdfView on top Being a UIView, it has no .zPosition?
Starting over with the suggestions offered so far,
I have this in AppDelegate:
var pdfView: PDFView!
In my GameViewController’s viewDidLoad(), I call:
`addPDFView()’
which looks like this:
func addPDFView() {
pdfView = PDFView(frame: self.view.frame)
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
pdfView.displayDirection = .vertical
view.addSubview(pdfView)
} // addPDFView
Then, in my SKScene’s sceneDidLoad(), I call:
displayPDF("ABOUT_OLD_WEST_LOCOMOTIVE")
which looks like this:
func displayPDF(_ itsName:String) {
guard (thisSceneName == "AboutIOSScene") else { return }
let pdfView = PDFView() // see GameViewController's addPDFView()
guard let path = Bundle.main.path(forResource: itsName, ofType: "pdf")
else { return }
print("path =", path)
guard let pdfDocument = PDFDocument(url: URL(fileURLWithPath: path))
else { return }
print("pdfDocument =", pdfDocument)
pdfView.document = pdfDocument
} // displayPDF
Once again, the 2 print statements are shown .. but no pdfView.document
John
Okay, I'm back.
I am still enjoying learning about re-parenting.
In the meantime ... instead of adding the particle emitter as a child of myTrain, I place the particle emitter as a child of GameScene, which obviously isn't moving/
SOLVED
Now, back to re-parenting ...
Yes, I have a published App, but I've only been at this for 9 months. Bunches to still learn about, including re-parenting.
Will return to you, guaranteed, after I drink from the re-parenting firehose.
John
Thanks bunches, Greg for responding!
I guess I need to find out how to override isPaused so that for my Emitters, the emitters always set isPaused = false, which overrides the default behavior, namely, whatever the super class has for isPaused trickles down hill to the children.
I need to find out how to override isPaused so no matter what the superclass specifies and tries to impose isPaused on its children, my EmitterScene class always returns isPaused = flase.
Currently, I have:
class EmitterScene: SKScene {
override var isPaused: Bool {
get {
return false
}
set {
// deliberately left empty
}
}
}
Not working .. my strong suspicion is that the not working is due to a monumental syntax error that still compiles okay, but just doesn't work.
Yes, I know isPaused belongs to SKNode
Thanks again bunches and bunches for "having pity on me"
John
See the 1st answer to https://stackoverflow.com/questions/50100268/ispaused-not-working-properly-in-sknode
Because of the response from the programmer at Reddit, I have even tried this code:
func addEmitterToScene(_ particleName: String,
_ theScene: SKScene) {
if let emitter = SKEmitterNode(fileNamed: particleName) {
emitter.name = "emitter"
emitter.targetNode = theScene
emitter.position = .zero // = at center of theScene
theScene.addChild(emitter)
}
} // addEmitterToScene
func removeEmitterFromScene(_ emitterName: String,
_ theScene: SKScene) {
if let emitterChild = theScene.childNode(withName: emitterName) {
emitterChild.removeFromParent()
}
} // removeEmitterFromScene
which I call via:
gameScene.addEmitterToScene("smokeParticle", itsScene)
when my Node has exceeded the speed limit
and:
gameScene.removeEmitterFromScene("emitter", itsScene)
when I start over by calling my newGame()
Same results ...
Thanks to a heads-up from someone at Reddit's iOS Programming board when he asked if not pausing the SKSpriteNode made the SKEmitterNode childNode to show ...
The answer = Yes ...
So, apparently, pausing the SKSpriteNode prevents the SKSpriteNode from updating with its SKEmitterNode childNode.
I have a override to GameScene's update(_ currentTime: TimeInterval) .. but that won't be called unless the SKSpriteNode is moving.
Is there a way to pause the SKSpriteNode and force an update to display the SKEmitterNode?
FWIW, I have tried to create the SKEmitterNode first, then pause the SKSpriteNode. In this case, the SKEmitterNode will definitely show, but the SKSpriteNode does not pause.
?????
I just read that adding/removing SKEmitterNodes was a known issue way back in 2015. Surely, it should have been corrected by now?
-- SOLVED --
The MAGIC centers on
(a) initializing the animated GIFs for display on the “top” every time there is a newGame()
(b) re-creating the animated GIFs with GameScene’s update(..) method.
I owe my "sanity" to both @DonMag on StackOverflow and to John at Apple DTS. Two huge Atta-Boys to these blooming geniuses.
-- end SOLVED --
SUCCESS ...
I discovered that when you use a SKTransition whenever calling presentScene just for os(tvOS), that the above OH-OH happens.
Again, no such OH-OH for os(iOS) ??
SO .. just eliminate the SKTransition for os(tvOS), and all is good.
I'm not particularly happy about ditching the SKTrnsition, but at least now I know the solution.
func presentScene(_ theScene: SKScene) {
theScene.scaleMode = .resizeFill
if let skView = self.view as? SKView {
skView.ignoresSiblingOrder = true
skView.showsFPS = true
skView.showsNodeCount = true
#if os(iOS)
let theTransition = SKTransition.doorway(withDuration: 2.0)
skView.presentScene(theScene, transition: theTransition)
#elseif os(tvOS)
skView.presentScene(theScene)
#endif
}
} // presentScene