Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Hi

Having just "discovered" sprite kit, I am trying to make a game which has a countdown timer. But my on screen timer is jittering.

The timer itself works fine. A display string is created with the function below. This string is then displayed with a SKLabelNode. But the size of the SKLabelNode varies with 1 pixel. It's enough to cause jittering of the text for large font sizes. It's distracting and draws unwanted attention.

SKLabelNode doesn't have an anchor point, otherwise it would probably be an easy fix.
I tried fixing the position in the SKScene update: and didEvaluateActions: function, but that didn't work.
What more can I try to fix this?

Code:
-(NSString *) formattedTimeInterval:(NSTimeInterval) timeInterval
{
	NSInteger timeInteger = (NSInteger)(timeInterval*100); //require resolution of 0.01s
	NSInteger ms	= timeInteger % 100; // ms remainder
	NSInteger s		= (timeInteger / 100) % 60; // s remainder
	NSInteger min	= (timeInteger / 6000) % 60; //min remainder
	NSInteger hours = (timeInteger / 360000); //hours

	NSString *string = [NSString stringWithFormat:@"%@:%@:%@.%@",
						[_formatter stringFromNumber:@(hours)],
						[_formatter stringFromNumber:@(min)],
						[_formatter stringFromNumber:@(s)],
						[_formatter stringFromNumber:@(ms)]];

	return string;
}

The number formatter has these properties:
Code:
//setup number formatter
		_formatter = [[NSNumberFormatter alloc] init];
		[_formatter setNumberStyle:NSNumberFormatterDecimalStyle];
		[_formatter setMinimumFractionDigits:0];
		[_formatter setMaximumFractionDigits:0];
		[_formatter setFormatWidth:2];
		[_formatter setPaddingCharacter:@"0"];

Code:
-(void) didEvaluateActions
{
	SKLabelNode *countdownNode = (SKLabelNode *)[self childNodeWithName:kCountdown];
	CGSize size = [countdownNode frame].size;
	
	if (size.width == 237) //236
	{
		CGRect frame = [self frame];
		[countdownNode setPosition:CGPointMake(frame.size.width/2+0.5, //-0.5
											   frame.size.height - size.height - kPadding)];
	}
	
}
 
Last edited:
It might depend on the text alignment in the label. For example if it is center aligned 3:20 will be slightly to the left of 3:19 (the 1 is smaller than 2).


Also you could instead use this:

Code:
NSString *string = [NSString stringWithFormat:@"%02d:%02d:%02d.%03d", hours, min,s,ms];
 
I'm trying to find a solution on my school project to implement the countdown timer in the sprite kit, but my problem is each time the label gets updated the labels are generated on top of previous label.

could you please explain how to implement your code?
 
I'm trying to find a solution on my school project to implement the countdown timer in the sprite kit, but my problem is each time the label gets updated the labels are generated on top of previous label.

could you please explain how to implement your code?

Create a SKScene with a SKLabelNode. Give the label a name. In the update function of your SKScene, update the content of the SKLabelNode with the setText function. Don't generate a new label each time.

Otherwise post your code and we can provide feedback on how to improve it.
 
This is the NEW code. The problem also I'm having with this is, the timer doesnt show in the SKScene

Code:
@interface ViewController()
{
UILabel *progress;
    NSTimer *timer;
    int currMinute;
    int currSeconds;
}
@end


@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    progress=[[UILabel alloc] initWithFrame:CGRectMake(80, 15, 100, 50)];
    progress.textColor=[UIColor redColor];
    [progress setText:@"Time : 3:00"];
    progress.backgroundColor=[UIColor clearColor];
    [self.view addSubview:progress];
    currMinute=3;
    currSeconds=00;

    // Do any additional setup after loading the view, typically from a nib.
}
-(void)start
{
    timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];

}
-(void)timerFired
{
if((currMinute>0 || currSeconds>=0) && currMinute>=0)
{
    if(currSeconds==0)
    {
        currMinute-=1;
        currSeconds=59;
    }
    else if(currSeconds>0)
    {
        currSeconds-=1;
    }
    if(currMinute>-1)
    [progress setText:[NSString stringWithFormat:@"%@%d%@%02d",@"Time : ",currMinute,@":",currSeconds]];
}
    else
    {
        [timer invalidate];
    }
}
 
This is the NEW code. The problem also I'm having with this is, the timer doesnt show in the SKScene

Code:
@interface ViewController()
{
UILabel *progress;
    NSTimer *timer;
    int currMinute;
    int currSeconds;
}
@end


@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    progress=[[UILabel alloc] initWithFrame:CGRectMake(80, 15, 100, 50)];
    progress.textColor=[UIColor redColor];
    [progress setText:@"Time : 3:00"];
    progress.backgroundColor=[UIColor clearColor];
    [self.view addSubview:progress];
    currMinute=3;
    currSeconds=00;

    // Do any additional setup after loading the view, typically from a nib.
}
-(void)start
{
    timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];

}
-(void)timerFired
{
if((currMinute>0 || currSeconds>=0) && currMinute>=0)
{
    if(currSeconds==0)
    {
        currMinute-=1;
        currSeconds=59;
    }
    else if(currSeconds>0)
    {
        currSeconds-=1;
    }
    if(currMinute>-1)
    [progress setText:[NSString stringWithFormat:@"%@%d%@%02d",@"Time : ",currMinute,@":",currSeconds]];
}
    else
    {
        [timer invalidate];
    }
}

You are not using sprite kit elements. You are using a regular UILabel and a NSTimer. Spritekit has its own timer. Use that to your advantage.
In semi pseudocode, I would do something like this:

Code:
@implementation YourView (subclass of SKView)
-init
{
 YourSKSceneSubclass *yourScene = alloc YourSKSceneSubclass
[self presentScene:yourScene];
}


//user events (somehow you have to couple the start and stop event for your timer to the time at which they are generated. Then you pass this time to your scene)
-(ibaction) startCountDown:(NSEvent) event
{
 [self.scene startCountDown:[event timestamp]]; 
}

-(ibaction) stopCountDown:(NSEvent) event
{
 [self.scene stopCountDown:[event timestamp]]; 
}


@end


@implementation YourSKSceneSubclass (subclass of SKScene)
{
 NSTimerInterval _startTime; 
}
-(ibaction) startCountDown:(NSEvent) event
{
   _startTime = [event timestamp]; //this time when you start your counttime
  SKLabelScene *progessScene = alloc SKLabelScene
  [progessScene setName:@"countdown"]  //add the label to your view 
  [self addChild:progessScene];

}

-(void) stopCountDown
{
  [[self childNodeWithName:@"countdown"] removeFromParent];  //remove the label from view
}

-(void) update:(CFTimeInterval) currentTime
{
  CFTimeInterval expiredTime = currentTime - _startTime; //time that has passed since starting your timer
  CFTimeInterval remainingTime = <your time length in seconds> - expriredTime; // time that is left for the user
 [[self childNodeWithName:@"countdown"]  setText:....];

 if (remainingTime < 0)
   Time up. Game Over. Or whatever

}
 
I've been able to create the timer programmatically. :D
I'm not big fan of storyboard for now. I will upload the code later.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.