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

SunnyLi

Guest
Original poster
Oct 7, 2010
22
0
Hi Guys,

Im building just a simple game with a ball and a paddle at the bottom, everytime the ball hits the paddle you get 1 point. But the minute the score is increasing by 7-8 points everytime you hit the paddle. Im not sure where im going wrong could someone help.

Code:
#import "GameViewController.h"
#import "KeepyUppiesViewController.h"
#import "GameOverViewController.h"

@implementation GameViewController

@synthesize scoreLabel;
@synthesize score;
@synthesize ball;
@synthesize paddle;
@synthesize livesLabel;
@synthesize messageLabel;

- (void)startPlaying {
	if (!lives) {
		lives = 3;
		score = 0;
		
	}
	scoreLabel.text = [NSString stringWithFormat:@"%d", score];
	livesLabel.text = [NSString stringWithFormat:@"%d", lives];
	ball.center = CGPointMake(159, 239);
	ballMovement = CGPointMake(4,4);
	// choose whether the ball moves left to right or right to left
	if (arc4random() % 100 < 50)
		ballMovement.x = -ballMovement.x;
	messageLabel.hidden = YES;
	isPlaying = YES;
	/*
	[self initialiseTimer];
	*/
	[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];
	
}
- (void)pauseGame {
	[theTimer invalidate];
	theTimer = nil;
	
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
	
	[self startPlaying];
	
	ballMovement = CGPointMake(4,4);
	
	[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];



	 }
- (void)initialiseTimer {
	
	
	if (theTimer == nil) {
		
		float theInterval = 1.0f/50.0f;
		
		theTimer = [NSTimer scheduledTimerWithTimeInterval:theInterval target:self
												  selector:@selector(animateBall:) userInfo:nil repeats:YES];
		
	}
}

- (void)animateBall:(NSTimer *)theTimer {
	
	ball.center = CGPointMake(ball.center.x+ballMovement.x, ball.center.y+ballMovement.y);
	
	BOOL paddleCollision = ball.center.y >= paddle.center.y - 16 &&
	
	ball.center.y <= paddle.center.y + 16 &&
	ball.center.x > paddle.center.x - 32 &&
	ball.center.x < paddle.center.x + 32;
	

	if(paddleCollision)
		ballMovement.y = -ballMovement.y;
	
	
	if (ball.center.x > 310 || ball.center.x < 16)
		ballMovement.x = -ballMovement.x;
	
	if (ball.center.y < 32)
		ballMovement.y = -ballMovement.y;
	if (ball.center.y > 444) {
		[self pauseGame];
		isPlaying = NO;
		lives--;
		
		livesLabel.text = [NSString stringWithFormat:@"%d", lives];
		if (!lives) {
			messageLabel.text = @"Game Over";
			[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];
			
			GameOverViewController *second = [[GameOverViewController alloc] initWithNibName:nil bundle:nil];
			second.score = score;
			second.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
			[self presentModalViewController:second animated:YES];
			
			
		} else {
			messageLabel.text = @"Ball Hit The Floor :(";
		}
		messageLabel.hidden = NO;
	}


	
	if (CGRectIntersectsRect(ball.frame, paddle.frame)) {
		[self checkcollision];
			[B]stopdetection = FALSE;[/B]
		
	}
	
	
}

 - (void)checkcollision {
 if (!stopdetection && CGRectIntersectsRect(ball.frame, paddle.frame)) {
 
 
 [B]score ++;
 scoreLabel.text = [NSString stringWithFormat:@"%d", score];
 
 stopdetection = TRUE;[/B]
 
 float diff=ball.center.x - paddle.center.x;
 ballMovement.x=150;  // default if it hits the middle
 if (diff>150) {
 ballMovement.x=10;
 }
 if (diff<150) {
 ballMovement.x=-10;
 }
 
 
 }
 
 }
 
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	if (isPlaying) {
		
		UITouch *touch = [[event allTouches] anyObject];
		touchOffset = paddle.center.x -
		[touch locationInView:touch.view].x;
		
	} else {
		[self startPlaying];
		
	}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	if (isPlaying) {
		
		UITouch *touch = [[event allTouches] anyObject];
		float distanceMoved =([touch locationInView:touch.view].x + touchOffset) -paddle.center.x;
		float newX = paddle.center.x + distanceMoved;
		if (newX > 30 && newX < 290)
			
			paddle.center = CGPointMake( newX, paddle.center.y );
		
	}
}

