Everything isDynamic? I'm not sure whether that matters or not; I read that only one shape needs to be dynamic for collisions to be flagged, but I've never experimented with it. What's didBegin look like?
Post
Replies
Boosts
Views
Activity
Nothing immediately obvious from that snippet. Did you turn on showsPhysics to see the physics bodies?
The "Variable used within its own initial value" just means you had some typo and were trying to initialize a variable using some expression involving the same variable. Anyway, glad it's working.
The setupBird in setupNodes is adding a bird immediately. Delete that and just call spawnBird only, then you should get a delay. If you want a shorter delay before the initial bird, then add an initial shorter period before the repeat in spawnBird.func spawnBird() {
let random = CGFloat.random(min: 15.0, max: 30.0)
.run(.sequence([.wait(forDuration: 3), .repeatForever(.sequence([
.wait(forDuration: TimeInterval(random)),
.run { [weak self] in
self?.setupBird()
}
]))]))
}If you want the bird spawning to be at varying intervals, you also should change the let random =..., since that's going to pick one delay and use it forever. Use wait(forDuration:withRange:) for varying delays.
Show what's calling spawnBird and/or setupBird.
Once you experiment with actions a while, your mental model of how they work and the various combination/completion options will get filled in. I spent the last 6 months doing a lot of that.
The fadeAlpha I've never used, but probably the name is confusing you and it's adding the amount specified to alpha. Since you're starting at alpha = 1, adding 0.5 is not going to do anything. Try -0.5.For doing actions in parallel on a bunch of nodes, then running something after all have finished, here's a couple of approaches.// If all nodes have actions that take the same amount of time
func makeNodes(numNodes: Int, then whenDone: @escaping () -> Void) {
let nodeAction = ...
let node1 = makeNode()
node1.run(nodeAction, completion: whenDone)
for _ in 1 ..< numNodes {
let node = makeNode()
node.run(nodeAction)
}
}// If node actions may take random unknown amounts of time
class Coordinator {
var remaining: Int
let action: () -> Void
init(numNodes: Int, whenDone action: @escaping () -> Void) {
remaining = numNodes
action = whenDone
}
func finished() {
remaining -= 1
if remaining == 0 {
action()
}
}
}
func makeNodes(numNodes: Int, then whenDone: @escaping () -> Void) {
let coordinator = Coordinator(numNodes: numNodes, whenDone: whenDone)
for _ in 0 ..< numNodes {
let node = makeNode()
let nodeAction = ...
node.run(.sequence([nodeAction, .run { coordinator.finished() }]))
}
}// If node actions may take varying times but you can compute a max
func makeNodes(numNodes: Int, then whenDone: @escaping () -> Void) {
for _ in 0 ..< numNodes {
let node = makeNode()
let nodeAction = ...
node.run(nodeAction)
}
let delayNode = SKNode()
addChild(delayNode)
delayNode.run(.sequence([.wait(forDuration: maxDelay), .removeFromParent()]), completion: whenDone)
}(I probably have some typos in there since I'm only typing and not compiling/running, but you get the idea.)
Oh, also sequences like NSLog, run, NSLog are just going to do two log messages in quick succession. It's not waiting for the run to finish. If you want that effect, you need to have the second NSLog in a completion block for the run.
It's hard to say without being able to try it and see what happens, but my impression is that you're essentially setting up a bunch of nodes in one corner, scheduling actions to have them move (in parallel) into position, renaming two nodes, and then scheduling actions to have them do some rotation (also in parallel with everything else). I suspect you want things to happen in a more sequential order:1. The shapes start in a corner and spread out to form an array (perhaps in parallel, perhaps one-by-one).2. One corner node to do some rotating.3. The second corner node to do some rotating.Possibly you want 2 and 3 to happen in parallel, but in any case, from your description it sounds like 1 should definitely happen before 2 and/or 3. That's not what you've written though.In particular, lines 28-38 add a bunch of nodes, schedule actions for those nodes, and then immediately (before the actions run) do the renameShape stuff.The completion of the run action means the completion of adding the nodes and scheduling their actions, but it does not mean the completion of those scheduled actions.There are various ways of sequencing things. E.g., you could pass a completion block that would do the rotations and have addShape schedule that after the completion of the actions for one of the nodes (assuming they all move into position simultaneously). Or you could just have another action that would wait(forDuration:) a bit longer than what it takes the nodes to move into position and then runs a block to do the rotations.As a side note, when you're writing SKAction.group, those are happening in parallel. So in a group with actions that have duration 2, an action that is a delay of 0.1 is having no effect at all. Maybe you meant SKAction.sequence, or .sequence([.group([...]), .wait(..)])
The actions will get run sequentially on your main thread, but sticking stuff in didMove may not be what you want. The only thing I ever used there was an initial action to happen on scene appearance (e.g., to wait for a couple of seconds, then start a new game). And things like background nodes that have something like an infinitely repeating animation could be placed there, though I usually put those in the scene creation. But once the scene gets going then the actions are all scheduled from other places. E.g., in response to contacts between nodes, or from the update function, or triggered as a result of user interaction, or based on completions of other actions, etc.Maybe you need to provide more context, because it's really not clear how you have things structured.
There are a few earlier threads on this forum and various threads on Stack Overflow discussing issues with physics bodies from textures in iOS 13.*. I'm not sure that those are all fixed yet (I worked around them back when the latest was 13.2 and haven't gone back to see the story in 13.3), so perhaps that has something to do with your contact issues. On the other hand, when I was having problems, showsPhysics would display obviously-broken physics body outlines.I've had no other issues though, despite working extensively with a large portion of the SpriteKit API over the last half year. When stuff like logging messages don't show up, it seems like something much odder is going on.
I decided to keep using playerID for now, and to stash away a mapping between that and gamePlayerID/teamPlayerID when scopedIDsArePersistent indicates that those are not transient. I'll figure out how to transition data associated with playerID when/if clarity is provided.
FWIW, we wound up not using the logo due to consistency with the app settings screen (where there's a Game Center achievement reset button but the regular GC logo color scheme looked inconsistent), so I never found out whether it would have passed review or not. We did write to legal, but we're probably too small for them to worry about and they never responded.
The iPhone X is driving a display of about 2400x1100, the 6s only about 1300x750, so differences in FPS aren't that surprising. Your main problem is likely the enormous number of draws: a whopping 120 for only 300 nodes. Perhaps you're using a lot of shape or text nodes, or maybe you've got a bunch of sprite nodes whose textures aren't in an atlas, or maybe you have ignoresSiblingOrder set to false unnecessarily. Once you fix the draw count issue, your performance will probably be much better on both devices.
Uint32(5) bitwise-& Uint32(9) = Uint32(1). Because that result isn't 0, it's notifying you of the collision.If you don't want that notification, you have to either change B's category bitmask or A's contact bitmask.The fact that the overlap between A's category and B's contact is 0 doesn't matter, since it notifies you if either result isn't 0.