简体   繁体   中英

Multiple ints - They don't work at the same time (Obj-C)

I'm making a simple little game.

I have two ints:

1) One to make an object's position to be generated randomly on the Y- and X-axis.

2) One for the scoring function.

I use NSTimers to make the objects move, and for the score to add 1 every second.

The problem is that the game gets all bugged and the timers start going crazy when the both ints exist. If I remove the scoring int/timer, the objects move perfectly. And the other way around.

I can't seem to find the issue since it should be working.

Any ideas?

ViewController.h:

int scoreNumber;
int randomPosition;

ViewController.m:

#define IsIphone4 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )480 ) < DBL_EPSILON )

#define IsIphone5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

#define IsIphone6 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )667 ) < DBL_EPSILON )

#define IsIphone6Plus ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )736 ) < DBL_EPSILON )

- (void)obstaclesMoving {

obstacle.center = CGPointMake(obstacle.center.x - 1, obstacle.center.y);
obstacle2.center = CGPointMake(obstacle2.center.x - 1, obstacle2.center.y);
obstacle3.center = CGPointMake(obstacle3.center.x - 1, obstacle3.center.y);

if (IsIphone4) {

    if (obstacle.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 70;
        obstacle.center = CGPointMake(320, randomPosition);
    }

    if (obstacle2.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 360;
        obstacle2.center = CGPointMake(320, randomPosition);

    }

    if (obstacle3.center.x < 0) {
        randomPosition = arc4random_uniform(100);
        randomPosition = randomPosition + 215;
        obstacle3.center = CGPointMake(320, randomPosition);

    }

}

if (IsIphone5) {

    if (obstacle.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 70;
        obstacle.center = CGPointMake(320, randomPosition);
    }

    if (obstacle2.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 448;
        obstacle2.center = CGPointMake(320, randomPosition);

    }


    if (obstacle3.center.x < 0) {
        randomPosition = arc4random_uniform(100);
        randomPosition = randomPosition + 259;
        obstacle3.center = CGPointMake(320, randomPosition);

    }

}

if (IsIphone6) {

    if (obstacle.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 70;
        obstacle.center = CGPointMake(375, randomPosition);
    }

    if (obstacle2.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 547;
        obstacle2.center = CGPointMake(375, randomPosition);

    }


    if (obstacle3.center.x < 0) {
        randomPosition = arc4random_uniform(100);
        randomPosition = randomPosition + 309;
        obstacle3.center = CGPointMake(375, randomPosition);

    }

}

if (IsIphone6Plus) {

    if (obstacle.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 70;
        obstacle.center = CGPointMake(414, randomPosition);
    }

    if (obstacle2.center.x < 0) {
        randomPosition = arc4random_uniform(60);
        randomPosition = randomPosition + 616;
        obstacle2.center = CGPointMake(414, randomPosition);

    }


    if (obstacle3.center.x < 0) {
        randomPosition = arc4random_uniform(100);
        randomPosition = randomPosition + 343;
        obstacle3.center = CGPointMake(414, randomPosition);

    }

}

}

- (IBAction)characterUp:(id)sender {

characterDrop = 5;

}

- (IBAction)characterDown:(id)sender {

characterDrop = -5;

}

- (void)characterMoving {

character.center = CGPointMake(character.center.x, character.center.y - characterDrop);

characterDrop = characterDrop - 0.1;

if ((CGRectIntersectsRect(character.frame, ground.frame)) && (characterDrop < -1)) {

    [self gameOver];

    //Sound for G.O.
}

if ((CGRectIntersectsRect(character.frame, roof.frame)) && (characterDrop < -1)) {

    [self gameOver];

    //Sound for G.O.
}

}

- (IBAction)startGame:(id)sender {

startGameButton.hidden = YES;

characterMovement = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(characterMoving) userInfo:nil repeats:YES];

characterDrop = -5;

obstacleTimer = [NSTimer scheduledTimerWithTimeInterval:0.0055 target:self selector:@selector(obstaclesMoving) userInfo:nil repeats:YES];