I think its the placement of the bits in bold but im not sure to be honest.
 
Score goes up by more than one because your ball overlaps the paddle for several frames. You seem to have added a stopdetection flag to try to prevent this, but you set it back to FALSE immediately after setting it to TRUE.

In your code, I'd imagine you'd be better off incrementing the score at the same moment as you invert the y vector.
 
Score goes up by more than one because your ball overlaps the paddle for several frames. You seem to have added a stopdetection flag to try to prevent this, but you set it back to FALSE immediately after setting it to TRUE.

In your code, I'd imagine you'd be better off incrementing the score at the same moment as you invert the y vector.

Cheers for your reply :) yeh if i make the uiimageview really small i dont get as many problems with the score but occasionally i still get a 5 point increase/

Im not sure what you mean by the inver the y vector.
 
Been working on this again all day today, havent got much futher, the score is incrementing by 1 point each time but occasionally there is the 5 - 10 point increase.

Code:
#import "GameViewController.h"
#import "KeepyUppiesViewController.h"
#import "GameOverViewController.h"

@implementation GameViewController

@synthesize scoreLabel;
@synthesize score;
@synthesize ball;
@synthesize paddle;
@synthesize livesLabel;
@synthesize messageLabel;

- (void)startPlaying {
	if (!lives) {
		lives = 3;
		score = 0;
		
	}
	scoreLabel.text = [NSString stringWithFormat:@"%d", score];
	livesLabel.text = [NSString stringWithFormat:@"%d", lives];
	ball.center = CGPointMake(159, 239);
	ballMovement = CGPointMake(4,4);
	// choose whether the ball moves left to right or right to left
	if (arc4random() % 100 < 50)
		ballMovement.x = -ballMovement.x;
	messageLabel.hidden = YES;
	isPlaying = YES;
	/*
	[self initialiseTimer];
	*/
	[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];
	
}
- (void)pauseGame {
	[theTimer invalidate];
	theTimer = nil;
	
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
	
	[self startPlaying];
	
	ballMovement = CGPointMake(4,4);
	
	[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];



	 }
- (void)initialiseTimer {
	
	
	if (theTimer == nil) {
		
		float theInterval = 1.0f/50.0f;
		
		theTimer = [NSTimer scheduledTimerWithTimeInterval:theInterval target:self
												  selector:@selector(animateBall:) userInfo:nil repeats:YES];
		
	}
}

- (void)animateBall:(NSTimer *)theTimer {
	
	ball.center = CGPointMake(ball.center.x+ballMovement.x, ball.center.y+ballMovement.y);
	
	BOOL paddleCollision = ball.center.y >= paddle.center.y - 16 &&
	
	ball.center.y <= paddle.center.y + 16 &&
	ball.center.x > paddle.center.x - 32 &&
	ball.center.x < paddle.center.x + 32;
	

	if(paddleCollision)
		ballMovement.y = -ballMovement.y;
	
	
	if (ball.center.x > 310 || ball.center.x < 16)
		ballMovement.x = -ballMovement.x;
	
	if (ball.center.y < 32)
		ballMovement.y = -ballMovement.y;
	if (ball.center.y > 444) {
		[self pauseGame];
		isPlaying = NO;
		lives--;
		
		livesLabel.text = [NSString stringWithFormat:@"%d", lives];
		if (!lives) {
			messageLabel.text = @"Game Over";
			[self performSelector:@selector(initialiseTimer) withObject:nil afterDelay:2.0];
			
			GameOverViewController *second = [[GameOverViewController alloc] initWithNibName:nil bundle:nil];
			second.score = score;
			second.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
			[self presentModalViewController:second animated:YES];
			
			
		} else {
			messageLabel.text = @"Ball Hit The Floor :(";
		}
		messageLabel.hidden = NO;
	}


	
	[B]if (CGRectIntersectsRect(ball.frame, paddle.frame)) {
		
		
		score ++;
		scoreLabel.text = [NSString stringWithFormat:@"%d", score];
		
		[self checkcollision];
			stopdetection = FALSE;[/B]
	
	}
	
	
}

