In my "xcode" timer project, I have a int variable named "overall". When I first set up my timer the overall variable is set to the amount of seconds wanted for the timer. I then have an NSTimer taking a second of the variable every second.
overall = (timerMin * 60) + (timerHour * 60 * 60) + timer;
[self setTimer];
When i first set the variable
If the app enters the background I record the date and then the date of when it enters the foreground. I then find out the difference of the two dates and take it away from the overall variable. And recall the NSTimer.
[Countdown invalidate];
Countdown = nil;
overallBackground = [saveOverall integerForKey:overall_save];
int newOverall = (int)overallBackground - secondsInBackground;
overall = newOverall;
[self setTimer];
When i set it after re-entering the app from background
The problem I have is that even though I have been into the background and reset the overall variable when the Timer was restarted the overall variable number from before was still there but the variable was also storing the new number!
2014-05-11 16:48:18.759 Timer[836:60b] overall:3595 - Old number
2014-05-11 16:48:19.044 Timer[836:60b] overall:3591 - New number
2014-05-11 16:48:19.759 Timer[836:60b] overall:3594 - Old number
2014-05-11 16:48:20.044 Timer[836:60b] overall:3590 - New number
NSLog(#"overall:%d", overall);
overall = overall - 1;
[saveOverall setInteger:overall forKey:overall_save];
[saveOverall synchronize];
hours = overall / 3600;
minutes = overall - (hours * 3600);
minCon = minutes / 60;
seconds = minutes - (minCon * 60);
From the log above you can see what I mean. I am printing the exact same variable to the log, just so you know.
My question is why is this happening? And how do I stop it?
Related
I'm using AVPlayer to play a live streaming. This stream supports one hour catch-up which means user can seek to one hour ago and play. But I have one question how do I know the accurate position that the player is playing. I need to display current position on the player view. For example,if user is playing half an hour ago then display -30:00; if user is playing the latest content, the player will show 00:00 or live. Thanks
Swift solution :
override func getLiveDuration() -> Float {
var result : Float = 0.0;
if let items = player.currentItem?.seekableTimeRanges {
if(!items.isEmpty) {
let range = items[items.count - 1]
let timeRange = range.timeRangeValue
let startSeconds = CMTimeGetSeconds(timeRange.start)
let durationSeconds = CMTimeGetSeconds(timeRange.duration)
result = Float(startSeconds + durationSeconds)
}
}
return result;
}
To get a live position poison and seek to it you can by using seekableTimeRanges of AVPlayerItem:
CMTimeRange seekableRange = [player.currentItem.seekableTimeRanges.lastObject CMTimeRangeValue];
CGFloat seekableStart = CMTimeGetSeconds(seekableRange.start);
CGFloat seekableDuration = CMTimeGetSeconds(seekableRange.duration);
CGFloat livePosition = seekableStart + seekableDuration;
[player seekToTime:CMTimeMake(livePosition, 1)];
Also when you seek some time back, you can get current playing position by calling currentTime method
CGFloat current = CMTimeGetSeconds([self.player.currentItem currentTime]);
CGFloat diff = livePosition - current;
I know this question is old, but I had the same requirement and I believe the solutions aren't addressing properly the intent of the question.
What I did for this same requirement was to gather the current point in time, the starting time, and the length of the total duration of the stream.
I'll explain something before going further, the current point in time could surpass the (starting time + total duration) this is due to the way hls is structured as ts segments. Ts segments are small chucks of playable video, you could have on your seekable range 5 ts segments of 10 seconds each. This doesn't mean that 50 secs is the full length of the live stream, there is around a full segment more (so 60 seconds of playtime total) but it isn't categorized as seekable since you shouldn't seek to that segment. If you were to do this you'll notice in most instances rebuffering (cause the source may be still creating the next ts segment when you already reached the end of playback).
What I did was checking if the current stream time is further than the seekable rage, if so this would mean were are live on stream. If it isn't you could easily calculate how far behind you are from live if you subtract the current time, starting time, and total duration.
let timeRange:CMTimeRange = player.currentItem?.seekableTimeRanges.last
let start = timeRange.start.seconds
let totalDuration = timeRange.duration.seconds
let currentTime = player.currentTime().seconds
let secondsBehindLive = currentTime - totalDuration - start
The code above will give you a negative number with the number of seconds behind "live" or more specifically the start of the lastest ts segment. Or a positive number or zero when it's playing the latest ts segment.
Tbh I don't really know when does the seekableTimeRanges will have more than 1 value, it has always been just one for the streams I have tested with, but if you find in your streams more than 1 value you may have to figure if you want to add all the ranges duration, which time range to use as the start value, etc. At least for my use case, this was enough.
I am making a reaction game, where you can destroy enemys and earn points. Now I would like to have combo points if you destroy them fast and if there is a specific time gap the combo multiplier should go to zero again.
I would like to multiple the points like this: 2 * 2 = 4 * 2 = 8 * 2 = 16 * 2...
(you get 2 points if you destroy an enemy).
I add the points here:
if (CGRectIntersectsRect(enemy.frame, player.frame)) {
points = points + 1;
[enemy removeFromParent];
}
I could always multiply the current points with 2, but I want to reset the combo multiplier if there is specific amount of time without getting points.
I hope someone can help me.
(code in objective c please)
It seems no more complicated than recording the time the last enemy was destroyed and then in the update: method deciding if the combo has elapsed as no more enemies were hit in whatever timeout period you allow.
I am not familiar with Sprite kit, but the update appears to pass the current time; excellent. You will need to record the following:
timeout (time): The current timeout. This will reduce as the game progresses, making it harder.
lastEnemyKillTime (time): the time the last enemy was killed.
comboPoints (integer): How many points the user gets per hit. This will increase as the combo extends.
points (integer): The current score.
So, something like this:
#interface MyClass ()
{
NSTimeInterval _timeout;
NSTimeInterval _lastEnemyKillTime;
BOOL _comboFactor;
NSUInteger _points;
}
#end
I guess Sprite Kit uses an init: method; use it to initialize the variables:
- (id)init
{
self = [super init];
if (self != nil) {
_timeout = 1.0;
_lastEnemyKillTime = 0.0;
_points = 0;
_comboPoints = 1;
}
}
The update: method would be something like:
- (void)update:(NSTimeInterval)currentTime
{
BOOL withinTimeout = currentTime - _lastEnemyKillTime <= _timeout;
if (CGRectIntersectsRect(enemy.frame, player.frame)) {
_inCombo = withinTimeout;
if (_inCombo)
_comboPoints *= 2;
_points += _comboPoint;
_lastEnemyKillTime = currentTime;
[enemy removeFromParent];
} else if (_comboPoints > 1 && !withinTimeout) {
_lastEnemyKillTime = 0.0;
_comboPoints = 1;
}
}
You need to keep track on the last enemy casual timestamp and the factor. When the next kill is processed, you check the timestamp, if it is below threshold, you raise the factor. The time of the current kill replaces the timestamp.
You could create a FightRecorder class as singleton, if you don't have a better place yet (services or sth).
NSDate *newKillTime = new NSDate;
FightRecorder recorder = [FightRecorder instance];
if([newKillTime timeIntervalSinceDate:recorder.lastKillTime] < SCORE_BOUNDS_IN_SEC) {
recorder.factor++; // could also be a method
points = points + [recorder calculateScore]; // do your score math here
}
else {
[recorder reset]; // set the inner state of the fight recorder to no-bonus
}
recorder.lastKillTime = newKillTime; // record the date for the next kill
I'm doing some glsl fractals, and I'd like to make the calculations bail if they're taking too long to keep the frame rate up (without having to figure out what's good for each existing device and any future ones).
It would be nice if there were a timer I could check every 10 iterations or something....
Failing that, it seems the best approach might be to track how long it took to render the previous frame (or previous N frames) and change the "iterate to" number dynamically as a uniform...?
Or some other suggestion? :)
As it appears there's no good way to do this in the GPU, one can do a simple approach to "tune" the "bail after this number of iterations" threshold outside the loop, once per frame.
CFTimeInterval previousTimestamp = CFAbsoluteTimeGetCurrent();
// gl calls here
CFTimeInterval frameDuration = CFAbsoluteTimeGetCurrent() - previousTimestamp;
float msecs = frameDuration * 1000.0;
if (msecs < 0.2) {
_dwell = MIN(_dwell + 16., 256.);
} else if (msecs > 0.4) {
_dwell = MAX(_dwell - 4., 32.);
}
So my "dwell" is kept between 32 and 256, and more optimistically raised than decreased, and is pushed as a uniform in the "gl calls here" section.
I create six (6) UIImageView's and add them to the view. I then create a timer running at 0.01 second intervals and incrementing the number by a set amount. Every so often the numbers just stop changing. Below is a sample of the code I'm running to better show what I'm doing.
NSTimer *newTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(numberTimerFired:) userInfo:nil repeats:YES]];
[newTimer fire];
// Assume that I've created six (6) UIImageView's and stored them in an array called digitImageViewArray (the right most UIImageView would be index 5)
- (void)numberTimerFired:(NSTimer *)newTimer
{
// self.currentNumber is the NSInteger property that is incremented each repetition
int tempScore = self.currentNumber;
int currentDigit = 5;
do {
int digit = tempScore % 10;
tempScore /= 10;
[[self.digitImageViewArray objectAtIndex:currentDigit] setImage:[self.numberImageArray objectAtIndex:digit]];
currentDigit--;
} while (tempScore !=0);
self.currentNumber += 133; // 133 can be any number to increment by
}
I have other conditions setup to stop the timer when the number reaches the final number. As I said, as this number goes up, whether the final number is 999,999 or 50,000 it just freezes intermittently as it rises. Any help would be greatly appreciated!
I also checked the Profile and watch CPU / memory usage. It's not even breaking 35% CPU and the memory usage is very insignificant. I've tried several fixes, such as adjusting the time interval the NSTimer runs at. However, if I leave the screen after it runs and come backā¦ it runs smoothly with no glitching.
I am trying to make a timer for my game that counts down from a number, let's call it 100. I am following the cocos2d best practices, and therefore I am not using a NSTimer. What I am looking to do is that every second, I want to numbers of this timer to change. I could probably find a way to do it using a spritesheet with all of the numbers from 100-0, but I know there is a way to do it using just the numbers 0-9 and their pictures.
This is the code that I am using, with the corresponding -(void)
[self schedule: #selector(tick:)];
[self schedule: #selector(tick2:) interval:1];
All in all, I would like to know how to make it count down from 100, but also to know how to make those ticks decrease the value by 1 every second.
Initialize an integer variable that will keep your countdown value:
int count = 100;
You will want to keep a label (CCLabelBMFont etc) to display this count value. I recommend Glyph Designer (or Hierro if you want something free) to generate the 0 to 9 cocos2D-compatible font bitmaps, which you can then use in your CCLabelBMFont:
CCLabelBMFont* countLabel = [CCLabelBMFont labelWithString:#"0" fntFile:#"myFont.fnt"];
Next, schedule a single tick function that will fire every second:
[self schedule: #selector(tick:) interval:1];
This tick function decrements count by 1 each time it is called. Also, add the condition that if count has reached 0, it will unschedule itself:
-void tick:(ccTime) dt
{
count --; // decrement count by 1 each time this function is called
if (count == 0)
[self unschedule: #selector(tick:)];
}
And finally, in your main update loop (or even in the tick function itself after you decrement your count), you can update and redraw this label with the latest value each time:
[countLabel setString:[NSString stringWithFormat:#"%i", count]];
All the best.