 |
|
 |
|
 |
01-25-2010, 01:15 PM
|
#1 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Need help with simple game :S
Hi all  ,
I am in the process of making my first iPhone game (I have made numerous utility type apps before). Instead of using Quartz, OpenGLES or any game engine, I have decided to simply use and animate UIImageViews (I plan to move onto the harder options later). There are some things, however, that I am struggling to do:
1) How to I create random instances of my UIImageView above the screen and allow them to fall?
2) How do I then get these images to stop on contact with the ones below them, but the screen continue to travel up?
3) How do I prevent my character (yet another UIImageView) from moving through the falling images, but be able to rest on top of them without falling (the rest of the time he will be falling)?
Sorry if this is a lot of questions, I have realised just how much harder making a game is to other types of apps :S. (P.S. I would appreciate any tutorial that anyone recommends)
Thanks,
Cam
|
|
|
01-25-2010, 01:44 PM
|
#2 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
This should get you started on the falling rocks:
Random Rocks
__________________
|
|
|
01-25-2010, 02:17 PM
|
#3 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Awesome, thanks!
I have now got blocks randomly falling from the top of the screen, but there are a couple of things wrong:
1)I want the blocks to stop falling when they reach the bottom, and instead of reappearing at the top, a new one is created. Is this possible?
2)The blocks go in from of my controls, how do I move them behind the controls?
Then on to collision detection!
Thanks
Cam
|
|
|
01-28-2010, 12:44 PM
|
#4 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
I have realised that the current code that I am using is causing the blocks to all fall to the bottom of the screen, whereas what I want is for the blocks to pile on top of themselves. I changes the code in the example smasher gave me to try to implement this, but it does not seem to have worked. The code I am currently using is posted below, but when built no blocks are created or animated down the screen.
Code:
- (void)viewDidLoad {
[super viewDidLoad];
self.gameState = kGameStatePaused;
blockVelocity = CGPointMake(kBlockSpeedX, kBlockSpeedY);
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(gameLoop) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(blockCollision) userInfo:nil repeats:YES];
}
-(void)gameLoop {
if(gameState == kGameStateRunning) {
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
block= [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = -100;
block.center = CGPointMake (x,y);
block.center = CGPointMake(block.center.x + blockVelocity.x, block.center.y + blockVelocity.y);
[self.view addSubview: block];
[block release];
}}
-(void)blockCollision {
CGPoint newCenter = block.center;
if (newCenter.y > 420){
newCenter.y = 420;
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
block= [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = -100;
newCenter = CGPointMake (x,y);
[self.view addSubview: block];
[block release]; }
if (CGRectIntersectsRect(block.frame, block.frame)){
newCenter.y = -10;
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
block= [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = -100;
newCenter = CGPointMake (x,y);
[self.view addSubview: block];
[block release]; }
block.center = newCenter;
}
Again, any help would be much appreciated!!
Thanks
Cam
|
|
|
01-28-2010, 03:59 PM
|
#5 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
The code you posted won't work, because you're creating a new UIImageView every time that gameLoop or blockCollision is called. You don't have an array to keep track of the blocks on the screen, and you don't have anything to make the blocks move down the screen. I'd go back to the working code that had blocks falling down the screen.
Making the blocks stop when they hit the bottom and stack up... there's no built-in methods for this. At this point you have to think about what method and what data structures you need to write to make it happen.
The method moveBlocks that you wrote needs to know when to *stop* moving a block. So... questions. When do you make a block stop moving? Answer: when it hits the bottom of the screen, or when the entire column below the current block is occupied by other blocks.
How do you know a block is at the bottom of the screen? Answer: Its y coordinate will be greater than some value, like the height of the screen minus the height of a block.
So, your moveBlocks method - the one that loops through all of the blocks - can have a line like if (block.y > screenheight) continue; that will make the loop skip that block once it hits the bottom.
If you get that working I'll explain one way you can tell if a column is occupied. Fingers tired.
__________________
|
|
|
01-29-2010, 02:14 PM
|
#6 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
This having worked before, I am mystified as to why it is not now :S.
Code:
- (void)viewDidLoad {
[super viewDidLoad];
self.gameState = kGameStatePaused;
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(moveBlocks) userInfo:nil repeats:YES];
}
-(void)createBlocks{
if (blockArray==nil){
blockArray = [[NSMutableArray alloc] init]; }
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
UIImageView *block;
for (int i = 0; i< 1; i++){
block = [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = 500;
block.center = CGPointMake (x,y);
[self.view addSubview: block];
[blockArray addObject: block];
[block release];
}
}
-(void)moveBlocks {
if(gameState == kGameStateRunning) {
for (UIImageView *block in blockArray) {
//move new center down
CGPoint newCenter = block.center;
newCenter.y = newCenter.y +10;
block.center = newCenter;
}
}
Thanks
Cam
(P.S. For all your help smasher, I' looking at purchasing your app  !)
|
|
|
01-29-2010, 02:51 PM
|
#7 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
No prob. That looks pretty good - but do you ever call [self createBlocks] and set gameState=kGameStateRunning to get the party started?
If that's not the problem, then what happens? Blocks don't appear, or blocks appear but don't move?
__________________
|
|
|
01-29-2010, 03:12 PM
|
#8 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Opps, silly me, I checked everything for bugs but the viewDidLoad method :S. Thanks a lot. I have now make a block fall and made it stop if it reaches the floor, how do I now start the cycle again?
if (newCenter.y > 420) {
newCenter.y = newCenter.y -10;
continue; }
Thanks
Cam
|
|
|
01-29-2010, 03:27 PM
|
#9 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
Excellent. The "continue" is a command you can use inside loops to skip to the next iteration of the loop; the rest of the loop after "continue" is skipped for this block.
When a block hits the bottom you can add it to a different array - maybe called stoppedBlocks. It'll have to be an instance variable like blockArray, and you'll have to init it somewhere.
Code:
if (newCenter.y > 420) {
[stoppedBlocks addObject: block];
[self addOneBlock];
continue;
}
//more moveBlocks stuff
//at the end of moveBlocks, remove all stoppedBlocks from the blockArray
[blockArray removeObjectsInArray:stoppedBlocks];
}
You'll also have to write the method createOneBlock to create one new block. it'll look a lot like createBlocks, but without the loop.
Note this still won't make blocks stop when they hit other blocks, that'll have to wait until this is working.
Edit: I just realized that it'll crash when you try to add a block to the array while still looping through it. Post your moveBlocks code after you add this code, and I'll fix the loop so you can add blocks while looping.
__________________
Last edited by smasher; 01-29-2010 at 05:53 PM.
|
|
|
01-30-2010, 03:57 AM
|
#10 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Does this look righto to you then?
Code:
-(void)createFirstBlock{
if (blockArray==nil){
blockArray = [[NSMutableArray alloc] init]; }
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
UIImageView *block;
for (int i = 0; i< 1; i++){
block = [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = -500;
block.center = CGPointMake (x,y);
[self.view addSubview: block];
[blockArray addObject: block];
[block release];
}
}
-(void)addOneBlock {
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
UIImageView *block;
block= [[UIImageView alloc] initWithImage: blockImage];
//pick a position *above* the top of the screen
int x = arc4random()%320;
int y = -500; // place at top of the screen
block.center = CGPointMake (x,y);
[self.view addSubview: block];
[blockArray addObject: block];
[block release];
}
-(void)moveBlocks {
if(gameState == kGameStateRunning) {
for (UIImageView *block in blockArray) {
//move new center down
CGPoint newCenter = block.center;
newCenter.y = newCenter.y +10;
if (newCenter.y > 420) {
if (stoppedBlocks==nil){
stoppedBlocks = [[NSMutableArray alloc] init]; }
newCenter.y = newCenter.y -10;
[stoppedBlocks addObject: block];
[self addOneBlock];
continue;
[blockArray removeObjectsInArray: stoppedBlocks];
}
block.center = newCenter; }
}
else {
if (showPlay.hidden) {
showPlay.hidden = NO;}
if (showInstructions.hidden) {
showInstructions.hidden = NO;}
if (showOpenfeint.hidden) {
showOpenfeint.hidden = NO;}
}
}
|
|
|
01-30-2010, 11:07 AM
|
#11 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
Not bad. Since createFirstBlock and addOneBlock do essentially the same thing, so you only need one of them, not both. I'd remove the loop from createFirstBlock (you don't need to loop from 0 to 0) and keep that one. Or you could redeclare it as "createBlocks  int)numBlocks" and use the loop to create the desired number of blocks.
Code:
-(void)createOneBlock{
if (blockArray==nil){
blockArray = [[NSMutableArray alloc] init]; }
UIImage *blockImage = [UIImage imageNamed:@"block.png"];
UIImageView *block;
block = [[UIImageView alloc] initWithImage: blockImage];
int x = arc4random()%320;
int y = -500;
block.center = CGPointMake (x,y);
[self.view addSubview: block];
[blockArray addObject: block];
[block release];
}
-(void)moveBlocks {
if(gameState == kGameStateRunning) {
for (int i=0; i< [blockArray count]; i++) {
UIImageView *block = [blockArray objectAtIndex:i];
//move new center down
CGPoint newCenter = block.center;
newCenter.y = newCenter.y +10;
if (newCenter.y > 420) {
if (stoppedBlocks==nil){
stoppedBlocks = [[NSMutableArray alloc] init];
}
newCenter.y = newCenter.y -10;
[stoppedBlocks addObject: block];
[self createOneBlock];
continue;
}
block.center = newCenter;
}
[blockArray removeObjectsInArray: stoppedBlocks];
}
else {
if (showPlay.hidden) {
showPlay.hidden = NO;}
if (showInstructions.hidden) {
showInstructions.hidden = NO;}
if (showOpenfeint.hidden) {
showOpenfeint.hidden = NO;}
}
}
I changed the type of the loop so that we could add items from the array while the loop is running - you can't make changes to the array while doing the "fast enumeration" loop we had before. I also moved the blockArray removeObjectsInArray: outside the loop; we really only need to do that once after the loop is over.
I think that will do the trick. Test it out; blocks should fall, stop at the bottom of the screen, and a new block should appear.
__________________
Last edited by smasher; 01-30-2010 at 11:12 AM.
|
|
|
01-30-2010, 12:49 PM
|
#12 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Awsome, thanks! You are teaching me so much! Right, now on to stacking the blocks!
Thanks,
Cam
(P.S. Is there any way to randomise the size of the falling blocks??)
|
|
|
01-30-2010, 01:32 PM
|
#13 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
Quote:
Originally Posted by iPhoneDevelopment
Awsome, thanks! You are teaching me so much! Right, now on to stacking the blocks!
(P.S. Is there any way to randomise the size of the falling blocks??)
|
UIImageView inherits from UIView, so you can use any UIView properties or methods. To change the size of a block you could change the "frame" property or you could change the "transform" property. I'd do this just before you set the center of the new block.
Code:
//change the frame
CGRect newFrame = block.frame;
int newSize = arc4random() % 32 + 1; // returns a number from 1 to 32
newFrame.size = CGPointMake(newSize,newSize);
block.frame = newFrame;
I'll do the stacking later today.
__________________
|
|
|
01-30-2010, 05:55 PM
|
#14 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
Okay, stacking blocks. You had this line in your moveBlocks method, to stop the blocks when they reach the bottom of the screen:
Code:
if (newCenter.y > 420) {
We want to change that to this, which will trigger if we're touching the bottom *or* our new method returns true:
Code:
if (newCenter.y > 420 || [self isTouchingStoppedBlock:block]) {
"isTouchingStoppedBlock" is a method we need to write. It will return true if the current block is touching a stopped block (meaning the new block should stop too).
Code:
-(bool) isTouchingStoppedBlock:(UIImageView*)block{
//create a new rectangle, based on the current block's frame
CGRect lowerFrame = block.frame;
//but slightly lower on the screen
// "10" should be a constant: how far a block moves in one frame
lowerFrame.origin.y = lowerFrame.origin.y+10;
//now check if this lower rectangle is touching any other stopped block.
//if it's touching a stopped block, we return true.
for (UIImageView* stoppedBlock in blockArray){
if( CGRectIntersectsRect(lowerFrame.fame, stoppedBlock.frame) )
return true;
}
return false;
}
I haven't compiled this code, so apologies for any typos. Let me know if it works.
__________________
|
|
|
01-31-2010, 03:41 AM
|
#15 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
It worked!! (the only change I made was to remove '.frame' from 'lowerFrame' in the 'CGRectIntersectsRect' statement)
I have written this code to detect swipes and move the character left and right:
Code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
character.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:@"character.png"],
[UIImage imageNamed:@"character2.png"], nil];
character.animationDuration = 0.5;
character.animationRepeatCount = 1;
[character startAnimating];
[self.view addSubview:character];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];
if (fabsf(startTouchPosition.x - currentTouchPosition.x) >= HORIZ_SWIPE_DRAG_MAX &&
fabsf(startTouchPosition.y - currentTouchPosition.y) <= VERT_SWIPE_DRAG_MIN)
{
if (startTouchPosition.y < currentTouchPosition.y)
[self characterJump:touches withEvent:event]; }
CGPoint location = [touch locationInView:touch.view];
CGPoint xLocation = CGPointMake(location.x,character.center.y);
character.center = xLocation;
}
Xcode returns a ton of errors when I try to compile it.. but I'm not sure why?? I also want my character to jump when a swipe is detected, but I don't want to just animate him because then he wont react to landing on a block (I want him to always be travelling down the screen, unless he is on a block or in a jump).
Sorry if this is a lot of questions :S
Cam
Last edited by iPhoneDevelopment; 01-31-2010 at 05:17 AM.
|
|
|
01-31-2010, 11:06 AM
|
#16 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
I don't see any syntax errors in that code, except that you declared "UITouch *touch" twice in the same method. The second time you assign that variable you don't need to declare it again, just assign it.
There is some kind of logic error though - startTouchPosition and currentTouchPosition will always be the same, they'll always be the location of the touch as it moves. You probably want to make startTouchPosition an instance variable and set it in touchesBegan; then you can get the distance from the start of the touch to the current position, right?
Now that you have your array of stopped blocks, you should be able to use the same trick for your jumping guy. Compute his next position, then see if his new position frame touches a stopped block.
__________________
|
|
|
01-31-2010, 11:55 AM
|
#17 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
The code I am now using:
Code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
character.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:@"character.png"],
[UIImage imageNamed:@"character2.png"], nil];
character.animationDuration = 0.5;
character.animationRepeatCount = 1;
[character startAnimating];
[self.view addSubview:character];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];
if (currentTouchPosition.y > startTouchPosition.y) {
[self characterJump:touches withEvent:event]; }
CGPoint location = [touch locationInView:touch.view];
CGPoint xLocation = CGPointMake(location.x,character.center.y);
character.center = xLocation;
}
-(void) characterJump {
}
But Xcode tells me that I have not declared startTouchPosition, and that warning: incompatible Objective-C types 'JumpViewController*', expected 'UIView*' when passing argument 1 of 'locationInView:' from distinct Objective-C type??
Last edited by iPhoneDevelopment; 01-31-2010 at 12:00 PM.
|
|
|
01-31-2010, 12:19 PM
|
#18 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
You should declare startTouchPosition as an instance variable (put it in the .h file between the brackets of the @interface ).
Re: the other error, you're passing a controller where the compiler expects you to pass a view. Use locationInView:self.view instead of locationInView:self .
__________________
|
|
|
01-31-2010, 01:21 PM
|
#19 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Sorry to be a nuisance, but I cant get my character to fall down after he has jumped a certain height. I also want him to fall continuously, but only after the first swipe (so that he doesn't disappear before the user can make him jump), or, as I said earlier, if he is resting on a block.
I know I am asking a lot of questions which is probably annoying, sorry :S.
Cam
|
|
|
01-31-2010, 03:34 PM
|
#20 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
It sounds like you need some more state variables - like playerJumpStep to tell you which frame of the jump you're on (1-5 for up, 6-10 for down maybe?) and firstSwipeDone (set it to false initially, set it to true when you detect a swipe). Once you have that info you can make decisions based on it.
__________________
|
|
|
02-01-2010, 02:53 PM
|
#21 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
I
Last edited by iPhoneDevelopment; 02-02-2010 at 02:20 PM.
|
|
|
02-02-2010, 02:21 PM
|
#22 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
I have read close to 30 different tutorials now, but have got barely any further than where I was before, so I have come back to the place where I have got the best info from in the past....
I am, yet again, having some problems:
1) I have set up a variable to prevent my character from falling until the first swipe has been detected:
Code:
@interface: BOOL firstSwipe
@property (nonatomic, assign) BOOL firstSwipe;
- (void)viewDidLoad {
firstSwipe = false; }
-(void)moveBlocks {
if(gameState == kGameStateRunning) {
if (firstSwipe = true) {
character.transform = CGAffineTransformTranslate(character.transform, 0.0, 15.0); }
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(gameState == kGameStateRunning) {
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.view];
if (fabsf(startTouchPosition.x - currentTouchPosition.x) >= HORIZ_SWIPE_DRAG_MAX &&
fabsf(startTouchPosition.y - currentTouchPosition.y) <= VERT_SWIPE_DRAG_MIN)
{
if (currentTouchPosition.y > startTouchPosition.y) {
[self characterJump];
firstSwipe = true; } }
But my character falls whether the first swipe has happened or not!
2) How do I make the the blocks continue to fall when they reach the bottom of the screen or each other (instead of just stop) to simulate that the screen is moving (I tried changing the
Code:
if (newCenter.y > 420 || [self isTouchingStoppedBlock:block]) {
if (stoppedBlocks==nil){
stoppedBlocks = [[NSMutableArray alloc] init];
}
newCenter.y = newCenter.y -10;
to newCenter.y -5 but it didn't do anything)?
The only thing I have done successfully is to make the character jump!
Thanks for all your help
Cam
|
|
|
02-02-2010, 10:36 PM
|
#23 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,577
|
The line "if (firstSwipe = true)" should use == instead. One equals sign sets the value of a variable, two does comparison. Easy mistake!
If you want it to look like the screen is scrolling up (blocks, even stopped ones are scrolling down) then you'll have to move every block down by a few pixels, even the stopped ones. I'd put two more loops at the bottom of your moveBlocks method to scroll everything down a little.
__________________
Last edited by smasher; 02-02-2010 at 10:39 PM.
|
|
|
02-03-2010, 03:20 PM
|
#24 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
⎮⎮⎮
Last edited by iPhoneDevelopment; 02-04-2010 at 01:20 PM.
|
|
|
02-04-2010, 01:20 PM
|
#25 (permalink)
|
|
App Developer
Join Date: Dec 2009
Posts: 58
|
Just a slight problem: I have set firstSwipe to true when the first swipe has been detected, but when I run it, the character falls as soon as the swipe has happened, without the jump happening first. I thought that moving the firstSwipe = true statement to the end of the character jump method would solve the problem, but it doesn't seem to have any effect.
Thanks
Cam
|
|
|
 |
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
» Advertisements |
» Online Users: 368 |
| 27 members and 341 guests |
| alekssebasstrs, ashishjraval, divis_2k, dre, Ed99, Erle, Eskema, Gudus, happymondays, harikant_jammi, hobbyCoder, Hololont, ifan, JasonR, joalta, jwutke, lepetitapps, mac514, Mr.David, Prajakta, preethaAjayan, sanjeev.sharma, scalar, scotopia, warmi, xyster, zacware |
| Most users ever online was 779, 05-11-2009 at 09:55 AM. |
» Stats |
Members: 24,335
Threads: 39,130
Posts: 171,565
Top Poster: smasher (2,577)
|
| Welcome to our newest member, Mr.David |
|