Why my sprite keeps flipping right when I move it left? - ios

I have a sprite that scales to 1 or -1 when moving right or left, if I move fast the finger it works fine, if I drag it slowly it doesn't stay in the left position and keeps flipping left and right. How can I solve it? This is how I handle the character movement:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
player.run(SKAction.move(to: CGPoint(x: playerPosition.x + location.x - startTouch.x, y: self.frame.height/2.5), duration: 0.1))
}
let touchLoc = touch!.location(in: self)
let prevTouchLoc = touch!.previousLocation(in: self)
let deltaX = touchLoc.x - prevTouchLoc.x
player.position.x += deltaX
player.xScale = deltaX < 0 ? 1 : -1
}

//set x flip based on delta
if deltaX < 0 {
player.xScale = -1
} else if deltaX > 0 {
player.xScale = 1
}
Don’t change xScale if deltaX is 0

Related

How can I flip horizontally a sprite when moving left or right?

In my SpriteKit project I have a boat that I drag left and right to catch items falling from the sky, I would like the boat to look in the direction it's moving, I think I have to change xScale from CGFloat(1) to CGFloat(-1) but I don't know how, any suggestion is appreciated, this is how I handle the boat movement:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
node.run(SKAction.move(to: CGPoint(x: nodePosition.x + location.x - startTouch.x, y: nodePosition.y + location.y - startTouch.y), duration: 0.1))
}
}
inside touchesMoved you can use touch.location and touch.previousLocation to determine a change in the x position. then if the delta x is positive or negative you can flip your xScale accordingly.
//grab current and previous locations
let touchLoc = touch.location(in: self)
let prevTouchLoc = touch.previousLocation(in: self)
//get deltas and update node position
let deltaX = touchLoc.x - prevTouchLoc.x
let deltaY = touchLoc.y - prevTouchLoc.y
node.position.x += deltaX
node.position.y += deltaY
//set x flip based on delta
node.xScale = deltaX < 0 ? 1 : -1

SpriteKit: calculate angle of joystick and change sprite based on that

I am making a RPG Birds-eye style game with SpriteKit. I made a joystick because a D-Pad does not give the player enough control over his character.
I cannot wrap my brain around how I would calculate the neccessary data needed to change the Sprite of my character based on the angle of the joystick thumb Node.
Here is my code I am using
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if isTracking == false && base.contains(location) {
isTracking = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location: CGPoint = touch.location(in: self)
if isTracking == true {
let v = CGVector(dx: location.x - base.position.x, dy: location.y - DPad.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / Double.pi)
let Length:CGFloat = base.frame.size.height / 2
let xDist: CGFloat = sin(angle - 1.57079633) * Length
let yDist: CGFloat = cos(angle - 1.57079633) * Length
print(xDist,yDist)
xJoystickDelta = location.x * base.position.x / CGFloat(Double.pi)
yJoystickDelta = location.y * base.position.y / CGFloat(Double.pi)
if base.contains(location) {
thumbNode.position = location
} else {
thumbNode.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)
}
}
}
}
Update method
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if xJoystickDelta > 0 && yJoystickDelta < 0 {
print("forward")
}
}
The way I have set up right now tests the positive or negative state of the Joystick position in a cross method based on where the thumb Node is inside of the four marked sections below
I dont want it to do that
How can I set it up so that it changes the sprite based on where the thumb node is actually pointing inside my joysticks base like so.
I have been struggling with this for 3 days now so any help would be appreciated.
That looks far too complicated. Just compare the x and y components
of the difference vector v. Something like this:
if v.dx > abs(v.dy) {
// right
} else if v.dx < -abs(v.dy) {
// left
} else if v.dy < 0 {
// up
} else if v.dy > 0 {
// down
}

Moving SKSpriteNode in a semi circle with a virtual joystick

I am making a game that contains a virtual joystick. My joystick is composed by two SKSpriteNode, one for the stick the other for the base panel. ( see the picture below )
Obviously my joystick can only be moved following the green semi-circle on the panel.
My problem here is that i'm trying to make it happen, here is my code for now:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
guard isTracking else {
return
}
let maxDistantion = panel.radius
let realDistantion = sqrt(pow(location.x, 2) + pow(location.y, 2))
let needPosition = realDistantion <= maxDistantion ? CGPoint(x: location.x, y: location.y) : CGPoint(x: location.x / realDistantion * maxDistantion, y: location.y / realDistantion * maxDistantion)
if (needPosition.y > 0) {
stick.position = needPosition
} else {
stick.position = CGPoint(x: needPosition.x, y: 0)
}
data = AnalogJoystickData(velocity: needPosition, angular: -atan2(needPosition.x, needPosition.y))
}
}
With this code, I can move into the semi-circle, but I would to only move my stick onto the green line, if someone can help me with my poor mathematics
Thank you

