How to apply different easing effects to sprite action? - ios

I use a lot of CCEase* functionalities in Cocos2D described here. iOS 7 Sprite Kit also have SKActionTimingMode. However only simple modes. How can I get CCEaseElasticIn or CCEaseBounceIn like effects using Sprite Kit?

Sprite Kit left easing (or tweening) intentionally limited with the expectation that the developer would take control of the specifics of the motion of the sprites. Basically, what you need to do is make a custom action and apply an easing curve to the parameter before changing the property (rotation, position, scale, etc) of the sprite. Here's an example.
CGFloat initialScale = mySprite.xScale;
SKAction *scaleAction = [SKAction customActionWithDuration:duration actionBlock:^(SKNode *node, CGFloat elapsedTime) {
CGFloat t = elapsedTime/duration;
CGFloat p = t*t;
CGFloat s = initialScale*(1-p) + scale * p;
[node setScale:s];
}];
[mySprite runAction:scaleAction];
The part of this that determines the easing is p = t*t. So, p is a function of t such that :
when t is 0, p is 0
when t is 1, p is 1
That means that you will start at the beginning and end at the end but the shape of the curve in between will determine how you get there. Easing functions can be simple, like the one shown here, which is basically an ease-in, or quite complex such as elastic or bounce. To generate your own, try this : http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
Or take a more detailed look at Robert Penner's equations: http://www.robertpenner.com/easing/

For arbitrary easing, Kardasis' answer says it all.
If you're looking for an easy way to add a bouncing effect to your animations, that is consistent with the way things are done in UIKit, I have something for you.
Apple introduced spring animations in UIKit a couple years ago, by letting you set a spring damping and initial velocity when performing a UIView animation. Unfortunately they didn't implement that in SpriteKit, so I made my own library that does just that.
It's a set of extensions on SKAction that replicate most factory methods, adding the damping and velocity parameters.
The code is on GitHub, feel free to use it: https://github.com/ataugeron/SpriteKit-Spring

Related

Smooth sprite movement in SpriteKit

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

How to only affect one coordinate of a sprite in sprite-kit?

I've been mucking around with sprite-kit but found out the only way to affect a sprites coordinate is with sprite.position, the issue here is I only want to affect one sprite coordinate, let's say y. How would I do this?
You should probably read up on SKActions:
SKAction *moveSprite = [SKAction moveToY:200 duration:0]; // or wherever...
[yourSpriteInstance runAction:moveSprite];
There is also a moveToX:duration:, moveTo:duration:, moveBy:duration: to mention a few of the options..
Like #sangony writes in the comments you can of course access the node's position directly through its position property:
sprite.position = CGPointMake(sprite.position.x, sprite.position.y + 200);
This will work just fine.
That being said, SKActions is the way to go about this in most real-life scenarios: E.g. if you want to have the sprite change its position after 3 seconds, then wait another 2 seconds before it begins rotating. It really is one of the cornerstones of the SpriteKit framework...

SpriteKit: rotation without friction

Is there a way to make a sprite rotate after contact with other sprites but without having frictional forces applied to it?
If i set
sprite.physicsBody.friction = 0.0;
sprite.physicsBody.allowsRotation = YES;
no rotation occurs.
If you want a body to rotate upon sliding contact with other bodies, some friction is necessary. (Just like in real-world physics!) Do you want friction to cause rotation, but exhibit frictionless behavior once it's rotating? If so, rereading the previous sentence should give a clue to the answer: you need to change the friction coefficient after the body starts rotating. Setting a contact delegate gives you an opportunity to make this change. It's also good for just about any other case where you want to "fudge" the results of a collision after it occurs, such as re-setting the body's velocity to a predetermined value.
If you want to manage the rotation by yourself, you can detect the collision with the delegate and the apply angular impulse like this
[sprite.physicsBody applyAngularImpulse:0.05];
Maybe I'm not getting the point but what you seem to want to do is really just:
sprite.zRotation = 1.0; // Note: zRotation is in radians
Or use SKAction rotateToAngle:duration: if you want the rotation to occur over a period of time.

SpriteKit SKAction easing

Well the title gives the question away, how can I apply easing to the SKAction node actions in SpriteKit?
I found that this works:
SKAction *moveAction = [SKAction moveByX:moveX y:moveY duration:0.5];
moveAction.timingMode = SKActionTimingEaseInEaseOut;
[node runAction:moveAction];
However there are only a few easing types available there, namely Linear, EaseIn, EaseOut, EaseInOut.
And those easing values are fixed and cannot be altered. I am looking for something like EleasticInOut. With preferably a bit more control. How can I create that?
I've been using the SKEase framework:
https://github.com/buddingmonkey/SpriteKit-Easing
It's as simple to use as the standard SpriteKit Actions and adds all the usual more complex eases, cubic, bounce, elastic, back etc.
SpriteKitUtils also adds more complex easing types and some handy SpriteKit utilities: https://github.com/raywenderlich/SKTUtils
The other option is to roll your own using the custom action method, and pass it a block of code with your custom easing/animation function:
-(SKAction *)customActionWithDuration:(NSTimeInterval)seconds actionBlock:(void (^)(SKNode *node, CGFloat elapsedTime))block
Apple introduced spring animations in UIKit a couple years ago, by letting you set a spring damping and initial velocity when performing a UIView animation. Unfortunately they didn't implement that in SpriteKit, so I made my own library that does just that.
It's a set of extensions on SKAction that replicate most factory methods, adding the damping and velocity parameters.
The code is on GitHub, feel free to use it: https://github.com/ataugeron/SpriteKit-Spring
Here is fresh, as spring water, answer goes. In iOS 8 timingFunction was introduced. It allows you to create custom timing curves.
The return SKActionTimingFunction value of the timing function
determines the actual time used to perform the animation.
This way, you can implement your own easing function. Although it has certain limitations: output values must be between 0.0 and 1.0. So for more realistic elastic bouncing I would recommend use SpriteKit-Spring

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