Smooth sprite movement in SpriteKit - ios

Hi I'm making a game in Swift with Sprite Kit and I'm wondering if there is a way to have a sprite have smooth movement. Currently I'm using the moveTo method in SKAction and the sprite gets to the target location in a set period of time - meaning that if the location is farther away, the sprite will get there faster. I'm wondering if there is a solid way of getting the sprite to accelerate to a maximum set speed and then slow down when getting to the location. All help is appreciated.

Use the Pythagorean theorem to get the correct duration based on distance in order to get desired speed. See here: https://stackoverflow.com/a/19126642/431271
as far as slowing at the end goes, you can do some quick built in easing methods like this:
var moveAction = SKAction.moveByX(moveX, y:moveY, duration:0.5);
moveAction.timingMode = SKActionTiming.EaseInEaseOut
node.runAction(moveAction)
And if you want other easing methods use libraries such as the one referenced here

Related

SpriteKit & Swift Ball Speed

I have made a game using SpriteKit and Swift 3 and have figured out all aspects of the game except the speed of the ball node in the game. Im confused with the different function applyImpulse() and ball.physicsBody.velocity, as I have tested both and don't seem to really understand what the speed I'm actually programatically settings is. Any clarification on what I should be using would be great?
Also whilst testing (by printing the ball's velocity to the console every collision) I would see sometimes the ball's speed would simply go to some long and random decimal value when it hit other nodes such as a paddle which I hadn't specifically coded anything to happen with the ball's speed in the case of a collision with it.
In summary I would appreciate:
Just general clarification regarding speed of the ball in SpriteKit and how I should approach it (what method/function I should use)
How I would make it so the ball's speed doesn't got to these very long random decimals
Thanks
In regards to the values, there is not really a set rule of what the values are for impulses and forces. It depends on how big your sprites physics body are etc. An impulse of 80 might be a perfect jump value for 1 sprite size, but than make it half the size and that 80 is suddenly way to high. There are also factors such as gravity, mass etc than can have an effect on this.
So you usually just play around with the values until you get the desired result.
In regards to the collision with the paddle, you need to check your bit mask values and your dynamic properties. SpriteKit by default sets collisions to all objects, so if you dont specifically tell your paddle/ball to ignore each other they will collide.
There are also things such as restitution, friction, damping etc that can have an effect on how you sprites behave when colliding.
There are loads of tutorials on google about SpritKit physic/collisions or read the apple documentation.
In regards to the difference between velocity and impulses/forces, as per apples documentation
"First, you can control a physics body’s velocity directly, by setting its velocity and angularVelocity properties. As with many other properties, you often set these properties once when the physics body is first created and then let the physics simulation adjust them as necessary. For example, assume for a moment you are making a space-based game where a rocket ship can fire missiles. When the ship fires a missile, the missile should have a starting velocity of the ship plus an additional vector in the direction of the launch.
When a body is in the simulation, it is more common for the velocity to be adjusted based on forces applied to the body. Another source of velocity changes, collisions, is discussed later."
https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Physics/Physics.html
So basically the general rule of thumb is this:
1) Only set the velocity property when you create the physics body. I never needed to do this for my games yet.
The only time I really use the velocity property is for things such as double jumping where I need to set it to 0 to have a consistent double jump
...velocity.dy = 0
...applyImpulse(
2) When you are playing the game already than
a) If you are trying to continuously move your ball you should use
applyForce...
in something like the update method of your SKScene.
b) If you want to make your ball jump, so basically a short 1 time thing, you should use
applyImpulse...
Hope this helps

Sometimes sprite is pushed away when touches another sprite

