I'm trying to geive the user the ability to drag a skspritenode over a UIImageView and UIButton, but whenever I create the scene it appears behind the UI elements. How do I fix this?
I am afraid that is just not possible. All the sprites and any other elements are rendered frame by frame on the SKScene node and cannot be "dragged" or placed anywhere else. These are not UIKit elements.
In this case, your view is acting as the SKScene and hence all the sprites are being rendered onto that.
SKView is a UIView/NSView in itself. All the Sprite Kit nodes (the scene is also a node) are constituents of the SKView and contained within it. You can only change the draw order of views but not their contents.
To give an example: what you're trying to do is the equivalent of trying to place a UIImageView on top of a UIButton's background but below the UIButton's label.
While technically you could achieve this for plain UIView elements with some trickery, the same will never work for Sprite Kit nodes. They aren't views to begin with but drawn onto an OpenGL framebuffer represented/managed by the SKView. From the perspective of Cocoa an SKView is a single view with no subviews in it.
Simply put: nodes are not views, and nodes are technically incompatible to views.
The UIImageView and its UIButton and whatever other content you want in there must be in a UIView that's sitting lower than the SKView you have the Sprite Kit contents in.
And you'll need to ensure the SKView is transparent (at least its background) and that it passes touches through to the UIView underneath if you need them down there sometimes.
Related
How do I turn off interaction for a childnode?
I'm adding labels to a bunch of sprites, beneath the sprite, describing what they are. The sprites themselves are touchable, and have code that responds when touchesBegun etc.
The labels do not visually overlap the sprite, they're fully beneath the visual representation of the Sprites, but they are children of their respective Sprite, and I'd like to keep it that way.
But I don't want the labels to respond to touch.
I set the labels to
myLabel.isUserInteractionEnabled = false
But this doesn't make any difference, they're still responding to touch as if they're the Sprite.
By default isUserInteractionEnabled is false then the touch on a child like a SKLabelNode is, by default, a simple touch handled to the main (or parent) class (the object is here, exist but if you don't implement any action, you simply touch it)
If you set the userInteractionEnabled property to true on a subclassed SKNode then the touch delegates will called inside this specific class.
So, you can handle the touch for the label (as your case) within its class.
I've created a SpriteNode in a scene and it's there, but it is stuck behind all the UIImages and UIButtons I've dragged onto the storyboard.
I tried changing the .zPosition of the spriteNode to 99999999999999, but it doesn't matter.
What do I need to do to get the spriteNode to appear in front of most of the images? Or can I only have one background image?
Unfortunately for you, this is impossible. You are combining two rendering hierarchies (UIKit and Sprite Kit) whose children (UIView and SKNode, respectively) do not mingle.
SKNodes are rendered inside the SKScene that contains them. The final rendered image is used as the image for the layer of the owning SKView. From there, UIKit (and CoreAnimation) composite the UIViews.
A hierarchy for illustration purposes:
UIView
UIButton
UIButton
SKView (renders an SKScene object)
SKNode
SKLabelNode
SKLabelNode
UIImageview
In my storyboard, I have a base UIView, then a UIView containing a square board drawing in a CGRect and buttons and status fields above and below. I tried drawing the playing pieces but animating them became a nightmare so I have rendered them as sprite nodes in an array and they animate themselves. So far so good. Then layer on top of that is a SKView view and I want to present the SpriteKit scene in there with skView.allowsTransparency = true so I just have the sprites over a transparent background (revealing the board below) and using TapGestureRecognizers to effect the sprite animation event handling.
So in IB hierarchy is: VC / UIView / boardView: UIView / skView
Problem is, the Spritekit scene always targets the top level UIView not skView so game pieces are behind the board. Am I missing something simple here?
I'm gonna try placing a child VC where skView is but any assist, if I've missed a trick, would be very much appreciated.
I wish I could see some code, but what you do is create an IBOutlet for your SKView, then have that outlet present the scene, I am currently doing this in an app I am working on, so I know it is doable
I'm looking for help. I'm trying to make some puzzle game and I have thin scrollable layer at the bottom of my main layer which contains some puzzle shapes. I can scroll the layer and see every shape but shapes were positioned manually in code on the scrollable layer and the problem is, if I try to detect if I touched on sprite, which position is greater than 1024(in first iPad) it doesn't work. it doesn't work because touch can have position inside 1024X768 and the position of shape is for example 1500x100. to make it clearer, shapes are sprites and i try to detect them using CGRectContainsPoints method. Is there any other way to make it or have you any ideas? thanks in advance :]
What you could do is subclass your sprite, create a delegate for it and assign your main view/class as the delegate.
Implement the appropriate touch method, and send the message of what sprite was selected to your delegate (Main view or desired controller class).
With this every sprite has the same delegate, and sends a message to your controlling class as to what sprite has been selected and continue with desired functionality. No need for CGRectContainsPoint method.
This is cleaner, and more efficient.
Hope this helps!
In My Application,i am having one scrollVIew containing multiple images.
and out of the scrollview i have one uiimageview.
i want to Drag any image from ScrollView and drop it on uiimageview which is out of the scrollview.
is it possible?
help And suggestions are appreciated
Thanks in advance.
gamozzii's reply is close to what you need to do, but there's one problem. An UIScrollView will eat touches, so tapping on an image will have no effect.
As a result you will have to subclass the UIScrollView
I have written a small functional app to illustrate dragging the image from a scroll view into an image view. You can download the project here.
Yes this should be possible, you will need to implement the touch/drag events directly.
Check out the touchesBegan, touchesMoved etc. delegate methods in UIResponder.
One approach would be to subclass imageview and implement touchesBegan, touchesMoved in it, and use this imageview subclass to display your images in the scroll view.
On the touchesBegan create a new image view and add it to the outer view and set its image to be the same as the one in the scroll view. You need to overlay it directly over your source image in the scroll view so adjust its frame origin to be relative to the outer view you will need to use the scrollview origin and also the content view size and offset of the source image view inside the content view in order to recalculate the new origin in the outer view.
Then on the touches moved, simply readjust the frame of this image in accordance with the coordinates from the touches moved so that the image follows the touch.
Do a boundary check against the frame of your target imageview - once the user drags it into this boundary, make that target imageviews image the same as the image in the view being dragged and remove the dragged image from the containing view and release it.
In case you're still interested in another solution (and for other users of course):
I did implement that behaviour before just like gamozzii recommended.
I set canCancelContentTouches = NO on the UIScrollView to make sure the subviews handle there touches on their own. If a subview (in your case an image) was touched, i moved the view out of the scrollview onto the superview and started tracking it's dragging. (You have to calculate the correct coordinates within the new superview, so it stays in place). After dragging finishes, i checked if the target area was reached, otherwise I moved it back into the scrollview.
The subviews are handling the dragging on there own via (touchesBegan:/Moved:/Ended:/Cancelled:).
If that's not detailed enough, here's my example code: Github: JDDroppableView