I'm developing a cocos2d game (using iOS 6 SDK and cocos2d 2.0rc2) and am having issues with a lower frame rate on the device. This causes issues with collision detection because most of it deals with the user drawing a line. The lower frame rate causes the points to be drawn farther apart and the object can go through the line because it never hits the points. The frame rate issue seems to happen most when I get a notification. Instead of the frame rate returning to normal when the notification disappears, it stays low and never returns to 60fps. Any ideas what might be causing this or a solution to handle the lines better with a lower fps?
Here is the drawing code, let me know if you want to see anything else.
-(void) draw {
glLineWidth(lineScale);
for (int i = 0; i < touchesArray.count; i += 2) {
CGPoint start = CGPointFromString([touchesArray objectAtIndex:i]);
CGPoint end = CGPointFromString([touchesArray objectAtIndex:i + 1]);
ccDrawLine(start, end);
}
}
Related
I am using SpriteKit's built in Physics Engine to build a game for iOS. Basically it involves a bouncing ball which moves via me manually setting it's initial velocity and bounces via resetting the velocity within the contact event with the floor.
The issue is, the actual maths for this environment do not add up. Using 'SUVAT' equations it's easy to determine how far the ball's x-displacement should be when it reaches the floor after being thrown with a certain velocity, however (with gravity set to -9.81), it barely moves a couple of pixels.
I simplified the problem to just trying to shoot a ball a certain distance upwards (in the y-direction) and the same thing happened, it moves a couple of points up and then just falls to the floor, at least a 20th of how far it should move.
This is how I have set the physics environment up:
self.physicsWorld.contactDelegate = self;
self.physicsWorld.gravity = CGVectorMake(0.0, -9.81);
And then this is my function for generating this ball (shooting upwards) example. Mathematically it should reach the height of the tower:
-(void)generateTestBall {
self.ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
SKSpriteNode * tower = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
self.ball.position = CGPointMake(self.scene.size.width/2,self.scene.size.height/2);
self.ball.size = CGSizeMake(20,20);
self.ball.color = [SKColor redColor];
self.ball.colorBlendFactor = 1;
tower.position = CGPointMake(self.scene.size.width/2 + 20,self.scene.size.height/2+100);
tower.size = CGSizeMake(20,200);
tower.color = [SKColor blueColor];
tower.colorBlendFactor = 1;
[self addChild:tower];
[self addChild:self.ball];
self.ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
self.ball.physicsBody.affectedByGravity = YES;
self.ball.physicsBody.linearDamping = NO;
self.ball.physicsBody.dynamic = YES;
CGFloat ballVel = sqrt(2*9.81*tower.size.height);
NSLog(#"%f",ballVel);
self.ball.physicsBody.velocity = CGVectorMake(0.0f, ballVel);
}
Please can someone explain what I am doing wrong? I've double checked my maths (I'm a maths student so fingers crossed that's not the issue)!
Thanks!
Steve
So I FINALLY managed to figure it out. Just incase anyone else is experiencing the same issue I'll post the answer here:
The issue was that, although gravity is (apparently) in ms^-2 and velocity m2^-1 (to replicate earth), any distances in Objective C are measured in POINTS rather than the required form of METRES. Therefore any calculation done with x,y position / size values taken from SKSpriteNodes etc will be a certain factor out.
After running a few tests I found the factor to roughly be 157. This means that you must multiply any sizes / distances in POINTS by 157 to get the relative 'METRE' value which will work with SUVAT.
The actual numbers themselves seem a bit ridiculous as they're all very big (velocity, distance etc) but that doesn't actually pose a problem anyway as they all now work relative to each other!
Hope this helps anyone!
Steve
I've been struggling with this problem for a while, which appears to be buried deep inside the spritekit physics engine.
My first question would be: Does Spritekit process its physics updates in a different thread than the main thread?
I have a "world" node in the scene which I move around to simulate a "camera" view. As such, I can center the "camera" on my player character node. Since the player jumps up and down a lot, I want to smooth the camera. Without camera smoothing, there's no problems. But when I add camera smoothing, as such: (this code is called from didFinishUpdate)
CGPoint ptPosition = self.position;
float fSmoothY = m_fLastCameraY + (ptPosition.y - m_fLastCameraY) * 0.1;
CGPoint pointCamera = [self.scene convertPoint:CGPointMake(ptPosition.x, fSmoothY) fromNode:self.parent];
[gameScene centerOnPoint:pointCamera];
m_fLastCameraY = fSmoothY;
If I call the above code from didSimulatePhysics, it does the exact same thing. It stutters whenever it falls down (due to the Y camera smoothing).
When plotting it out, you can see that the player Y (the red line) is stuttering over the course of the frames.
How can I fix this, or work around it if it can't be truly "fixed"?
I suggest you apply an infinite impulse response (IIR) filter to smooth the camera. You can do that by...
First, declare the instance variables
CGFloat alpha;
CGFloat fSmoothY;
and then Initialize alpha and fSmoothY
// alpha should be in [0, 1], where a larger value = less smoothing
alpha = 0.5;
fSmoothY = ptPosition.y;
Lastly, apply the filter with
fSmoothY = fSmoothY * (1-alpha) + ptPosition.y * alpha;
I want to track the motion of device along 0-180 degrees from left to right (up and downwards also) and show it on the device screen like a graph. I am using device motion sensors to draw the line but unable to find which values I need to use for.
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
{
CGFloat rotationRateY = motion.rotationRate.y;
CGFloat rotationRateX = motion.rotationRate.x;
if (fabs(rotationRateY) >= 0.1f || fabs(rotationRateX) >= 0.1f)
{
CMAttitude *currentAttitude = self.motionManager.deviceMotion.attitude;
newXVal = (int)round(degrees(currentAttitude.roll));
newYVal = (int)round(degrees(currentAttitude.pitch));
newZVal = (int)round(degrees(currentAttitude.yaw));
// Degrees should always be positive
if(newZVal < 0)
{
newZVal = newZVal + 360;
}
else
{
newZVal = newZVal + 180;
}
//I want to track some cgpoints to draw the line here I think but how...:(
}
}];
In the above code I am depending on yaw value to track 0 - 180 degrees but it is changing as I move the device up/down, so I couldn't use the values.
For Reference:
Thanks.
The problem with doing this is that the only information you get back from the device about movement is acceleration. (i.e. not position or speed).
You might be able to work out which direction the device is currently accelerating in. But not how far it has travelled (or how fast) in that direction.
Using this you could then put lines down.
i.e. right, up, right, down, right, diagonal up, diagonal down, right, etc...
You can get this from the userAcceleration property of CMDeviceMotion. This then has x, y, and z values.
There are many resources about why it's hard (impossible) to work out location though... This is one of the best I have found. It's the same reason that the Oculus Rift 2 has an external camera to track movement.
Good luck though :)
I have an app that records angles as user is walking around an object, while pointing device (preferably) at the center of the object.
Angle gets reset on user's command - so reference attitude gets reset.
Using Euler angles produces Gimbal lock, so I am currently using quaternions and calculating angles this way:
double angleFromLastPosition = acos(fromLastPositionAttitude.quaternion.w) * 2.0f;
This gives off good precision and it works perfectly IF device's pitch and yaw does not change. In other words, as the angle shows 360 degrees I end up in the same place as the start of the circle.
Problem 1: if device's yaw and pitch change slightly (user not pointing directly at center of the object), so does the angleFromLastPosition.
I understand this part, as my angle formula just shows the angle in between two device attitudes in 3D space.
Scenario:
I mark the start of rotation attitude and start moving in a circle around the object while pointing at the center
I stop at, say, 45 degrees and change pitch of the device by pointing it higher or lower. Angle changes accordingly.
What I would love to see is: angle stays at 45 degrees, even if pitch or yaw changes.
Question 1 is, how can I calculate only the Roll of the device using quaternions, and disregard changes in other two axes (at least within some reasonable number of degrees).
Problem 2: if I rotate for a bit and then freeze the device completely (on tripod so there's no shaking at all), the angleFromLastPosition drifts at a rate of 1 degree per about 10-20 seconds, and it appears not to be linear. In other words, it drifts fast at first, then slows down considerably. Sometimes I get no drift at all - angle is rock-solid if device is stationary. And this makes me lost in understanding what's going on.
Question 2, what is going on here, and how can I take care of the drift?
I went through quite a few articles and tutorials, and quaternion math is beyond me at the moment, hope someone will be able to help with a tip, link, or few lines of code.
I have tested this and it seems to work according to what you're looking for in Question 1, Andrei.
I set the homeangle initially 0, and immediately after the first pass I store the angle returned from walkaroundAngleFromAttitude:fromHomeAngle: in homeangle, for future use.
My testing included starting the device updates using a reference frame:
[_motionManager
startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical
toQueue:operationQueue
withHandler:handler];
and using the following methods called within handler:
- (CMQuaternion) multiplyQuanternion:(CMQuaternion)left withRight:(CMQuaternion)right {
CMQuaternion newQ;
newQ.w = left.w*right.w - left.x*right.x - left.y*right.y - left.z*right.z;
newQ.x = left.w*right.x + left.x*right.w + left.y*right.z - left.z*right.y;
newQ.y = left.w*right.y + left.y*right.w + left.z*right.x - left.x*right.z;
newQ.z = left.w*right.z + left.z*right.w + left.x*right.y - left.y*right.x;
return newQ;
}
-(float)walkaroundRawAngleFromAttitude:(CMAttitude*)attitude {
CMQuaternion e = (CMQuaternion){0,0,1,1};
CMQuaternion quatConj = attitude.quaternion;
quatConj.x *= -1; quatConj.y *= -1; quatConj.z *= -1;
CMQuaternion quat1 = attitude.quaternion;
CMQuaternion quat2 = [self multiplyQuanternion:quat1 withRight:e];
CMQuaternion quat3 = [self multiplyQuanternion:quat2 withRight:quatConj];
return atan2f(quat3.y, quat3.x);
}
-(float)walkaroundAngleFromAttitude:(CMAttitude*)attitude fromHomeAngle:(float)homeangle {
float rawangle = [self walkaroundRawAngleFromAttitude:attitude];
if (rawangle <0) rawangle += M_PI *2;
if (homeangle < 0) homeangle += M_PI *2;
float finalangle = rawangle - homeangle;
if (finalangle < 0) finalangle += M_PI *2;
return finalangle;
}
This is using some modified and extended code from Finding normal vector to iOS device
Edit to deal with Question 2 & Problem 2:
This may not be solvable. I've seen it in other apps (360 pano for example) and have read about faulty readings in gyro and such. If you tried to compensate for it, of course you'll end up with a jittery experience when some authentic rotational movement gets tossed by the compensation code. So far as I've been interpreting for the last few years, this is a hardware-based issue.
I've got and XNA 2D game which I've been making, but I'm having problems with it.
I've got boxes scrolling across the screen which my sprite is jumping over. The sprite is being followed by a 2D camera, and I fear that the camera is causing issues, as it's causing the scrolling boxes to stop half way across the screen instead of continuing, and also the number of lives are decreasing rapidly rather than one life when one collision occurs.
This is the code in which my sprite collides with the moving boxes
Rectangle fairyRectangle = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
hit = false;
for (int i = 0; i < GameConstants.TotalBoxes; i++)
{
if (scrollingBlocks.boxArray[i].alive)
{
Rectangle blockRectangle = new Rectangle((int)scrollingBlocks.boxArray[i].position.X, (int)scrollingBlocks.boxArray[i].position.Y, scrollingBlocks.boxArray[i].texture.Width, scrollingBlocks.boxArray[i].texture.Height);
if (IntersectPixels(fairyRectangle, fairyTextureData, blockRectangle, blockTextureData))
{
scrollingBlocks.boxArray[i].alive = false;
hit = true;
lives--;
scrollingBlocks.boxArray[i].alive = true;
scrollingBlocks.boxArray[i].position.X = random.Next(GameConstants.ScreenWidth);
scrollingBlocks.boxArray[i].position.Y = 570;
}
}
}
And this is the update function in the scrolling boxes
public void Update(GameTime gameTime)
{
for (int i = 0; i < GameConstants.TotalBoxes; i++)
{
boxArray[i].position.X = boxArray[i].position.X - 5;
boxArray[i].position.Y = boxArray[i].position.Y;
if (boxArray[i].position.X < 0)
{
boxArray[i].position.X = randomno.Next(GameConstants.ScreenWidth) + 700;
boxArray[i].position.Y = 570;
}
Helper.WrapScreenPosition(ref boxArray[i].position);
}
}
I want them to start at the right hand screen and move all the way across to x = 0, but they're currently stopping around halfway at x = 400.
And finally this is where I'm drawing it all, with the sprite and the block
if (gameState == GameState.PLAYINGLEVEL3)
{
graphics.GraphicsDevice.Clear(Color.Aquamarine);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
backgroundManager.Draw(spriteBatch);
//scrollingBlocks.Draw(spriteBatch);
spriteBatch.DrawString(lucidaConsole, "Score: " + score + " Level: " + level + " Time Remaining: " + ((int)timer / 1000).ToString() + " Lives Remaining: " + lives, scorePosition, Color.DarkOrchid);
spriteBatch.End();
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.None, camera.transform);
scrollingBlocks.Draw(spriteBatch);
fairyL3.Draw(spriteBatch);
spriteBatch.End();
}
Thanks for any help!
From the code provided I can't tell much about how your camera works but my guess is that when you start the level your camera picks a new center point(rather than the original xna screen location)
In other words, the center of the camera may have pushed it back a bit, so what you think is position 0 of the screen may have been pushed forward to the middle of the screen making the boxes stop. I'd suggest looking at these camera tutorials http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ or http://www.youtube.com/watch?v=pin8_ZfBgq0
Cameras can be tricky so I'd suggest looking at a few tutorials to get the hang out matrices and view ports.
As for the lives taking away more than one, It's because your saying "If this box is colliding with my player, take away lives." the computer doesn't know that you only want one taken away as long as it's colliding with the player its taking away lives, it will keep decrementing.
Hopefully this will give you some ideas :D