Swift - PanGesture Recognizer - move with object - speed of movement - ios

I am using PanGesture Recognizer in Swift for iOS. Inside the action method, I am calling 3rd party method, that takes move direction and speed. From this, it calculates position of object:
objectPos += normalize(move) * speed
Problem is, that if I put my finger on a certain object and move with fingers, objects is not at the same position under my finger. It starts to move slower / faster. Moving directions are OK. Problem is with acceleration / decceleration - if I move faster, objects move faster.
In gesture callback I have tried:
let move = recognizer.translation(in: self.view);
let speed = sqrt((move.x * move.x) + (move.y * move.y));
and
let move = recognizer.velocity(in: self.view);
let speed = dt * sqrt((move.x * move.x) + (move.y * move.y));
Usually dt = 1.0 / 60.0. It is the gesture callback refresh rate (in code, I am calculating dt manually using difference of CFAbsoluteTimeGetCurrent()). Without this, If I use velocity directly to calculate speed, movement is too fast.
I have tried to calculate difference manually by subtracting current and last position, but still no luck.
I have also tried to "change speed" accoring to current view width and height, but none ot if worked. I am probably missing something, but dont know what.

It would be easier if you just computed the moves of the object based on acceleration when the user stops touching the object.
As long as the user has their finger on the object, it is much easier to just set the position of the object to the position you get from the pan gesture recognizer.

Ok... I have found the problem. Movement of th eobject it in screen normalized coordinates with corners [0,0] - [1,1]. So movement in Y axis (height) was correct, but in X axis (width) the speed was about half.
Multiply move.x with correct aspect ratio solved the problem. Basically, the moevement in X axis is enlarged manually.

Related

ScrollView.contentOffset.y can't move less than 0.333 pixel

I'm trying to create a teleprompter. Basically auto scrolling scrollView.
I'm moving my scrollView.contentOffset.y by 1 point/pixel every X time.
I'm giving the user the option to slow the animation down, and I want to do it by moving fewer points, not by increasing the time it takes to call for each pixel movement.
But I can't reduce the point size to less than 0.3333. When calling for a movement of 0.2 it's rounded up to 0.333, 0.1 is rounded down to 0 so I'm getting 0 movement. Why is that and how can I change it?
The offset is in points. On a 3x device, a single pixel is 0.3333 points. Obviously you can't scroll a partial pixel.
One solution that effectively gets around this issue is for you to keep your own value for the offset that you can increment in smaller values. Then update the scroll view's offset with your own running value. Don't try to add something like 0.1 or 0.2 to the scroll view's offset. Increment your own value and update the scroll view's offset. Of course the actual movement of the scroll view won't be as fined grained as your little updates but the overall scrolling will be slower.

Gravity not working correctly

My code for physics in my game is this:
-- dt = time after each update
self.x = math.floor(self.x + math.sin(self.angle)*self.speed*dt)
self.y = math.floor(self.y - math.cos(self.angle)*self.speed*dt)
-- addVector(speed,angle,speed2,angle2)
self.speed,self.angle = addVector(self.speed,self.angle,g,math.pi)`
when it hits the ground, the code for it to bounce is :
self.angle = math.pi - self.angle
self.y = other.y - self.r`
the function addVector is defined here:
x = math.sin(angle)*speed + math.sin(angle2)*speed2
y = math.cos(angle)*speed + math.cos(angle2)*speed2
v = math.sqrt(x^2 + y^2)
a = math.pi/2 - math.atan(y,x)
return v,a
but when I place a single ball in the simulation without any drag or elasticity, the height of the ball after each bounce keeps getting higher. Any idea what may be causing the problem?
Edit: self.r is the radius, self.x and self.y are the position of the centre of the ball.
Your Y axis is increasing downward and decreasing upward.
Making self.y = math.floor(..) moves your ball a bit upward every frame.
The solution is to store your coordinates with maximal precision.
You could make new variable y_for_drawing = math.floor(y) to draw the ball at pixel with integer coordinates, but your main y value must have fractional part.
I’ve managed to get your code to run and reproduce the behavior you are seeing. I also find it difficult to figure out the issue. Here’s why: movement physics involves position, which is affected by a velocity vector, which in turn is affected by an acceleration vector. In your code these are all there, but are in no way clearly separated. There are trig functions and floor functions all interacting in a way that makes it difficult to see what role they are playing in the final position calculation.
By far the best and easiest-to-understand tutorial to help you implement basic physics lime this is The Nature of Code (free to read online, with interactive examples). As an exercise I ported most of the early exercises into Lua. I would suggest you see how he clearly separates the position, velocity and acceleration calculations.
As an experiemnt, increase g to a much higher number. When I did that, I noticed the ball would eventually settle to the ground, but of course the bouces were too fast and it didnt bounce in a way that seems natural.
Also, define other.y - it doesnt seem to affect the bouncing issue, but just to be clear on what that is.

ScrollView in SpriteKit

I have found a few other questions and answers similar to this, but none of them quite work perfect for me.
My vision is to have a horizontal scrollable view at the bottom of the screen where I can scroll through what will look like cards in a hand. Ideally, I could eventually make the card in the middle scaled up a bit and give it a highlighted look to show the user which card is selected. Even better would be if I could figure out how to keep the scroll view resizing to fir the number of sprites (cards) in the view.
Anyways, I am still very new to XCode and Swift, so it is hard for me to take what I find and change it. But, I am hoping to learn fast.
What I understand so far is that a UIScrollView could overlay the scene and with a moveable spritenode I could scroll through the view. The view would then translate the coordinates somehow to the SpriteKit Scene to move the sprites that will look like they are in the view. I think that's how it works. Any help would be great. I am pretty stuck. <3
You have to make your own logic that takes place in touchesMoved() using a global/member variable.
Unfortunately, a lot of gamedev and SK is math and logic.. You have to come up with your own problems and solutions.. There is no manual because the possibilities in programming and Swift are endless :)
Moving the cards:
Basically, you compare each touch location to the last one, and this becomes a "delta value" that you can use to perform actions.
Example, if I touch in the center of the screen, my touch location is 0,0 (or whatever your anchorpoint is set to). If I move my finger right, then I'm now at say 25, 0... This creates a "delta value" of +25x.
With that delta value, you can perform various actions such as moveBy for all the cards... so if I have a deltaX of +25, then I need to move all of the card nodes to the right (by a certain amount that you will determine according to your preferences). If I have a deltaX of -25, I move the cards to the left by a certain amount.
Where you do the actual moving is up to you--you could put a function in update() or touchesMoved() that constantly moves the cards a certain direction at a certain rate of that deltaX value..
Ok that was a mouthful... Maybe this will help:
for touch in touches {
myGlobalDeltaX = myDeltaXFunc(currentTouch: touch)
myMoveFunc(cards: allTheCards, byDeltaX: myGlobalDeltaX)
- You can search on how to make a Delta function, but it really is just the same thing from Algebra.
- myMoveFunc can be something as simple as iterating through all of your card nodes then running .moveBy on them at the same time.
Middle detection:
To detect which card is in the center, you would put in touchesEnded() or update() a call to check the name / identity of the node in the center of the screen... so something like
// `self` here refers to your GameScene class' instance, which is just an `SKScene` object
let centerX = self.frame.midX
let centerY = self.frame.midY
let center = CGPoint(x: centerX, y: centerY)
let centerNode = self.nodes(at: center)
You would obviously want to change centerX and centerY to wherever it is you want the middle card to be :) Right now, this is just in the dead-center of the screen.
Once you have a centerNode, you would then just need to do whatever function you have created to "select" it.
let selectedCard = centerNode
mySelectionFunc(middleCard: selectedCard)
This may look like a lot, but I drew out the steps to make understanding it a bit easier.. You can do all of this in one line if desired.
mySelectionFunc(middleCard: self.nodes(at: CGPoint(x: self.frame.x, y: self.frame.y)))
Hope this helps some!

Snake game movement issue Spritekit

I am trying to create a basic snake game using Swift and Spritekit. I have a sprite moving on the screen and when i swipe it starts moving in the swipe direction. I do this in the update method where I change the position of the sprite based on the swipe direction, a set speed and a fixed duration.
e.g. direction.x * blockMovePerSecond * CGFloat(actionDuration)
I have the sprites following each other, however, as soon as i swipe and the first sprite changes direction, the one following it moves diagonally instead of first on the x-axis and then the y-axis like a normal snakes game.
I tried the following options:
Tried keeping the distance that the sprite moves on each update equal
to the distance between the two sprites. However, the sprite runs off
the screen when i do that.
Made the first sprite create a path for the rest of the sprites to follow. However, the second sprite
runs off the screen and never shows up again. I think the problem is
because the path is open.
Here's my move method code for the sprites following the first sprite (snake head):
{
var temp:NSValue = lastNodeLocation // the lastnodelocation is from first sprite location
var tempNodeDirection = lastNodeDirection
let actionDuration = 1.0
let distanceToMoveThisFrame = tempNodeDirection.CGPointValue() * blockMovePerSecond * CGFloat(actionDuration)
var currentPosition = NSValue(CGPoint: blocksOfAlphabets[i].position)
let beforeDistance = CGPoint(x: temp.CGPointValue().x - currentPosition.CGPointValue().x, y: temp.CGPointValue().y - currentPosition.CGPointValue().y)
lastNodeLocation = NSValue(CGPoint: blocksOfAlphabets[i].position)
// move node to new location
var moveAction = SKAction.moveTo(temp.CGPointValue(), duration: 1.0)
node.runAction(moveAction)
}
Can somebody please help?
Thanks
Shuchi
Well your problem is that the runAction-methods don't wait to complete. So if you call another runAction-method while a sprite is already running an action, the new action will be started immediately.
You can work with sequences to finish the x-axis first: SKAction:sequence
I think the easiest thing to do here is to keep an array of snake sprite components (let's call these sprites a "Rib").
Every 5 seconds add a new Rib to the end of the array to make the snake grow.
Then, each half second in the update() method (or however long you want it to be):
check for any swipes that have happened since the last update and change direction of the first rib (the snake head) in the direction of the swipe.
now run through the snake array in reverse and set the location of node (n) to the node position of node (n-1).
There are other ways you could do it but I think this would be the easiest.

How to measure acceleration and deceleration of a vehicle?

Given the following data
Orientation of the device (CMAttitude - Quaternion or Rotation Matrix)
Acceleration Vector (CMAcceleration - userAcceleration --> without gravity)
Is there a way to get the acceleration and deceleration of a car placing the device in an arbitrary orientation into the car?
If not what would be the best approach to get the acceleration and deceleration by positioning the device in a fixed position inside the car?
Any hints or solution approached would be highly appreciated.
Thanks in advance!
Edit:
I tried to implement the suggested approach from this answer Using CMDeviceMotion and CMAttitude to isolate vertical or horizontal acceleration to isolate the vertical and horizontal acceleration.
I set the reference frame to CMAttitudeReferenceFrameXMagneticNorthZVertical
//Quaternion Conjugation
CMQuaternion quaternion = newMotion.attitude.quaternion;
GLKQuaternion conjugated_quaternion = GLKQuaternionMake(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
conjugated_quaternion = GLKQuaternionConjugate(conjugated_quaternion);
//Rotation of Accelerometer vector with quanternion
GLKVector3 acceleromationVector = GLKVector3Make(newMotion.userAcceleration.x, newMotion.userAcceleration.y, newMotion.userAcceleration.z);
GLKVector3 accelerometionVector_toReferenceFrame = GLKQuaternionRotateVector3(conjugated_quaternion, acceleromationVector);
//Horizontal Acceleration
float horizontalAcceleration = sqrtf(powf(accelerometionVector_toReferenceFrame.x,2)+powf(accelerometionVector_toReferenceFrame.y,2));
In the suggested answer the reference frame which should be used is North-East-Down. Would this be the same than CMAttitudeReferenceFrameXMagneticNorthZVertical? Or could it be that this is the wron reference frame and thus the results of this implementation turn out to be wrong?
You're looking for an algorithm not a functionality in the device itself. I don't believe there is a feature in any apple's iDevice that allows you to get the current ** deceleration/acceleration**
Use The Kinematic Equations: a = (Vf - Vi) / t
a: Acceleration
Vf: final velocity
Vi: initial velocity
t: time difference between Vi and Vf
This is what I would do to get the de/acceleration:
Calculate Vf = d/t say the car moves for a 10 km (this is d distance in meters) in 10 seconds (this is t time in seconds) you should be able get the final velocity Vf.
Assume Vi = 0 at first calculation then keep track of it by assigning current-Vi = previous-Vf
Calculate de/acceleration a = (Vf - Vi) / t
Remember deceleration is just a negative acceleration
Edit: You can also use userAcceleration defined in CMDeviceMotion.h

Resources