Giving a physicsBody a constant force - swift

I have a ball bouncing up and down. I've accomplished this by setting it's physics body up like this:
linearDamping = 0
friction = 0
restitution = 1
And then just applyForce(CGVectorMake(0, 10)) in the setup call. The ball is now bouncing up and down, up and down with not interruption.
Now I want to add player control. The player can move the ball sideways. I could do this by just setting the balls velocity when the controls are pressed. BUT by doing that I lose all the stuff the physics engine gives me.
Here's a short snippet of code I have right now:
override func update(currentTime: CFTimeInterval) {
/* Apply damping only in x */
if !movingLeft && !movingRight {
let dx = ball!.physicsBody!.velocity.dx * xAlpha
let dy = ball!.physicsBody!.velocity.dy
ball!.physicsBody?.velocity = CGVectorMake(dx, dy)
}
if movingRight {
ball!.physicsBody?.applyImpulse(CGVectorMake(ballVelocityX, 0))
}
if movingLeft {
ball!.physicsBody?.applyImpulse(CGVectorMake(-ballVelocityX, 0))
}
}
The problem, as you might imagine, is that applying impulse upon impulse on each frame like this makes the ball go superfast, which is not what I want, when the controls are held down. But if I apply the force only on keyDown the ball will stop moving in that direction once the ball hits something. And also the keyDown event works wonky on OS X (because of key repeat settings).
So what I want to do is apply an impulse in the update function in a way that makes the force of the ball not exceed my limit but also not go away completely if the ball hits something.

Related

SpriteKit - Bouncing node constant speed/velocity?

Simple setup - I have bouncing ball nodes (blue) and static ball nodes (green). The grey box has Physics body SKPhysicsBody(edgeLoopFrom: box.frame), so it limits the bouncing ball from moving outside. I set the bouncing balls node (blue) velocity to a random CGVector upon creation and it starts moving. It bounces off the static ball node (green), and off the edges of the grey box.
My general SKPhysicsBody setup with all nodes is:
node.physicsBody?.restitution = 1
node.physicsBody?.friction = 0.0
node.physicsBody?.linearDamping = 0.0
node.physicsBody?.angularDamping = 0.0
My question is: How do I make sure the bouncing ball does move at a constant speed? After a couple of bounces, the node is either speeding up, or slowing down.
In order to achieve this, I normalized the vector whenever the physics engine detects a collision. So in func didBegin(_ contact: SKPhysicsContact), the following happens:
let length = hypotf(Float(node.velocity.dx), Float(node.velocity.dy))
let multiplier = (290.0 / length)
firstBody.velocity.dx *= CGFloat(multiplier)
firstBody.velocity.dy *= CGFloat(multiplier)
290.0 is an arbitrary value that determines the speed of ball.
For reference, check this answer.

Swift 2: Removing Slowly increase of speed

I am trying to effect the movement speed of a sprite in my app. When i apply velocity to the sprite it slowly increases in speed until it reaches a maximum speed. I am looking for a method to remove the smooth increase in speed and just have the exact same speed all the time (Until i change the velocity)
Feel free to add a comment if you have any questions.
enemy1 = SKSpriteNode(texture: enemyTexture)
enemy1.position = CGPoint(x: CGRectGetMidX(self.frame) - 300, y: CGRectGetMidY(self.frame) - 300)
enemy1.physicsBody = SKPhysicsBody(texture: enemyTexture, size: enemyTexture.size())
enemy1.physicsBody!.affectedByGravity = false
enemy1.physicsBody!.allowsRotation = false
self.addChild(enemy1)
This is the velocity i apply to the sprite. I am doing it in the update function for a continuing movement speed:
override func update(currentTime: NSTimeInterval) {
enemy1.physicsBody!.velocity = CGVectorMake(70, 0)
}
Instead of changing the velocity, have you tried to apply force vector for each update like this:
override func update(currentTime: NSTimeInterval) {
enemy1.physicsBody!.applyForce = CGVectorMake(70, 0)
}
I tried your code and it works correctly for me (sprite has a constant speed from the very beginning). It always worked like that. You can check this by pasting your code in an empty SpriteKit project. Currently, what you have described looks like you are actually using applyForce method rather than changing velocity vector directly.
The solution certainly is to change velocity property directly, like you are saying that you are doing right now. Probably you are overwriting this behaviour somewhere in your code accidentally, because what you have described isn't reproducible (with the code you've provided).

Check when an SKSpriteNode passes a certain point or line

