I have a SceneKit view like so:
mySCNKitView.scene = a SCNScene
mySCNKitView.overlaySKScene = a SKScene
Now if I set the userInteractionEnabled property on the overlaySKScene, it has no effect i.e. it is always enabled and so I can't disable user interaction for the overlaySKScene!?
All added child SKNode's to the overlaySKScene will still receive user interaction…
i.e. this has no effect, it is always enabled
mySCNKitView.overlaySKScene?.userInteractionEnabled = true / false
I don't know if it is supposed to be this way?
But it seems like this is how one should disable user interaction for the overlaySKScene…?
Apple Developer Relations20-Jan-2016 08:20 PM
This issue behaves as intended based on the following:
This is the expected behavior of the “userInteractionEnabled” in SpriteKit (which differs from UIKit). You have to set userInteractionEnabled to false to every nodes (not only the SKScene node) otherwise any node with userInteractionEnabled=true will catch the event. Note that SKNode’s userInteractionEnabled defaults to NO (expect for SKScene).
We are now closing this bug report.
If you have questions about the resolution, or if this is still a critical issue for you, then please update your bug report with that information.
Did you ever solve this? I was experiencing a similar problem and then finally got it to work with the following:
let scnView = self.view as! SCNView
let scene = SCNScene()
var spriteScene: OverlayScene!
self.spriteScene = OverlayScene(size: self.view.bounds.size)
scnView.overlaySKScene = self.spriteScene
scnView.overlaySKScene?.userInteractionEnabled = false
With the above code, my entire overlay scene is ignored, events are received by the SceneKit scene as desired. This is in Xcode 7.3 beta, tvOS deployment target 9.1, so maybe it's something that Apple changed recently?
Related
I have a SpriteKit project in which I'm suddenly seeing the following error repeatedly printed to the logs when testing on a real device:
Execution of the command buffer was aborted due to an error during execution. Insufficient Permission (to submit GPU work from background)
This happens when the app is in the background state.
Now, it's pretty obvious what's going on: SpriteKit uses Metal, and the latter is committing new work to the GPU when the app is backgrounded (which is something you can't do).
I've confirmed this theory by not loading my SpriteKit scenes. If I don't load the scenes, the problem does not occur.
What I've tried:
In my SceneDelegate's sceneWillResignActive(_:) function, I tried setting isPaused to true, like this:
func sceneWillResignActive(_ scene: UIScene) {
GameSceneHelper.scene.isPaused = true
CloudSceneHelper.scene.isPaused = true
}
...and then resuming the scenes in sceneDidBecomeActive(_:), like this:
func sceneDidBecomeActive(_ scene: UIScene) {
GameSceneHelper.scene.isPaused = false
CloudSceneHelper.scene.isPaused = false
}
I'd think that would work, but it doesn't. The error persists.
Question:
What's going on, here? Why am I suddenly getting this new error, and how do I solve the problem?
Thank you!
Edit:
I found a (ugly) workaround: Because my SpriteKit scenes are presented using SwiftUI, I can just set a boolean that indicates whether or not to show the scenes. There's no error when I do it this way.
Unfortunately, this results in undesirable behaviors: 1) when you swipe the app away, you can see the scene suddenly disappear, 2) when you bring the app to the foreground you can see the scene suddenly reappear, and 3) the app snapshot (that iOS takes of your app when you move it to the background) shows an empty screen because the scenes have already been hidden when it takes the snapshot.
I can't understand why this is happening in the first place; my understanding was that SpriteKit scenes are automatically paused when the app is in the background.
So, I'm still looking for a better solution -- and maybe an explanation.
Edit #2:
According to Apple's documentation, SpriteKit is, indeed, paused/resumed automatically when the app goes from/to the background:
When an application moves from an active to an inactive state, isPaused is automatically set to true. When an application returns to an active state, isPaused is automatically set to its previous value.
I heard back from Apple Support after sending them an Xcode project illustrating the problem. They recommended that I file a bug report using Feedback Assistant. So, it appears that this is a legitimate bug.
Apple says the problem is related to the use of the playSoundFileNamed, which is somehow making my update(_:) function get called while the app is in the background (and while the SpriteKit scene is paused!).
What's really weird to me is that I don't see other people reporting this problem. If all it takes to trigger this is the use of playSoundFileNamed, I would expect a lot of SpriteKit developers to have the same issue. Maybe SpriteKit isn't used that much? I don't know.
When running my SwiftUI & SpriteKit app, I get the following messages in the logs:
2019-11-18 21:58:57.631912+0000 PixelBattles[2812:1215803]
SKView: ignoreRenderSyncInLayoutSubviews is NO. Call _renderSynchronouslyForTime without handler
What am I doing wrong to receive this log, and should I worry about it? Could it be a bug?
Could it be that SwiftUI cannot figure out how to do the layout for an SKView?
Major edit:
If you need code, you can see it in the previous edits. Below I state why I don't think it is any longer relevant.
I have sent Apple some feedback (FB7456217). I have removed the code, as I no longer suspect it is an issue to do with my code. I created a blank game project, no SwiftUI, and still got the same warning log instantly.
So even with the default project template, the log still appeared for device and simulator. I will update on this issue if I get a useful response.
I still haven't heard anything back - has anyone got any new information since when I posted this over half a month ago? I still have these warnings!
This is Apple's response to this issue:
Hi! You don't really need to fix that. That's a log message that was
left by mistake in SpriteKit framework. It was removed and will no
longer appear in the future SpriteKit versions. Thanks!
just figured this out for myself.
In your code change
if let scene = SKScene(fileNamed: "GameScene")
to
if let scene = GameScene(fileNamed: "GameScene")
I believe you'll also get this warning if you have UIKit subviews of the SKView.
I've been playing around with SpriteKit, and am getting a pretty decent feel about how to drive it from code, but am pretty baffled by the level editor included in Xcode 6.
I've watched the wwdc videos ("platforms state of union" and "what's new in spriteKit"), and scrounged around the web, but haven't been able to find much description about the level editor, and what it's really doing.
What I don't understand, is how are the two files that the template sets up related? Is the .sks file an expression of the GameScene.swift file, or perhaps the GameScene class it contains?
OR do they both just hold separate objects/nodes that are going to play together in the same scene?
Or (this is my best explanation) is the .sks file and the editor basically for making the environment that responsive characters are going to "live" in? If that's true, how can my code in the .swift file relate to what's in the .sks file?
The .sks file is a static archive of your scene's content. If you've used Interface Builder to set up UI apps before, it's much the same idea, if rather different in implementation.
In a UI app, you could do everything in code:
override func viewDidLoad() {
let someText = UITextField(...)
let aButton = UIButton(...)
// ... position everything
// ... style everything
// ... etc ...
}
Or you could do all the static content setup in IB (a xib or storyboard), and use code only for setting up the dynamic behavior of your app — the things that happen when somebody starts touching those buttons. When you do that, the view controller you write code for exists as a proxy object in the xib/storyboard, making a bridge between what you set up in IB and what you set up in code.
In SpriteKit, you have the same choice. Before Xcode 6, many SK games took the all-code approach:
override func didMoveToView(view: SKView) {
let player = PlumberSprite(color: .Red)
player.position = // ...
player.physicsBody = // ...
self.addChild(player)
let ground = SKSpriteNode(...)
ground.position = // ...
ground.physicsBody = // ...
self.addChild(ground)
let block = QuestionBlockSprite()
block.position = // ...
block.physicsBody = // ...
block.contents = CoinSprite()
self.addChild(block)
// ... etc etc etc ...
}
That's a lot of code for what's ultimately a graphical, static scene — even before you start adding code to make it into a game (input handling, enemy behavior, physics callbacks that increment the score or go to game over, etc). And it doesn't lend itself well to designs where you split out the general game logic from the content, so it's harder to add multiple levels to your game.
Instead, you can use the SpriteKit editor in Xcode to build your static content (levels), and stick to code for dynamic behavior and game logic. Just like how, in IB, the view controller is a bridge between your storyboard and your code, your scene class (GameScene.swift in the template) is the bridge between the editor and code. When you load an .sks file at run time (the code for this is in GameViewController.swift in the template), it becomes an instance of your GameScene class, and anything you set up in the editor is accessible as child nodes of the scene.
Checking out WWDC talks is a good idea, but you missed the one that covers this: see session 608: Best Practices for Building SpriteKit Games for more on the motivation behind the SpriteKit editor, how to use it, and how to work with the scene contents loaded from an .sks file in your scene code.
I want to remove an item (lets say a UIButton) from my iPhone application. I want to add some animation when i tap on the button to remove it.
This is the animation i want:
In your OSX dock, if you right-click on an item and tap on *remove from dock*,
it kinda like **explodes** with a funny noise, and removes itself from that dock.
Any knows how to do that smoke (or) tiny explosion animation on the iPhone ?? Is there a pre-defined name for it ?
Believe it or not, there's an API for exactly that on Mac OS X:
NSPoint centrePoint = ...;
NSSize size = ...;
NSShowAnimationEffect(NSAnimationEffectPoof, centrePoint, size, nil, NULL, NULL);
On iOS, there isn't because the animation is a Mac-specific animation. On iOS, one typically sees the deleted object collapse into a point. That animation can be done by animating the transform of a view (using CAAnimation or the UIView class methods) so that it scales to nothingness.
You can roll your own using CAEmitterLayer - there are lots of examples on SO and elsewhere. You could do some really nice stuff (or maybe find some really nice open source code).
I am setting the userTrackingMode of an MKMapView instance in my UIViewController's viewLoaded method. The first time the view loads I set it to MKUserTrackingModeFollowWithHeading successfully. However every subsequent time the view loads, though I again set its value to MKUserTrackingModeFollowWithHeading, this is almost immediately overritten by MKUserTrackingModeNone. I have subclassed MKMapView and overridden setUserTrackingMode, inserting a breakpoint so I can see where it is being called from. The same thing happens in both simulator and on device:
On simulator I get the following from the stack when the value is set to MKUserTrackingModeNone:
On my device (iPhone 4s) I get the following:
There is very little else going on in my application and certainly nothing that is directly triggering the property to be set. What is CLSqliteDatabaseManager? Google returns not a single result. On the device how on earth can MKMapRectContainsRect be involved? I'm using iOS 5.0.
It seems too late to answer. But it may still be helpful for whoever is looking for an answer.
I had exactly same problem. Suddenly I figure out why. Please load your iOS build-in Maps app and click the small arrow button at bottom-left corner to start tracking your location. As soon as you drag the map. The tracking is stopped. Same reason, if you move the map in your code, the MKMapView property userTrackingMode will be reset to MKUserTrackingModeNone automatically.
In my case, I called setCenterCoordinate after set userTrackingMode to MKUserTrackingModeFollow in - (void)viewWillAppear:(BOOL)animated. It worked fine after moving around the code mapView.userTrackingMode = MKUserTrackingModeFollow; to the end.