I am making a game using cocos2d and SpriteBuilder. There is a hero sprite and coins, that should be collected by him. That's a horizontal scrolling game, so every time hero touches a coin, this coin changes it's x-coordinate 2000px to the right and new y-coordinate is generated at random. Using update method I move it to the visible area as a "new" coin. But when hero flyies by and doesn't collect it ,coin must change coordinates only when it's already off the screen, so I tried this solution:
-(void)update:(CCTime)delta{
_coin.position=ccp(_coin.position.x - delta * scrollSpeed, _coinY);
if (CGRectIntersectsRect(_hero.boundingBox,_coin.boundingBox)) {
_coinY=arc4random() % 801 + 100;
_coin.position=ccp(_coin.position.x + 2000.f,_coinY);
}
else if(_hero.position.x >= _coin.position.x + 150){
_coinY=arc4random() % 801 + 100;
_coin.position=ccp(_coin.position.x + 2000.f,_coinY);
}
It works,but after that I found a small bug(I am not sure, whether it's related to this code) : sometimes, when hero touches coin, hero is like pushed away to the left. I have no idea why.
How to fix it?
Is that way, that I am using for coin ,right?
I see 2 issues with your approach:
1. Hero bounces of the coin.
To fix this you need to make your coin a sensor. This way you will still be notified about collisions, but the hero will simply pass through the coin without actually hitting it.
I'm not sure if you can set this in SpriteBuilder, but probably you can enumerate all coins after loading the scene and set sensor property to YES:
coin.physicsBody.sensor = YES;
Things like this is one of the reasons I believe you first need to learn pure Cocos2D and only then use tools making your life easier such as SpriteBuilder. Which is a great tool, but in some cases you still need know what happens behind the scenes.
2. You're mixing physics with things like CGRectIntersectsRect
If you're using physics engine you need to detect collisions via collision delegate and not by checking CGRectIntersectsRect in update:.
It is hard to explain how to do this in a few sentences, so here is a nice tutorial that shows how to detect collisions in Cocos2D v3 and of course there is a chapter about this in my book.
By the way you shouldn't use update:at all when manipulating physics nodes, use fixedUpdate: instead.
I hope this will help you to solve your issue.

Sprite kit ios game slingshot machanism similar to angry bird game

I am newbie in IOS Gaming, and i need to create a game using Sprite Kit framework for functionality similar to angry bird pulley system, and also wants to find the distance the object is travelled from the pulley to its landing.
Can anyone help me out with this, i would be thankfull for it.
Thanks in advance.
One way you could code a slingshot effect would to use a starting point on the screen at let's say (x=100,y=100). You would display a SpriteNode of a slingshot with the Y centered at the (100,100).
The next step would be to use touchesBegan:withEvent: in the area of the slingshot to let your code know the player is looking to shoot the slingshot.
You would use touchesMoved:withEvent: to track how far back (how much tension) the player is pulling back from the slingshot.
The release would be triggtouchesEnded:withEvent. Based on how far the touch began (x=100) and how far back is was released (for example x=30), you can apply force like this:
float forceUsed = startTouchX - endTouchX;
[_projectile.physicsBody applyForce:CGVectorMake(forceUsed, 0)];
If you are looking to angle the shot you would also have to track Y and use that variable instead of the 0 above.
As for calculating distance between 2 points on the screen, it boils down to x and y coordinates. Subtract objectA.position.x from objectB.position.x
Things can get a lot more complex of course but that all depends on what you want to do in your code. Hope this helps.
P.S. The touches above are all part of the UIResponder Class.

Filtering collisions in Chipmunk for trapped bodies

Background
I'm making an iOS app for kids where you can use your finger to drag balls around on a screen.
I'm using Chipmunk 7.0.0 for the physics simulation.
I've adapted the Chipmunk demo code to implement the dragging functionality.
I'm using 2 ms fixed time step. (It's not like my app has anything better to do...)
Issue
I've recently added code to play a sound whenever the balls collide with each other or with a wall, which I'm doing inside a postSolve callback:
static void postSolve(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
{
GameLayer *layer = (__bridge GameLayer *)userData;
[layer collisionHandler:arb];
}
-(void) collisionHandler:(cpArbiter*)arb
{
if(cpArbiterIsFirstContact(arb)) {
[[SimpleAudioEngine sharedEngine] playEffect:kCollisionEffectFilename];
}
}
Here's the problem... When I drag a ball into a wall, it generates a very large number of collisions, even when filtering on cpArbiterIsFirstContact, and it sounds terrible. It appears that the ball is bouncing off the wall, being driven back into wall by the constraint, rinse, and repeat. I'd like to play the collision sound only once or twice in this scenario.
Things I've tried that don't seem to work...
Filtering using cpArbiterTotalKE, cpArbiterTotalImpulse, or relative velocity: Impulse, kinetic energy, and relative velocity are all in the range of typical collisions.
Using a separate callback: The ball really is bouncing off the wall multiple times.
Reducing the step size: The physics engine actually takes longer to converge.
Rate limiting the sound effects: Better, but the ball still makes noise even after it looks like it's stationary.
Question
Is there a way to filter collisions for trapped bodies?
A simple and effective solution is to avoid playing the sound in quick succession.
When the ball contacts with the wall, check if the ball's "last contact" timer is lower than the current time. If so, play the sound and set the ball's "last contact" time to the current time plus x, where x is the timeout duration the sound shouldn't play again (ie 0.5 seconds).
In cocos2d-iphone you can add up an update method's deltaTime to keep track of time. There are also a number of ways to get system time, for example [NSDate date].timeIntervalSince1970 gives you the current number of seconds since 1970. I know, seems ridiculous, but if you get that number again sometime later, and subtract the previous number of seconds you get the difference in seconds, that's all that counts.
So you are using a constraint to drag the ball around, and the ball is elastic correct? Have you tried tweaking the constraint parameters at all? If the constraint has a lower maxForce, the chance for oscillations would drop significantly.
Another thing that can help is to increase the space's collision slop (how much shapes are allowed to overlap). The default value is 0.1 (in whatever scale you are using), but increasing it to a pixel or so can help this sort of thing significantly without being very visible.

Cocos2D Realistic Gravity?

I have tried many different techniques of applying a realistic looking gravity feature in my game but have had no luck so far. I plan on offering a 100 point bounty on this for someone who can show me or (share) some code that applies gravity to a CCSprite in Cocos2D.
What I have done so far has just been ugly or unrealistic and I have asked in many different places on what the best approach is but I just have not found any good looking gravity techniques yet.
Anyway, can anyone offer some tips/ideas or their approach only applying gravity to a CCSprite in Cocos2D without using a physics engine?
Thanks!
A effective approach without having to explicitly use any physics engine is to step the velocity and position of your sprite manually in your update loop. This is essentially Euler Integration.
// define your gravity value
#define GRAVITY -0.1
// define a velocity variable in the header of your Game class/CCSprite Subclass (neater)
float velocity_y;
-(void) update: (ccTime) dt
{
// Step the y-velocity by your acceleration value (gravity value in this case)
velocity_y += GRAVITY *dt; // drop the dt if you don't want to use it
// Step the position values and update the sprite position accordingly
sprite.position.y += velocity_y* dt; // same here
}
In the code snippet above, I defined a velocity_y variable to keep track of my sprite's current velocity along the y-direction. Remember to initialize this value to 0 in your init method.
Next comes the crux of Euler. At every time step:
Advance your velocity by your acceleration (which is your gravity) multiplied by dt to find your new velocity.
Advance your position by your newly computed velocity value multiplied by dt to find your new position.
You can experiment whether using delta-time or not (see LearnCocos2D's excellent comment on the cons of using it) works for your game. While multiplying by delta-time allows your object motion to more accurately take into account varying framerates, as LearnCocos2d pointed out, it might be wise to avoid using it in a real-time game where system interrupts (new mail, low battery, ads pop-out) can occur and subsequently cause the game simulation to jump forward in an attempt to make up.
So if you are dropping the dt, remember to tweak (scale down) your GRAVITY value accordingly to retain the right feel, since this value is no longer multiplied by the value of delta-time (which is ~ 1/60).
Aditional Tip: To apply an impulse to move the sprite (say via a swipe), you can affect the velocities directly by changing the values of velocity_x (if you have this) and velocity_y.
I have used this approach in my games, and it works very well. hope it helps.
This isn't trivial matter, you should try to see other posts. I'm sure other poeple already had this issue. Try to look at :
How to simulate a gravity for one sprite in cocos2d without a physics engine?
Cocos2D Gravity?
Or try our good friend google :
http://www.gamedev.net/page/resources/ -> got to Math and Physics and then A Verlet based approach for 2D game physics
http://www.rodedev.com/tutorials/gamephysics/
In any case here are some tips :
Step 1, calculate the effective direction vectors
Step 2, calculate velocity
Step 3, project this velocity onto the two effective directions.
Step 4, generate an equal and opposite force for the two direction and call this the “response force”.

Resources