What's the equivalent of convertToNodeSpace in Sprite Kit - sprite-kit

Let me first introduce you to the node hierarchy:
SKView->SKScene->SKNode
I've added a UIPinchGestureRecognizer to the view so that I can zoom in and out my content. Here's the code in SKScene object:
-(void)handlePinch:(UIPinchGestureRecognizer*)pinchRecognizer{
[self runAction:[SKAction scaleBy:pinchRecognizer.scale duration:0]];
pinchRecognizer.scale = 1;
}
Everything's OK except for two things:
In my node's touch events I check the position of the touch and act accordingly. Everything works fine as long as the scale of the scene is untouched. But if I zoom in or out I can no more do this. It's because even if I seem to touch the same point on the screen it's actually different before and after zooming. In Cocos2D I had exactly the same problem. But I could solve this problem by just converting the touch point to node space with convertToNodeSpace method. There should be an equivalent in Sprite Kit. What is it?
When pinching, anchor point is the lower left corner. Is there a way to make it zoom from where the pinching occurs?

Related

Swift/Sprite-kit Adding a static hud that is always at the top and bottom, with the moveable game in the middle?

I have been playing around trying to learn spritekit in xcode7. So far I have a level that is larger than the screen, a hero the I can move around and a camera that follows the hero as he moves off the the viewable screen area. Next I'm trying to create a hud at the top and bottom of the screen. The bottom one would be where the joystick/buttons live.
I tried something like this:
let hud = SKSpriteNode(color: SKColor.blackColor(), size: CGSizeMake(self.size.width, self.size.height * 0.05))
hud.anchorPoint = CGPointMake(0, 0)
hud.position = CGPointMake(0, (self.view?.bounds.height)! - hud.size.height)
self.addChild(hud)
But this puts a black view at the top of my level and I can only see it if I walk my hero up there. That means if I move it to the bottom, as soon as my hero walks up the joystick and buttons will be off the screen.
Can anyone please provide any direction on how I can add huds to sprite-kit that are always at the top and bottom of the viewable area, while still allowing the hero to move around the level?
You could add the HUD as a child of the scene, then add the world as a child of the scene too. The character must be a child of the world.
This way, the character can move around the world and then the world can be moved on the scene so the character could be visible, without messing with the HUD.
Swift 3:
This should move your hud (suppose is a SKNode) from the origin anchorPoint (0.5,0.5) of the camera to CGPoint.zero always visible:
override func didSimulatePhysics() {
hud.position = CGPoint(x:-self.frame.midX,y:-self.frame.midY)
}
There are two options to doing this, one is to add UIButtons to your view which will always appear on the top, the other (which I commonly use) is dynamically setting the position of the hud based off of the anchor point of the scene.
The first way is pretty simple, just create the UIButtons and UILabels in Interface Builder and they should be on top of your scene (you may need to mess around with view layer numbers to get it appearing above though).
The other way is to put some code in the didSimulatePhysics method (which will only be called after the update, and after the physics have been simulated). Basically, doing what you are doing, and setting the position of the hud to the scene's anchorPoint multiplied by the width and height of the scene. Something like this (my Swift is a little rough):
let x = (((-self.scene.anchorPoint.x) * self.frame.size.x) + anyOffsetRequired.x)
let y = (((-self.scene.anchorPoint.y) * self.frame.size.y) + anyOffsetRequired.y)
hud.position = CGPointMake(x, y)
The - on the anchorPoint is due to how moving the scene's anchorPoint works (going right requires negative, going down requires positive). anyOffsetRequired is just a CGPoint that allows you to set the offset, you may or may not need it in your case.

Cocos2d CCFollow when there are multiple layers

Essentially, when I have one CCLayer for background and platform sprites and another for player sprite and HUD, how should I go about calling CCFollow if I want my camera to always center at the player with the HUD in the same layer moving accordingly as well?
Right now the background layer is a subclass of CCLayer that has a CCSpriteBatchNode for drawing objects in the environment. It contains an instance variable CCLayer *HudLayer that has a CCMenu and another CCSpriteBatchNode for the player animation sprites. They are both direct children of a CCScene, meaning HudLayer is not a children of BackgroundLayer. I'm now calling the CCFollow as [self runAction:[CCFollow actionWithTarget:playerSprite worldBoundary:worldRect]] where self is the BackgroundLayer.
The camera follows the box2d physics body of the player correctly, and the menu moves with it too, but whenever the camera moves, let's say to the right, the player sprite moves twice as fast to the right, leaving its physics body behind. So after moving to the right for a bit the playerSprite is outside of screen. playerSprite.pos and playerSprite.position seem to have nothing wrong though.
I've tried calling the CCFollow in different places but either the HUD refuses to move or the camera won't move or the player moves weirdly. What's wrong with it?
I FIGURED IT OUT! The key here is to put the player sprite in some layer other than the HUD layer. I added my CCSpriteBatchNode for the player sprites as a child of backgroundLayer instead of the HudLayer without changing anything else and it worked.
So basically everything that needs to always stay on screen as the HUD should be in one layer, while the target node for CCFollow should be in a separate layer (in the background in my case). The caller layer of CCFollow should contain the target node as a direct child. This tutorial helped me a great deal: http://www.raywenderlich.com/4666/how-to-create-a-hud-layer-with-cocos2d

out of the scene elements overlap the previous scene during transitions

I am developing a cocos2d based IPhone game where a scene replace another with a Left to Right Transition. The new scene has a background a bit bigger than the scene. That is just because I move it according to the device tilt to create a sort of 3D effect.
Unfortunately during the transition of the scene I can see the background outside the scene overlapping the previous one :(
I have then tried to use the z-order in such a way the previous scene should go on top of the new one bug it does not work the way it should.
do you have any suggestion?
Thank you in advance
I think you need do crop your scenes layer by overriding it's -(void)visit method.
That's how I did it:
- (void) visit {
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(cropRect.origin.x,
cropRect.origin.y,
cropRect.size.width,
cropRect.size.height);
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
May be you'll need to play a bit with cropRect origin and size values.
Also you may need to add some device orientation changing support

Cocos2D, UIScrollView, and initial placement of a scene

I am using a UIScrollView to forward touches to Cocos2D as outlined in http://getsetgames.com/2009/08/21/cocos2d-and-uiscrollview/
Everything works great after a few days of working with it, except one thing: when the initial view appears on the screen, the background appears to be scrolled to the center. As soon as I try to scroll around, the image jumps to 0,0, and everything works as normal, except the touches are offset by half the width and height of the background image. Am I overlooking something basic? I can't think of a useful portion of the code that illustrates the issue, as I can't track it down, but would be happy to post code if anyone has any ideas.
Thanks in advance,
-Roberto
I just had to localize the touches in respect to the window, by using nil in locationInView. This returns the touch's location on what's currently visible in the display.
CGPoint location = [[CCDirector sharedDirector] convertToGL:[touch locationInView:nil]];

How can i rotate an arrow image by touch on that image?

I am working on a project where i need to rotate an image by touching it.
It can be rotate faster or slower depending on how the user touches it.
Can you show me some tutorials or how this can be done?
Place your image within a UIImageView, then either subclass that view and replace touchesBegan:withEvent: or set a delegate for it and implement the same method as a delegate method. This will give you the ability to respond to touch events (the beginning of a touch, in this case, although you can do the same for ending a touch or moving of the finger).
Within this touch handling method, you can implement something similar to what I describe here in order to perform a Core-Animation-enabled rotation of your UIImageView at a given speed. To alter the speed, change the duration property on the animation I provide. As I suggest there, you may want to look into a CAKeyframeAnimation to do a smoother animation with acceleration and deceleration at the beginning and end.
An easier way is to set up an NStimer and rotate the transform everytime it fires.
I've some sample code here that coincidentally does something similar:
http://github.com/kailoa/touchsamplecode/tree/master
Using Cocos2d, you can't have 'touch enabled' sprites, 'isTouchEnabled' is at the Layer level. You'll have to receive the touch at the layer level, then check the location of the touch against the location of the touchable sprite. The CGRect* functions include a 'rect contains point' which you can pass the touch location to, with the sprite's rect to see if it was 'touched', and which point you could then say [sprite runAction:[Rotate ....]]