Maintaining sync between animating objects? - iphone

I have simple object(AnimateTopDown) which animates up-down continuously , and i have several AnimateTopDown objects which animates but there is no sync between all objects animation. In general how to maintain sync between objects? Is there is any way to sync between separate animation blocks?
p.s. I am using UIViewAnimation interface for animating objects.

It is kinda hard to get what you want here. What kind of effect are you getting and what kind of effect do you want to achieve?
But in general, you can use a single UIView animation block (or whatever mechanism you use to animate) to move all your objects so they move at the same time. Giving them separate animation blocks will mean they will execute one at a time as they get queue'd up for CPU time.

//mSyncTime can be shared/global variable
-(NSTimeInterval) getStartDelay
{
NSTimeInterval delay;
NSTimeInterval oldTime = mSyncTime;
if(oldTime == 0)
{
mSyncTime = [NSDate timeIntervalSinceReferenceDate];
oldTime = mSyncTime;
}
NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];
delay = timeNow - oldTime;
SLint delayInMiliSec = delay * 1000;
SLint animDuration = (DEFAULT_ANIM_SPPED*2) * 1000;
SLint timeElapsed = delayInMiliSec%animDuration;
delay = animDuration - timeElapsed;
delay = delay/1000.0;
if(oldTime == 0)
delay = 0;
return delay;
}
And before starting animation I have set the delay to the setAnimationDelay API...
[UIView setAnimationDelay:[self getStartDelay]];
It worked for me... The hack is we have to maintain a standard time and before starting any animation we need to sync our animation to that reference time.

Related

Creating a NSThread Game Loop