scorer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(scoring) userInfo:nil repeats:YES];

}

- (void)scoring {

scoreNumber = scoreNumber + 1;
scoreLabelInGame.text = [NSString stringWithFormat:@"%i", scoreNumber];
scoreLabelGameOver.text = [NSString stringWithFormat:@"%i", scoreNumber];

}

- (void)gameOver {

if (scoreNumber > bestScoreNumber) {

    [[NSUserDefaults standardUserDefaults] setInteger:scoreNumber forKey:@"bestScoreSaved"];
    bestScoreLabel.text = [NSString stringWithFormat:@"New best: %i", scoreNumber];

}

character.hidden = YES;
obstacle.hidden = YES;
obstacle2.hidden = YES;
obstacle3.hidden = YES;
startGameButton.hidden = YES;
scoreLabelInGame.hidden = YES;
characterUpButton.hidden = YES;
characterDownButton.hidden = YES;
scoreLabelGameOver.hidden = NO;
bestScoreLabel.hidden = NO;
gameOverLabel.hidden = NO;
restartGameButton.hidden = NO;
backButton.hidden = NO;

[characterMovement invalidate];
[obstacleTimer invalidate];
[obstacleTimer2 invalidate];
[obstacleTimer3 invalidate];
[obstacleTimer4 invalidate];
[scorer invalidate];

}

- (void)viewDidLoad {

bestScoreNumber = [[NSUserDefaults standardUserDefaults] integerForKey:@"bestScoreSaved"];
bestScoreLabel.text = [NSString stringWithFormat:@"Best: %li", (long)bestScoreNumber];

scoreNumber = 0;

scoreLabelGameOver.hidden = YES;
bestScoreLabel.hidden = YES;
gameOverLabel.hidden = YES;
restartGameButton.hidden = YES;
backButton.hidden = YES;

[super viewDidLoad];
// Do any additional setup after loading the view.
}

I think a cleaner approach would be to move to a CADisplayLink or a single NSTimer and move your views off of the selector it calls.

/* Add _amountOfTicks as an instance Variable */
{
  int _amountOfTicks;
  int scoreNumber;
  int randomPosition;
}

/* replace timers in startGame */
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick)];
displayLink.frameInterval = 1;
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

- (void)tick {

  _amountOfTicks++;
  if (_amountOfTicks > 16){
    _amountOfTicks = 1;
  }

  if (_amountOfTicks == 2) {
     [self characterMoving] 
  }

  if (_amountOfTicks == 4) {
     [self obstaclesMoving] 
  }

  if (_amountOfTicks == 16) {
     [self scoring] 
  }

}

Also, in the method below you're reducing the center.x by 1 then changing it back to the screens width directly below when checking for macros.

- (void)obstaclesMoving {

obstacle.center = CGPointMake(obstacle.center.x - 1, obstacle.center.y); /* reduce by 1 */
obstacle2.center = CGPointMake(obstacle2.center.x - 1, obstacle2.center.y);
obstacle3.center = CGPointMake(obstacle3.center.x - 1, obstacle3.center.y);

if (IsIphone4) {

  if (obstacle.center.x < 0) {
    randomPosition = arc4random_uniform(60);
    randomPosition = randomPosition + 70;
    obstacle.center = CGPointMake(320, randomPosition); /* changes it back to screen width which makes what you did up above useless */
  }
}

From the docs :

the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds

My guess is that this maybe the issue.

If you need to your score increment every 1 sec, why you calling that function every 0.0055 sec?

You also need to move [super viewDidLoad]; to the top of you viewDidLoad function.

Also as @rmaddy stated, you shouldn't be explicitly checking for the screen size.

I can tell you that running a timer with a resolution of 1/180th of a second is going to get you into trouble. Since the frame is updated at most every 60th of a second, the user isn't going to see it. There is no guarantee that the timers will actually run that often (most likely they won't).

You can't use timers like that. You can only use them to trigger an event, and then you need to check exactly what time it is and what you should do.

What might be happening is that you managed to turn autolayout on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM