Confusing reversed touch event in Swift - ios

In my function
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
for touch in touches{
let touchLocation = touch.location(in: self.view)
print("X: \(touchLocation.x) Y: \(touchLocation.y)")
}
}
I get reversed Y value. If I click at the top I get ~0 value and if I click at the bottom I get high value. This makes my sprite im moving move in the wrong Y direction.
However if I remove '.view' in self.view it works as it should. Does anyone know why it's reversed when I use self.view?

As explained by Whirlwind in the comment below your question, this happened because with self you indicate SKScene (SpriteKit) and with self.view you use SKView (UIView subclass so UIKit system):
UIKit coordinate system for iOS has its origin at the upper left of the drawing area, and positive values extend down and to the right from it.
SpriteKit coordinate system uses the same coordinate system on both iOS and OS X, has the origin (0,0) in the lower-left corner, and the (1334,750) coordinate in the upper-right corner.

Related

Xamarin iOS - UIView Animation with velocity

I've got a UIView laying right above all others. This UIView has a UIPanGestureRecognizer to drag it around of the screen. If the User stopped panning, the View moves to a calculated Position which is the left screen bounds or the right ones. This works quite good but now I want to consider the velocity the View moved around the screen and when the user lifts his Finger off the screen, the UIView should not stop immediately to move to the endpoint, instead it should do it with a curve.
Edit 1
I think I expressed myself wrongly. I meant that the View should move the direction the user dragged it to but then it should make a curve and move to the desired position. Think of it like gravity. The user will drag the View with a speed from the left bottom corner to the middle of the screen and lifts immediately his finger. Then the View should not stop, else it should move in the last direction und slowly move to the desired location, which is in this case the right bottom corner.
This is the code I already have:
private void DidPan()
{
CGPoint translation = PanGesture.TranslationInView(this.Superview);
CGPoint velocity = PanGesture.VelocityInView(this.Superview);
if (PanGesture.State == UIGestureRecognizerState.Changed)
{
this.Center = new CGPoint(lastLocation.X + translation.X, lastLocation.Y + translation.Y);
}
else if (PanGesture.State == UIGestureRecognizerState.Ended)
{
// Calculates the new position the view will be moving to
var newLocation = new CGPoint(SetX(Superview.Bounds), SetY(Superview.Bounds));
// Animate it to the desired location
UIView.Animate(0.3, () =>
{
this.Center = newLocation;
}, null);
}
}
As you can see we already have the velocity but I don't know how to continue from here. Hopefully someone has the right starting point from here and could help me.
Thanks a lot!
I think UIKit Dynamics can meet your requirement.
refer to this Blog : https://blog.xamarin.com/drag-drop-and-snap-with-uikit-dynamics/

Scrollview in Spritekit using Swift Programmatically (no storyboard)

So I'm hoping to learn about making a scrollview of icons (kinda like a menu) in Spritekit, using Swift. I can't find any good resources or tutorials that don't charge.
I have my basic app set up with a ViewController and my scene.
I'm hoping to have a scrollview that's say 2 or 3 times longer than the height of the screen, where I can scroll up and down and view different icons.
I hope this would be a good implementation, so I can programmatically set all the icons using x/y coordinates.
My viewdidLoad:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
addChild(worldNode)
//create Scrollview
//for loop to adding icons from top to bottom of scrollview
//name sprites
//use touch location so allow sprites to be clickable
//will just adjust alpha of icon for testing purposes later
}
This is really all I'm looking at achieving at the moment, if you can imagine, something like this:
Some of the questions that I have seen here seem to go in far more detail than I imagine I need, and are too complex for me at this stage, or they are not in swift...
How can I include a scrollview?
Thank you in advance :)
If your entire UI is a scene built with SpriteKit, you may want to consider building it as if it were a scrolling scene with a camera. Here's an example in a gameplay context
Basically it could work like this:
var sceneCam: SKCameraNode! //declare your camera variable in your scene class
Then, in your didMoveToView function:
sceneCam = SKCameraNode() //initialize your camera
//scaleAsPoint lets you zoom the camera in and out
sceneCam.scaleAsPoint = CGPoint(x: 0.25, y: 0.25)
camera = sceneCam //set the scene's camera
addChild(sceneCam) //add camera to scene
//position the camera on the scene.
sceneCam.position = CGPoint(x: frame.center.x, y: frame.center.y)
Now, in your touchesMoved gesture handler, when you detect the pan, you can adjust the camera position to match the pan gesture translation.
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
let positionInScene = touch.locationInNode(self)
let previousPosition = touch.previousLocationInNode(self)
let translation = CGPoint(x: positionInScene.x - previousPosition.x, y: positionInScene.y - previousPosition.y)
sceneCam.position = CGPoint(x: sceneCam.position.x - translation.x, y: sceneCam.position.y - translation.y)
}
The other crucial part of the setup is just to make your scene the right size for your menu. This is a similar concept to your content size on a scrollview. You might also have some work to do to implement paging or similar UIScrollView features if you desire those. But if you just need a simple scrolling view, you could do it with a camera.
If you ONLY want UIKit elements on this view, it should probably just be it's own VC without a scene. You could even create this menu view controller and place it in a container on your game scene - that way you'd be using only UIKit components in your menu vc, but you can still use it in a SpriteKit setting.

Touch locations UIPinchGestureRecognizer

I'm trying to resize an image using the UIPinchGesture recognizer and in order to carry that out I need to find the location of the center point upon which the pinching is focused on.
Originally I thought about creating a midpoint calculation for the center point based on the two touched points. The problem is that for some reason the returned points using the touch indexes are not the touch locations that are applied on screen.
For example, when I tried zooming using a touch that was approximately at (333, 187) and another at (1000, 563) the returned locations of the touches were (496, 279) and (170, 95).
What exactly are UITouch 1 and UITouch 2 the indexes of? How can I find the center-point value?
func handlePinchGesture(gesture: UIPinchGestureRecognizer){
// Finds the midpoint location of the pinch gesture
var touch1 = gesture.locationOfTouch(0, inView: self.view)
var touch2 = gesture.locationOfTouch(1, inView: self.view)
var midPointX = (touch1.x + touch2.x)/2
var midPointY = (touch1.y + touch2.y)/2
var touchedPoint = CGPointMake(midPointX, midPointY)
}
How can I find the center-point value
You don't have to find it. The gesture recognizer gives it to you. It is the gesture recognizer's locationInView:.
You can use the following code to get the touch location:
#objc func onGesture(gesture: UIPinchGestureRecognizer) {
print("Location", gesture.location(ofTouch: 0, in: nil))
}
CGPoint centerPoint = [recognizer locationInView: self.view];
Apple says:
The returned value is a generic single-point location for the gesture computed by the UIKit framework. It is usually the centroid of the touches involved in the gesture.
This will give you the center. Hope this helps.. :)

swift: SKNode position not animating

I'm rotating a ball based on pan gestures, and I want to add inertia. To do this, I decided to use animateWithDuration when pan gesture finished. The problem is that instead of animating, the position of the ball changes straight away. I'll be posting the code bellow.
func moveByInertia(finalPosition: CGPoint, finalRotation: CGFloat)
{
UIView.animateWithDuration(2, animations:
{
self.tommy.position = finalPosition
self.tommy.zRotation = finalRotation
})
}
The arguments are definitely passed correctly into this function because it moves to the correct position. The problem is that it does so without animating. I couldn't find the same problem with a solution on the internet.
Thanks in advance

Press And Hold iPhone Screen

So I am working on an app for an iPhone and I need to detect if the player is holding the screen and I need to get the location of where they are pressing.
Originally I was using the touchesBegin function but that is only called when the screen is touched a new time. Is there a way that I can modify this to be called more often, like every time the the update function is called?
Another thing I looked into was the UILongGesture stuff, but I couldn't get the location of where it was pressed.
Any help/advice to figuring this out would be greatly appreciated.
I am being specific here on your question about how to get the location of where user tap,
- (void)handleTap:(UITapGestureRecognizer *)tapRecognizer
{
CGPoint touchPoint = [tapRecognizer locationInView: _tileMap] //locationInView is the method you need to try
}
Secondly, UIGestureRecognizer also gives you the state which may be useful in your case
UIGestureRecognizerStateBegan UIGestureRecognizerStateChanged
UIGestureRecognizerStateEnded
and so on.
Hope this helps
You were on the right track - are you using multitouch?
If not, all you need to do is set a variable when the user touches the screen, then clear that variable on the touches ended function. Using the update function would work but is a super inefficient way of doing it
I'm assuming you want something to happen when they keep their finger on the screen. You could schedule an event in say 2 seconds when they touch the screen, and then if they release the screen before that you just cancel the event.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInView(yourScrollView)
}
}
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
var currentLocation : CGPoint = CGPointMake(location.x+translation.x, location.y+translation.y)
recognizer.setTranslation(CGPointZero, inView: self.view)
}
This code finds the initial location of the touch, and then the new location whenever the touch is moved. However, no code will be called without using the touchesEnded method. I can't give you much more without knowing how you intend to use the touch.

Resources