Im trying to create a NSThread game loop, i have some of the time been able to get a successful 57 FPS.
Some of the time my fps goes up to some ridiculice number.
I dont understand how its happening.
I check how long since the last loop and if it was to quick, sleep the thread for that much time.
This is not always happening, it sometimes escapes the if check on the speed and does the loop way to fast.
Any comments would mean alot.
Also where am i suposed to 'Tick' ?
- (void)gameLoop{
//gameIsRunning is set to TRUE in viewDidLoad
while (gameIsRunnning){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Get Current date
NSDate *curTime = [NSDate date];
//Time since last loop and vurrent date;
NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:old_date];// * 1000.0;
NSLog(#"***************");
//Cout the time interval
NSLog(#"Loop Time %f",timePassed_ms);
//Check if the loop was to fast and sleep for long enough to make up for about 60 FPS
if (timePassed_ms < 1.0/60) {
double timeToSleep = timePassed_ms - (1.0/60);
timeToSleep = timeToSleep*-1;
NSLog(#"Sleep For %f",timeToSleep);
[NSThread sleepForTimeInterval:timeToSleep];
}
//This new date is to try and check if after waiting the loop is taking the correct duration
NSDate *newDate = [NSDate date];
NSTimeInterval timePassed_after = [newDate timeIntervalSinceDate:curTime];// * 1000.0;
//Make an fps out of this new time interval after wait
double FPS = (1.0/timePassed_after);
NSLog(#"FPS %f",FPS);
NSLog(#"Adjusted Time %f",timePassed_after);
NSLog(#"***************");
//Reset olddate for next loop
old_date = curTime;
//Apparently this will capture touches and button events
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);
//A test on moving a ball to see how smooth it will be
[self performSelectorOnMainThread:#selector(moveBall) withObject:nil waitUntilDone:NO];
[pool drain];
}
}
You shouldn't rely on sleeping a thread because you can never be sure it will take the same amount of time.
So instead of making a thread sleep, do nothing with it, nothing at all (except of course with incrementing your fixed time step)
You will find you will have a much smoother Frame Rate then.
Also as a side note, don't use FPS as a performance indicator. Use the amount of time a single update has taken to be completed.
If you are aiming # 60fps, your goal processing time should be 0.01666* seconds. In reality you should be able to increase your processing time to 0.02555* which is 40fps and there should be no noticable performance hit on the game
EDIT: I also noticed you are creating a new pool and draining everytime the update is hit, in my experiences the autorelease pools should be placed at higher levels such appDelegate. But I wouldn't take it any lower then the level creation(create)/release(drain), moving this further up will help with performance as well.
I recommend switching to CADisplayLink API (docs). It creates a timer that automatically fires as often as the display refreshes, without you having to figure out how long to sleep. This will solve the problem about delivering "refresh" events to your code, but it will not solve all your problems.
Obviously, if your code can't finish in 1/60 seconds then you will not get 60 fps. Make sure your game logic and physics is not tied to the video refresh rate. Some people disagree whether CADisplayLink is the right thing to do. However, the agreed alternative is to update as fast as the hardware permits.
Last year, I switched a rendering loop in a toy game I had to use a display link (Mac, not iOS). I noticed a significant improvement in how "smooth" the game felt. Your results may vary.
Here is one way to do it (semi-pseudocode, simplified):
- (void)update:(CADisplayLink *)link {
now = gettime();
while (gametime < now) {
// Physics always updated at rate of 1/delta
advanceframe();
gametime += delta;
}
draw();
}
- (void) gameLoop
{
NSAutoreleasePool* loopPool = [NSAutoreleasePool new];
int loopCnt = 0;
while ( isRunning ) {
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);
[self draw];
select(0, 0, 0, 0, &tm);
if ( loopCnt > 20000 ) { // 20000
loopCnt = 0;
[loopPool release];
loopPool = [NSAutoreleasePool new];
}
++loopCnt;
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);
}
[loopPool release];
}
timeIntervalSinceDate: returns the interval in seconds, not milliseconds.
(I wanted to write this in a little comment, not in a real answer, but couldn't figure out how to do this...)

Gauge animation on iphone

I'm trying to implement a gauge animation using (+ and - buttons) on iphone, but i have no idea where to start? Any help is really welcome. See the image below (this is what I'm trying to do). Thanks for your help.
Here is some open source code (with an example) that implements the gauge view. You of course would still need to do the buttons yourself, and possible add a different visual style.
http://www.cocoacontrols.com/platforms/ios/controls/meterview
You need to rotate the needle based on the angle... Here is the logic
You can refer my answer here... Rotating a UIImageView around a point over 10 seconds?
fireInterval = 10;
//Adjust starting and ending angle
mStartingAngle = 45;
mEndingAngle = 180;
//Implementation
-(void) startTimer
{
mPreviousTime = [NSDate timeIntervalSinceReferenceDate];
}
In the loop
-(void) updateFunction
{
NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];
//NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
//Mapping values between mStartAngle and mEndAngle
mCurrentAngle = (((timeNow - mPreviousTime) * (mEndingAngle - mStartingAngle)) / (previousTime+fireInterval - mPreviousTime)) + mStartingAngle;
if( mPreviousTime + fireInterval <= timeNow )
{
NSLog(#"10 seconds completed");
mPreviousTime = timeNow;
}
}
And rotate the needle based on mCurrentAngle....

timeIntervalSinceDate Accuracy

I've been working on a game with an engine that updates 20 times per seconds. I've got to point now where I want to start getting some performance figures and tweak the rendering and logic updates. In order to do so I started to add some timing code to my game loop, implemented as follows...
NSDate* startTime = [NSDate date];
// Game update logic here....
// Also timing of smaller internal events
NSDate* endTime = [NSDate date];
[endTime timeIntervalSinceDate:startTime];
I noticed however that when I timed blocks within the outer timing logic that the time they took to execute did not sum up to match the overall time taken.
So I wrote a small unit test to demonstrate the problem in which I time the overall time taken to complete the test and then 10 smaller events, here it is...
- (void)testThatSumOfTimingsMatchesOverallTiming {
NSDate* startOfOverallTime = [NSDate date];
// Variable to hold summation of smaller timing events in the upcoming loop...
float sumOfIndividualTimes = 0.0;
NSTimeInterval times[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
for (int i = 0; i < 10; i++) {
NSDate* startOfIndividualTime = [NSDate date];
// Kill some time...
sleep(1);
NSDate* endOfIndividualTime = [NSDate date];
times[i] = [endOfIndividualTime timeIntervalSinceDate:startOfIndividualTime];
sumOfIndividualTimes += times[i];
}
NSDate* endOfOverallTime = [NSDate date];
NSTimeInterval overallTimeTaken = [endOfOverallTime timeIntervalSinceDate:startOfOverallTime];
NSLog(#"Sum of individual times: %fms", sumOfIndividualTimes);
NSLog(#"Overall time: %fms", overallTimeTaken);
STAssertFalse(TRUE, #"");
}
And here's the output...
Sum of individual times: 10.001377ms
Overall time: 10.016834ms
Which illustrates my problem quite clearly. The overall time was 0.000012ms but the smaller events took only 0.000001ms. So what happened to the other 0.000011ms?
Is there anything that looks particularly wrong with my code? Or is there an alternative timing mechanism I should use?
Well, there is some time required to run [NSDate date] and [endTime timeIntervalSinceDate:startDate] which probably accounts for the difference.
However, I would use CACurrentMediaTime() which returns a CFTimeInterval (which is just a double), or mach_absolute_time() which returns an unsigned long int. Both of these avoid object creation and probably take less time.
Of course, you'll still be subtracting two numbers every frame, which takes time. My suggestion to get around that would be to just use lastFrameEnd:
CFTimeInterval lastFrameEnd = CACurrentMediaTime();
while (true) {
// Game update logic here....
// Also timing of smaller internal events
CFTimeInterval frameEnd = CACurrentMediaTime();
CFTimeInterval duration = frameEnd - lastFrameEnd; //Use this
lastFrameEnd = frameEnd;
}
This takes into account the time taken for the end of one frame to the end of the next, including the time taken for the subtraction and method calls.

cocos2d ccArray removing object is slow

I'm making a particle system for my game, which basically is smoke coming out from rockets in my game. All particles are in a ccArray called smoke.
ccArray *smoke = ccArrayNew(0);
I have a class called Smoke, which is a subclass of CCSprite, with the addition of an ivar called __opacity.
When I add a new smoke to the ccArray I do like this:
ccArrayAppendObject(smoke, [Smoke spriteWithFile: #"smoke.png"]);
[smoke->arr[smoke->num - 1] setupWithTouch: touch andOpacity: 255.0f];
[self addChild: smoke->arr[smoke->num - 1]];
Which doesn't lag at all, and is fast,
And this is how I handle the smoke every frame:
if(smoke->num > 0)
{
for(NSUInteger i = 0; i < smoke->num; i++)
{
Smoke *s = smoke->arr[i];
s.__opacity = s.__opacity - 255.0f * delta;
[s setOpacity: s.__opacity];
if(s.__opacity <= 0.0f)
{
[self removeChild: s cleanup: YES];
ccArrayFastRemoveObjectAtIndex(smoke, i);
}
}
}
When opacity is less than 0, we remove the smoke from the scene, and then
remove it from the array -- which is the part that slows the game down, removing it from the Array. It goes from 60 FPS to like 15-20 FPS, when there's like, 60 smoke particles on the scene.
Any ideas how I can speed this up?
Also, reason I'm using ccArray instead of NSMutableArray is because I read ccArray is faster.
removing object from the middle or the beginning of an array (any array) will recreate the array, and the operation is very slow (alloc+copy of members), if you have datastruct with many removes that not at the end you probably should use a linked-list
here some implementation i found in the internet (haven't tested it but it looks decent)
http://www.cocoadev.com/index.pl?DoublyLinkedList

iPhone Add a timer at Navigation Bar

HI , i have made simple application with 5 view controllers with some functionality .. what i want to do now is add a time at the main screen . and it should b running till i quit from application .. i will move to other view controllers also but that timer would b running .. how i will have this functionality ??
Check out the "Timers" section here: http://www.iphoneexamples.com/
Also, refer to Apple's NSTimer Documentation
The most practical way to do this is to fake it - that is, just store the start timestamp, and don't bother to continuously maintain any kind of timePassed variable. This is both easier to code, and actually more reliable since it's stable.
Store an NSDate for the instant the timer was started, and whenever you want to display or update the timer, use NSDate's timeIntervalSinceNow method, which returns the number of seconds passed as an NSTimeInterval, which is basically a typedef for a double. Note: this function returns a negative number when called on a timestamp in the past, which will be the case here.
If part of your display is showing this time, you can update it every second (or even more often) with an NSTimer object that periodically called one of your methods which updates the display.
Sample code:
// In the initialization code:
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self
selector:#selector(secondPassed:) userInfo:nil repeats:YES];
// Later:
// (This code assumes #minutes < 60.)
- (void) secondPassed: (NSTimer:) timer {
NSTimeInterval secondsPassed = -1 * [self.timerStart timeIntervalSinceNow];
int minutes = (int)(secondsPassed / 60);
int seconds = (int)(seconds - minutes * 60);
NSString* timerString = [NSString stringWithFormat:#"%02d:%02d",
minutes, seconds];
[self updateTimerDisplay:timerString];
}