Calculate rotation velocity and naturally rotate view iOS

I have a circle-shaped view and have it rotate via the following code overriding touchesBegan(touches:, withEvent:) and touchesMoved(touches:, withEvent:).
var deltaAngle = CGFloat(0)
var startTransform: CGAffineTransform?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
let touchPoint = touches.first!.locationInView(view)
let dx = touchPoint.x - view.center.x
let dy = touchPoint.y - view.center.y
deltaAngle = atan2(dy, dx)
startTransform = arrowPickerView.transform
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
{
let touchPoint = touches.first!.locationInView(view)
let dx = touchPoint.x - view.center.x
let dy = touchPoint.y - view.center.y
let angle = atan2(dy, dx)
let angleDifference = deltaAngle - angle
let transform = CGAffineTransformRotate(startTransform!, -angleDifference)
arrowPickerView.transform = transform
}
I want to override touchesEnded(touches:, withEvent:) to calculate the velocity and have the view naturally rotate a little (similar to continuous scrolling). I currently save the original transform and calculate the delta angle. How can I implement this? Thanks in advance!
In my example below, the CGAffineTransformRotate depends on:
direction (if the user moves from left to right, up or down etc)
rotation (a factor dependent on the time between touchesBegan and touchesEnded)
PI
This creates an CGAffineTransformRotate and this rotates with duration 1 (s), to create a feel of kinetic scrolling the UIViewAnimationOptions.CurveEaseOut property is used
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touchPointEnd = touches.first!.locationInView(view)
self.dateTouchesEnded = NSDate()
let delay : NSTimeInterval = NSTimeInterval(0)
let timeDelta : Double = self.dateTouchesEnded!.timeIntervalSince1970 - self.dateTouchesStarted!.timeIntervalSince1970
let horizontalDistance : Double = Double(touchPointEnd.x - self.touchPointStart!.x)
let verticalDistance : Double = Double(touchPointEnd.y - self.touchPointStart!.y)
var direction : Double = 1
if (fabs(horizontalDistance) > fabs(verticalDistance)) {
if horizontalDistance > 0 {
direction = -1
}
} else {
if verticalDistance < 0 {
direction = -1
}
}
let rotation : Double = (0.1 / timeDelta < 0.99) ? 0.1 / timeDelta : 0.99
let duration : NSTimeInterval = NSTimeInterval(1)
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseOut, animations: {
let transform = CGAffineTransformRotate(self.imageView.transform, CGFloat(direction) * CGFloat(rotation) * CGFloat(M_PI))
self.imageView.transform = transform
}, completion: nil)
}
I added the variables to keep track of the start and end time of touches and added the CGPoint location of the touchesBegan function
var dateTouchesStarted : NSDate?
var dateTouchesEnded : NSDate?
var touchPointStart : CGPoint?
In touchesBegan i added:
self.touchPointStart = touchPoint
To set the variable as explained above.

Move the object in a specific area

I have a circle called circle and a line called ground in the View.
I can drag & move the circle in the whole view, but when I try to limit it (in the code) to move only under the ground area - it works (when I try to drag it above the ground) and the circle moves only by my x location dragging, BUT when I try to drag it back under the ground - the circle only moves by the x location dragging and the y location dragging doesn't change (the y is the ground y).
How can I make it move back again, in a free way, under the ground and not only by the x location of the dragging?
Here is what I tried so far:
let ground = SKSpriteNode()
var circle = SKShapeNode(circleOfRadius: 40)
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// ground.physicsBody?.dynamic = false
ground.color = SKColor.redColor()
ground.size = CGSizeMake(self.frame.size.width, 5)
ground.position = CGPoint(x: CGRectGetMidX(self.frame), y: self.frame.size.height / 5)
self.addChild(ground)
circle.position = CGPointMake(CGRectGetMidX(self.frame) ,CGRectGetMinY(ground.frame) - (circle.frame.size.height / 2))
circle.strokeColor = SKColor.blackColor()
circle.glowWidth = 1.0
circle.fillColor = SKColor.orangeColor()
self.addChild(circle)
}
var lastTouch: CGPoint? = nil
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
if circle.position.y < ground.position.y - (circle.frame.size.height / 2){
circle.position = touchLocation
} else {
circle.position.x = CGFloat(touchLocation.x)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
if circle.position.y < ground.position.y - (circle.frame.size.height / 2) {
circle.position = touchLocation
} else {
circle.position.x = CGFloat(touchLocation.x)
}
}
I have solved it:
In touchesMoved func I wrote this code:
for touch in touches {
if touchLocation.y < ground.position.y {
circle.position = touchLocation
} else {
circle.position.x = touchLocation.x
}
}

Resources