iOS 7 Sprite Kit frame rate - ios7

I have written the -update method for an SKScene in two different forms and one has a much better and constant frame rate than the other.
Can someone explain the difference between the two implementations and reason(s) why they create two different frame rates?
Method 1 (frame rate drops to about 20-30 fps when moving sprite)
- (void)update:(NSTimeInterval)currentTime
{
[self updateBackground];
player.position = CGPointMake(slider.sliderValue * self.view.frame.size.width/200 + self.view.frame.size.width/2, player.position.y);
}
Method 2 (frame rate remains constant 60 fps when moving sprite)
- (void)update:(NSTimeInterval)currentTime
{
[self updateBackground];
delta = currentTime - previousTime;
previousTime = currentTime;
//NSLog(#"%f",delta);
player.position = CGPointMake(delta * adjustmentFactor * slider.sliderValue * self.view.frame.size.width/200 + self.view.frame.size.width/2, player.position.y);
}

Related

Velocity Verlet Algorithm: Cannot seem to determine correct velocity for stable Orbit?

Like many that post about this topic, I too am busy trying to write myself an accurate simulator for the movement of objects in a 2D gravitation field.
I decided early on that I would settle on Velocity Verlet Integration, as I want my objects to maintain stable orbits and conserve energy even if the timestep is rather large. So, what might the problem be?
Well, so far, everything seems to behave correctly, except for one component. When I try to calculate the correct velocity for a stable orbit at a certain distance, the resulting velocity sends them into odd elliptical orbits that quickly increase in magnitude each time.
So, to begin, here are the following methods that determine an objects next position, velocity, and acceleration in scene: (Objective C)
Acceleration:
-(CGVector)determineAccelerationFor:(SKObject *)object
{ // Ok, let's find Acceleration!
CGVector forceVector = (CGVector){0,0}; // Blank vector that we will add forces to
for (SKObject *i in self.sceneObjects)
{
if (![i isEqual:object]) // Just make sure we're not counting ourselves here
{
CGPoint distance = [self getDistanceBetween:i.position And:object.position];
float hypotenuse = sqrtf(powf(distance.x, 2)+ powf(distance.y, 2));
float force = ((self.gravity * object.mass * i.mass)/powf(hypotenuse, 3));
float xMagnitude = (force * distance.x);
float yMagnitude = (force * distance.y);
forceVector.dx += xMagnitude;
forceVector.dy += yMagnitude;
}
}
CGVector acceleration = (CGVector){forceVector.dx/object.mass, forceVector.dy/object.mass};
return acceleration;
}
Cool, so basically, I just take an object, add all the other forces that each other object imposes on it together then divide the X & Y factor by the mass of the current object to get the acceleration!
Next up is Velocity. Here I use the following equation:
The method for it is pretty straightforward too:
-(CGVector)determineVelocityWithCurrentVelocity:(CGVector)v OldAcceleration:(CGVector)ao NewAcceleration:(CGVector)a
{
float xVelocity = (v.dx + ((ao.dx + a.dx)/2) * self.timeStep);
float yVelocity = (v.dy + ((ao.dy + a.dy)/2) * self.timeStep);
CGVector velocity = (CGVector){xVelocity,yVelocity};
return velocity;
}
And finally, position! The equation for this is:
And it is determined with the following method!
-(CGPoint)determinePositionWithCurrentPosition:(CGPoint)x CurrentVelocity:(CGVector)v OldAcceleration:(CGVector)ao
{
float xPosition = (x.x + v.dx * self.timeStep + ((ao.dx * powf(self.timeStep, 2))/2));
float yPosition = (x.y + v.dy * self.timeStep + ((ao.dy * powf(self.timeStep, 2))/2));
CGPoint position = (CGPoint){xPosition,yPosition};
return position;
}
This is all called from the below method!!
-(void)refreshPhysics:(SKObject *)object
{
CGPoint position = [self determinePositionWithCurrentPosition:object.position CurrentVelocity:object.velocity OldAcceleration:object.acceleration]; // Determine new Position
SKAction *moveTo = [SKAction moveTo:position duration:0.0];
[object runAction:moveTo]; // Move to new position
CGVector acceleration = [self determineAccelerationFor:object]; // Determine acceleration off new position
CGVector velocity = [self determineVelocityWithCurrentVelocity:object.velocity OldAcceleration:object.acceleration NewAcceleration:acceleration];
NSLog(#"%# Old Velocity: %f, %f",object.name,object.velocity.dx,object.velocity.dy);
NSLog(#"%# New Velocity: %f, %f\n\n",object.name,velocity.dx,velocity.dy);
[object setAcceleration:acceleration];
[object setVelocity:velocity];
}
Okay, so those methods above dictate how objects are moved in scene. Now onto the initial issue, the ever present problem of achieving a stable orbit!
In order to determine what velocity an object should have to maintain an orbit, I use the following equation:
And I implement that as follows:
-(void)setObject:(SKObject *)object ToOrbit:(SKObject *)parent
{
float defaultSeparation = 200;
// Move Object to Position at right of parent
CGPoint defaultOrbitPosition = (CGPoint){parent.position.x + (parent.size.width/2)+ defaultSeparation,parent.position.y};
[object setPosition:defaultOrbitPosition];
// Determine Orbital Velocity
float velocity = sqrtf((self.gravity * parent.mass)/(parent.size.width/2+defaultSeparation));
CGVector vector = (CGVector){0,velocity};
[object setVelocity:vector];
}
And for some reason, despite this, I get abysmal results. Here is some of the output:
Information:
Gravity(constant) = 1000 (For test purposes)
Mass(Parent) = 5000 units
Mass(Satellite) = 1 units
Separation = 224 pixels
It determines that in order for the Satellite to Orbit the Parent, a velocity of:
149.403580 pixels/timeStep
is required. And that checks out on my calculator.
So this has left me a little confused as to what could be going wrong. I log all the output concerning new velocities and positions, and it does use the velocity I set it to, but that just doesn't seem to make a difference. If anyone could possible help spot what's going wrong here I would be immensely grateful.
If anyone believes I have left something out, tell me and I will edit this right away. Thanks!

UIKit Dynamics: Calculating pushDirection Needed for UIPushBehavior

I'd like to use UIPushBehavior to give a physically realistic animation of a view across the screen. But to do this, I need to be be able to calculated the magnitude of the push needed in the CGVector in the pushDirection property of UIPushBehavior.
Basically, I know the size of the view, the amount of time, and the distance I'd like it to travel. Is there a way to use the UIKit Newton definition and a UIDynamicItemBehavior with resistance to calculate exactly the magnitude need to move a view a specific distance in a specific amount of time?
If you're using a pan gesture, you can do this:
if ( gestureRecognizer.state == UIGestureRecognizerStateEnded )
{
CGPoint velocity = [gestureRecognizer velocityInView:gestureRecognizer.view.superview];
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
myPushBehavior = [[UIPushBehavior alloc] initWithItems:#[gestureRecognizer.view]
mode:UIPushBehaviorModeInstantaneous];
myPushBehavior.pushDirection = CGVectorMake((velocity.x / 10) , (velocity.y / 10));
myPushBehavior.magnitude = magnitude;
}
Courtesy of Tony Dahbura's tutorial.

How many times a second should CADisplayLink's displayLink be called?

I have a CADisplayLink running in line with Chipmunk Physics, and I'm getting very slow performance. I put an NSLog in the method that's called on the CADisplayLink update, and it's being called an average of 22 times per second. I was under the impression that that should be nearer 60. I have the frameInterval set to 1, so should it be 60fps, in a perfect world? The delta times are averaging around 0.0167 seconds (and 1 / 60 IS 0.0167, which is confusing me even further).
I just have four walls around the bounds of my screen and just eight circle-shaped bodies on-screen, updating to UIButton instances on each call, so I don't think I'm doing anything that should tax it to this extent on both my 4S and iPad3. I'm applying a random force to each button once every 2.5 seconds in a separate method. Running in the simulator is butter-smooth, so it's a device-only issue. Can anyone help me spot what's causing the slowdown here, and what I can do about it?
Here's the relevant code, first that which sets up the link:
[NSTimer scheduledTimerWithTimeInterval: 2.5f target: self selector: #selector(updateForces) userInfo: nil repeats: YES];
_displayLink = [CADisplayLink displayLinkWithTarget: self selector: #selector(update)];
_displayLink.frameInterval = 1;
[_displayLink addToRunLoop: [NSRunLoop mainRunLoop] forMode: NSRunLoopCommonModes];
Here's the method that should be called (I think!) 60 times per second, but is called only 22 or so:
if (!gameIsPaused) {
cpFloat dt = _displayLink.duration * _displayLink.frameInterval;
cpSpaceStep([[AGChipmunkSpace sharedInstance] space], dt);
for (LCBall *i in balls) {
cpVect pos1 = cpBodyGetPos(i.body);
CGAffineTransform trans1 = CGAffineTransformMakeTranslation(pos1.x, pos1.y);
CGAffineTransform rot1 = CGAffineTransformMakeRotation(cpBodyGetAngle(i.body));
i.button.transform = CGAffineTransformConcat(rot1, trans1);
}
}
And finally, here's the method that's called every 2.5 seconds, to apply the random forces (updateForces):
if (!gameIsPaused) {
for (LCBall *i in balls) {
int randomAngle = arc4random() % 360;
CGPoint point1 = [self getVectorFromAngle: randomAngle AndMagnitude: (arc4random() % 40) + ((arc4random() % 20) + 15)];
i.body -> f = cpv(point1.x, point1.y);
}
}
(Also, here's my method to get a vector from an angle, which I doubt is causing the issue):
angle = (angle / 180.0) * M_PI;
float x = magnitude * cos(angle);
float y = magnitude * sin(angle);
CGPoint point = CGPointMake(x, y);
return point;
Turns out I had a method on a different UIViewController in my storyboard that was firing every 0.1 seconds that hadn't turned off, and combined with the physics processing, was bogging things down.

UIView Delta Time

I'm animating a UIView by updating its anchorpoint 60 times a second using an NSTimer.
The location of the UIView changes depending on its angle, so it always appears to be down relative to the device...
However, the NSTimer doesn't fire precisely 60 times a second. It's always a little off, causing jerky animation. I've searched this a lot, I know a bit about delta time, but I don't know how to apply it to my situation.
Here's the movement code I'm using:
float rotation = 0;
if (leftSideIsBeingHeldDown) {
rotation += (0.05f/rotationFactor);
} else if (rightSideIsBeingHeldDown) {
rotation -= (0.05f/rotationFactor);
}
movementX += -sinf(rotation);
movementY += -cosf(rotation);
float finalX = 0.0001 * movementX;
float finalY = 0.0001 * movementY;
mapView.layer.anchorPoint = CGPointMake(finalX, finalY);
mapView.transform = CGAffineTransformMakeRotation(rotation);
Does anyone know how to apply delta time to this?
You might want to look into the CADisplayLink class which provides you a timer that is tied to the display refresh rate. It should be a better solution than an NSTimer in this case.
Additionally, you need to remember the time of each "tick" and calculate the rotation or movement that should have been done since the last tick. For example (pseudo-code):
- (void)displayLinkTick:(id)sender
{
NSTimeInterval timespan;
NSDate *now;
now = [NSDate date];
if (myPreviousTick) {
timespan = [now timeintervalSinceDate:myPreviousTick];
} else {
// The very first tick.
timespan = 0;
}
// Calculate the angle according to the timespan. You need a
// value that specifies how many degrees/radians you want to
// revolve per second and simply multiply that with the timespan.
angle += myRadiansPerSecond * timespan;
// You'd do the same with the position. I guess this involves
// minor vector math which I don't remember right now and am
// too lazy to look up. You need to have a distance per second
// which you multiply with the timespan. Together with the
// direction vector you can calculate the new position.
// At the end, remember when this tick ran.
[myPreviousTick release];
myPreviousTick = [now retain];
}
You want to record the time you last rotated, and the difference in time between then and now, and use that to work out a factor, which you can use to adjust the rotation and x/y values.
for example:
NSDate now = [NSDate now];
timeDiff = now - lastRotateTime;
factor = timeDiff / expectedTimeDiff;
x = x + xIncrement * factor;
y = y + yIncrement * factor;
angle = angle + angleIncrement * factor;
There are many better examples on game dev forums, which explain it in more detail.

know the position of the finger in the trackpad under Mac OS X

I am developing an Mac application and I would like to know the position of the finger in the trackpad when there is a touch.
Is it something possible and if yes, how?
Your view needs to be set to accept touches ([self setAcceptsTouchEvents:YES]). When you get a touch event like -touchesBeganWithEvent:, you can figure out where the finger lies by looking at its normalizedPosition (range is [0.0, 1.0] x [0.0, 1.0]) in light of its deviceSize in big points (there are 72 bp per inch). The lower-left corner of the trackpad is treated as the zero origin.
So, for example:
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (!self) return nil;
/* You need to set this to receive any touch event messages. */
[self setAcceptsTouchEvents:YES];
/* You only need to set this if you actually want resting touches.
* If you don't, a touch will "end" when it starts resting and
* "begin" again if it starts moving again. */
[self setWantsRestingTouches:YES]
return self;
}
/* One of many touch event handling methods. */
- (void)touchesBeganWithEvent:(NSEvent *)ev {
NSSet *touches = [ev touchesMatchingPhase:NSTouchPhaseBegan inView:self];
for (NSTouch *touch in touches) {
/* Once you have a touch, getting the position is dead simple. */
NSPoint fraction = touch.normalizedPosition;
NSSize whole = touch.deviceSize;
NSPoint wholeInches = {whole.width / 72.0, whole.height / 72.0};
NSPoint pos = wholeInches;
pos.x *= fraction.x;
pos.y *= fraction.y;
NSLog(#"%s: Finger is touching %g inches right and %g inches up "
#"from lower left corner of trackpad.", __func__, pos.x, pos.y);
}
}
(Treat this code as an illustration, not as tried and true, battle-worn sample code; I just wrote it directly into the comment box.)
Swift 3:
I've written an extension to NSTouch that returns the trackpad-touch pos, relative to an NSView:
extension NSTouch {
/**
* Returns the relative position of the touch to the view
* NOTE: the normalizedTouch is the relative location on the trackpad. values range from 0-1. And are y-flipped
* TODO: debug if the touch area is working with a rect with a green stroke
*/
func pos(_ view:NSView) -> CGPoint{
let w = view.frame.size.width
let h = view.frame.size.height
let touchPos:CGPoint = CGPoint(self.normalizedPosition.x,1 + (self.normalizedPosition.y * -1))/*flip the touch coordinates*/
let deviceSize:CGSize = self.deviceSize
let deviceRatio:CGFloat = deviceSize.width/deviceSize.height/*find the ratio of the device*/
let viewRatio:CGFloat = w/h
var touchArea:CGSize = CGSize(w,h)
/*Uniform-shrink the device to the view frame*/
if(deviceRatio > viewRatio){/*device is wider than view*/
touchArea.height = h/viewRatio
touchArea.width = w
}else if(deviceRatio < viewRatio){/*view is wider than device*/
touchArea.height = h
touchArea.width = w/deviceRatio
}/*else ratios are the same*/
let touchAreaPos:CGPoint = CGPoint((w - touchArea.width)/2,(h - touchArea.height)/2)/*we center the touchArea to the View*/
return CGPoint(touchPos.x * touchArea.width,touchPos.y * touchArea.height) + touchAreaPos
}
}
Here is an article I wrote about my GestureHUD class in macOS. With link to a ready-made extension as well: http://eon.codes/blog/2017/03/15/Gesture-HUD/
Example:
I don't know if there's an ObjC interface, but you might find the C HID Class Device Interface interesting.
At a Cocoa (Obj-C level) try the following - although remember that many users are still using mouse control.
http://developer.apple.com/mac/library/documentation/cocoa/conceptual/EventOverview/HandlingTouchEvents/HandlingTouchEvents.html