- (void)checkcollision {
	
		
		
		stopdetection = TRUE;
		
		float diff=ball.center.x - paddle.center.x;
		ballMovement.x=150;  // default if it hits the middle
		if (diff>150) {
			ballMovement.x=10;
		}
		if (diff<150) {
			ballMovement.x=-10;
		}
		

	
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	if (isPlaying) {
		
		UITouch *touch = [[event allTouches] anyObject];
		touchOffset = paddle.center.x -
		[touch locationInView:touch.view].x;
		
	} else {
		[self startPlaying];
		
	}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	if (isPlaying) {
		
		UITouch *touch = [[event allTouches] anyObject];
		float distanceMoved =([touch locationInView:touch.view].x + touchOffset) -paddle.center.x;
		float newX = paddle.center.x + distanceMoved;
		if (newX > 30 && newX < 290)
			
			paddle.center = CGPointMake( newX, paddle.center.y );
		
	}
}
 
You removed all the code that tests stopdetection. All that's left is one place that sets it to TRUE, and another place that sets it to FALSE. It almost looks like you're semi-randomly removing code and hoping it will work, instead of trying to analyze and understand the code you had.

The fix is only going to be apparent when you analyze the code you had, and understand how it wasn't working. The best way to analyze the code is to step through it manually, taking careful note of the state of the stopdetection variable.

Pretend you have a coworker you're walking through the code, and your job is to explain why your code does what it does, line by line. For example:
Explainer (you): "This tests the ball and paddle rects for intersection. If they intersect, it's a collision, so this block is executed. If no collision, it's not. When there's a collision, the score is incremented by one. Then the scorelabel's text is changed to the new score."

Explainee (me): "So the only condition for incrementing the score in the latest code is that the rects intersect. Does that seem correct, or is that what stopdetection was for?"

Explainer: _____​

By the way, this act of explaining to a coworker is part of a process called a code review. When you do it by yourself, it's called debugging.
 
You removed all the code that tests stopdetection. All that's left is one place that sets it to TRUE, and another place that sets it to FALSE. It almost looks like you're semi-randomly removing code and hoping it will work, instead of trying to analyze and understand the code you had.

The fix is only going to be apparent when you analyze the code you had, and understand how it wasn't working. The best way to analyze the code is to step through it manually, taking careful note of the state of the stopdetection variable.

Pretend you have a coworker you're walking through the code, and your job is to explain why your code does what it does, line by line. For example:
Explainer (you): "This tests the ball and paddle rects for intersection. If they intersect, it's a collision, so this block is executed. If no collision, it's not. When there's a collision, the score is incremented by one. Then the scorelabel's text is changed to the new score."

Explainee (me): "So the only condition for incrementing the score in the latest code is that the rects intersect. Does that seem correct, or is that what stopdetection was for?"

Explainer: _____​

By the way, this act of explaining to a coworker is part of a process called a code review. When you do it by yourself, it's called debugging.

Thanks for your reply, i was doing that to be honest to start off with. But noww ive been through the code and commented the main parts of the code. I just dont understand how to stop the score from increasing randomly some times. This is the code im not sure on:

Code:
if (CGRectIntersectsRect(ball.frame, paddle.frame)) {
		
	
		score ++;
		scoreLabel.text = [NSString stringWithFormat:@"%d", score];
		
		stopdetection = FALSE;
	
	}
	
	
}

- (void)checkcollision {
	
	if (!stopdetection && CGRectIntersectsRect(ball.frame, paddle.frame)) {	
		
		stopdetection = TRUE;
		
		float diff=ball.center.x - paddle.center.x;
		ballMovement.x=150;  // default if it hits the middle
		if (diff>150) {
			ballMovement.x=10;
		}
		if (diff<150) {
			ballMovement.x=-10;
		}
	}

	
}
 
Your code is still mostly wrong, because checkcollision is never called.

Going back to your original code:
Code:
	if (CGRectIntersectsRect(ball.frame, paddle.frame)) {
		[self checkcollision];
			stopdetection = FALSE;
		
	}
Think about exactly what happens here. In checkcollision (original version), you conditionally set stopdetection to TRUE. Then immediately after it returns, you always set stopdetection to FALSE. Logically, that makes no sense if the variable was just set to TRUE by checkcollision.

Now think about what ought to happen. When the ball and paddle first intersect, then that's a new collision (score increases). Next, you have to wait for the ball and paddle to stop intersecting, which signals the end of the collision. You should only start looking for new collisions after the end of the previous collision. It's this "no longer intersecting" part that all your code is missing. If you renamed the boolean variable to isColliding it might make more sense.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.