In my game, there is an SKSpriteNode, which we will call a "gate," that is moving upwards in the scene. When the gate reaches the top of the screen, it moves back down to the bottom and begins traveling upwards again.
The way the player loses is if the character, which is located at a constant y position towards the top of the scene, collides with the gate. I have the collision and 'death' all worked out, but now I need to check if the character successfully passed 'through' the gate (meaning the gate moved past the character without hitting him). Basically, I need to know how to check when one moving node crosses a certain y position (in this case, that position is the character's y position). If this occurs, I want to increase the score by one.
Here is a rough sketch of the situation:
(click here for the rough sketch)
One thing I have tried is in the update method, if the gate's y position ever equals the character's y position, I know the two nodes have crossed, so I should increase the score. It looks like this:
override func update(currentTime: CFTimeInterval) {
if gate.position.y == character.position.y {
print("score")
score++
}
}
but doesn't seem to work. Is there any other way to check when the gate crosses the character's y position?
Thanks!
What may be happening is that the y coordinates aren't the same. For example if gate.position.y = 100, and character. position.y = 101, it won't work. Try this:
override func update(currentTime: CFTimeInterval) {
let minY = gate.position.y - 10
let maxY = gate.position.y + 10
if character.position.y > minY && character.position.y < maxY {
print("score")
score++
}
}
You can adjust the number 10 to see what works best. Hope this helps

How to track node movement after contact in SpriteKit

I have a ball node and a hole node. I want to detect when will the ball fall into the hold.
Currently I'm using didBeginContact, but it only gives me the distance of two nodes at the begin of contact, in which case the ball won't necessarily fall into the hole (it falls when distance between two centers < hole's radius).
Is there a way I can track the position of the ball after the contact had happened?
You can add invisible SKSpriteNodes and track when the ball touches them. You would have node1 just in top of the hole (a zone that the ball MUST go through - or touch - before entering the hole) before going into the hole, and node2 just after the hole (again, a zone that the ball MUST go through - or touch - after entering the hole).
If the ball touches node1 but not node2, you know it was almost going into the hole but then it didn't. If the ball touches node2, you know the ball is trying to go through the hole from the bottom part.
I guess you can make a physics body of a hole a lot smaller. That way, when contact occurs, you will be sure that ball can fall into a hole. Take a look at this picture (second example):
On top of that as an additional idea, when contact is detected, you can let ball to move little more, and then scale it down to make impression of falling.
There is no need to test for a contact between the ball and the hole, since it doesn't tell you if the objective was completed. Alternatively, you can simply add a check in didSimulatePhysics to see if the ball is sufficiently close to the hole before starting the falling animation sequence. For example,
override func didSimulatePhysics() {
let dx = ball.position.x - hole.position.x
let dy = ball.position.y - hole.position.y
let distance = sqrt(dx*dx+dy*dy)
if (distance < hole.size.width / 2.0) {
// Start falling animation sequence
}
}
Optionally, you can test if the ball is moving fast enough to skip over the hole by
override func didSimulatePhysics() {
let dx = ball.position.x - hole.position.x
let dy = ball.position.y - hole.position.y
let distance = sqrt(dx*dx+dy*dy)
if (distance < hole.size.width / 2.0) {
// Check if the ball is moving fast
let vx = ball.physicsBody!.velocity.dx
let vy = ball.physicsBody!.velocity.dy
let speed = sqrt(vx*vx+vy*vy)
if (speed < minSpeedToSkipOverHole) {
// Start falling animation sequence
}
}
}
This problem is solved by this: I maintain a possible_falling_list of all contacted holes for each ball and use another timer to frequently check if a ball is falling into any hole. Since the list is small for each ball, the performance is not an issue.

Move Object by dragging (mobile) makes the balls fall from the cup

I have this cup that contains balls inside. All 2D
I am using Rigidbody2d and Collider2d.
When running in unity and moving the cup (with arrow keys) the balls stay inside the cup. I also added drag movement for Android touch to move the cup.
The problem is that when moving the cup too fast (by draging) the balls fall from the cup collider (using Polygon colider 2d).
Code for movement is:
public float speed = 0.1F;
void Update() {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
transform.Translate(-touchDeltaPosition.x * speed, -touchDeltaPosition.y * speed, 0);
}
}
I tried to play with the speed parameter but it wont really help. if the cup movement is too slow it is not very useful for me.
I believe it is related the velocity/force of the ball or cup which makes the cup collider miss...
Any help on this would be appreciated greatly!
it is because you are moving it by changing the position of the cup, that means that when you move it fast, it disappears, and reappears where you dragged it, leaving the balls behind, and then they fall. I had the same thing where my objects would just go through the walls and out of the camera area. I fixed that by using AddForce. This makes the cup move, position by position over to where you dragged. this bumps the balls along, and they stay in the cup. This is what I guess is going on. If you use velocity that would work to.
you could rather than transform.Translate, you could find the vector to where you want to move to.
var direction = touchDeltaPosition - transform.position;
gameObject.rigidbody2D.velocity.x = direction.x * speed;
gameObject.rigidbody2D.velocity.y = direction.y * speed;
hope this solves it
The problem is that, when you're moving the cup too fast, at Frame 1 the ball is inside the cup, but at Frame 2 it's outside. You can reduce the value of "Fixed Timestep" (http://docs.unity3d.com/Manual/class-TimeManager.html) to increase the frequency of the physics calculations, or make the colliders larger.
If a ball in the cup will always stay in the cup, maybe you can turn off the physics of the ball once it's in the cup, or something along those lines.
Usually transform.Translate() is not very efficient when dealing with colliders, instead, you can try three other solutions:
1) rigidbody2D.AddForce(Vector2.Up * Input.GetAxis("Vertical"));
2) rigidbody2D.velocity = new Vector2(//write what you need);
3) which I consider the best solution for dealing with colliders and dragging is : MoveRigidbody2D
Well, this is what worked for me:
var newVec = new Vector2 (transform.position.x, transform.position.y);
var touchDeltaPosition = Input.GetTouch(0).deltaPosition*touchSpeed;
var direction = touchDeltaPosition- newVec;
rigidbody2D.AddForce(direction);