SpriteKit Add node in empty location with duration - objective-c

I need some help.
I am developing a game and I have two questions.
Quick explanation of game :
There are three different nodes (shark (player), water ball and brick )
When the game starts there are one shark, four water balls and eight bricks.
when shark contacts with water ball, player earns point, water ball disappears and game adds another water ball in random location,
When shark contacts with brick shark dies and disappear from the screen.
My questions are;
First : When we hit the water ball how do we add the water ball in empty location. How do I make sure new water ball will be in different location then bricks and other water balls?
Second:
I want to wait a few seconds before I add the new water ball. How do I do that?
Here is some part of my code.
Thank you,
-(void) addWaterBallTopLeft {
WaterBall *waterBall = [WaterBall waterBallAtPosition:CGPointMake
([Util randomWithMin:(self.frame.size.width/10) + self.waterBall.size.width max:self.frame.size.width/2-self.brickT.size.width],
[Util randomWithMin:(self.frame.size.height- (self.frame.size.height/4)) + self.brickW.size.height max:self.frame.size.height-20])];
waterBall.name = #"WATERBALLTL";
[self addChild:waterBall ];
}
-(void) addWaterBallTopRight {
WaterBall *waterBall = [WaterBall waterBallAtPosition:CGPointMake([Util randomWithMin:self.frame.size.width/2+20 max:self.frame.size.width-20], [Util randomWithMin:(self.frame.size.height- (self.frame.size.height/4)-20) max:self.frame.size.height-20])];
waterBall.name = #"WATERBALLTR";
[self addChild:waterBall ];
}
-(void) addWaterBallBottomLeft {
WaterBall *waterBall = [WaterBall waterBallAtPosition:CGPointMake([Util randomWithMin:20 max:self.frame.size.width/2-20], [Util randomWithMin:(self.frame.size.height/2)+20 max:(self.frame.size.height- (self.frame.size.height/4)-20)])];
waterBall.name = #"WATERBALLBL";
[self addChild:waterBall];
}
-(void) addWaterBallBottomRight {
WaterBall *waterBall = [WaterBall waterBallAtPosition:CGPointMake([Util randomWithMin:self.frame.size.width/2+20 max:self.frame.size.width-20], [Util randomWithMin:(self.frame.size.height/2)+20 max:(self.frame.size.height- (self.frame.size.height/4)-20)])];
waterBall.name = #"WATERBALLBR";
[self addChild:waterBall];
}
-(void) addBrick {
BrickW *brickW1 = [BrickW BrickWAtPosition:CGPointMake( (self.frame.size.width/12)* 1 , self.frame.size.height - self.frame.size.height * 0.25) ];
[self addChild:brickW1];
BrickW *brickW2 = [BrickW BrickWAtPosition:CGPointMake( (self.frame.size.width/12)* 3 , self.frame.size.height - self.frame.size.height * 0.25) ];
[self addChild:brickW2];
BrickW *brickW3 = [BrickW BrickWAtPosition:CGPointMake( (self.frame.size.width/12)* 9, self.frame.size.height - self.frame.size.height * 0.25)];
[self addChild:brickW3];
BrickW *brickW4 = [BrickW BrickWAtPosition:CGPointMake( (self.frame.size.width/12)* 11, self.frame.size.height - self.frame.size.height * 0.25)];
[self addChild:brickW4];
BrickT *brickT1 = [BrickT BrickTAtPosition:CGPointMake( self.frame.size.width/2 , (self.frame.size.height / 24)*23 )];
[self addChild:brickT1];
BrickT *brickT2 = [BrickT BrickTAtPosition:CGPointMake( self.frame.size.width/2 , (self.frame.size.height / 24)*21 ) ];
[self addChild:brickT2];
BrickT *brickT3 = [BrickT BrickTAtPosition:CGPointMake( self.frame.size.width/2 , (self.frame.size.height / 24)*13 )];
[self addChild:brickT3];
BrickT *brickT4 = [BrickT BrickTAtPosition:CGPointMake( self.frame.size.width/2 , (self.frame.size.height / 24)*15)];
[self addChild:brickT4];
}
- (void) didBeginContact:(SKPhysicsContact *)contact {
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
} else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if ( firstBody.categoryBitMask == CollisionCategoryBrick && secondBody.categoryBitMask == CollisionCategoryShark ) {
NSLog(#"BRICK");
[contact.bodyB.node removeFromParent];
} else if ( firstBody.categoryBitMask == CollisionCategoryWaterBall && secondBody.categoryBitMask == CollisionCategoryShark ) {
NSLog(#"BALL");
self.addSeconds =YES;
[contact.bodyA.node removeFromParent];
[self addPoints:PointsPerHit];
if (![ self childNodeWithName:#"WATERBALLTL"]) {
[self addWaterBallTopLeft];
}
if (![ self childNodeWithName:#"WATERBALLTR"]) {
[self addWaterBallTopRight];
}
if (![ self childNodeWithName:#"WATERBALLBL"]) {
[self addWaterBallBottomLeft];
}
if (![ self childNodeWithName:#"WATERBALLBR"]) {
[self addWaterBallBottomRight];
} }
NSLog(#"%lu", (unsigned long)[self.children count]);
}
-(void)update:(CFTimeInterval)currentTime {
if (startGamePlay){
startTime = currentTime;
startGamePlay = NO;
}
timeSinceStart = (currentTime -startTime);
countDownInt = 1000 - (int)(currentTime-startTime);
if (countDownInt > 0 && self.addSeconds == NO) {
countDown.text = [NSString stringWithFormat:#"%i", countDownInt];
} else if(countDownInt > 0 && self.addSeconds == YES){
startTime +=2;
countDown.text = [NSString stringWithFormat:#"%i", countDownInt];
self.addSeconds = NO;
}
if (countDownInt == 0 ){
countDown.text =#"0";
Level2 *level2 = [Level2 sceneWithSize:self.frame.size];
SKTransition *transition = [SKTransition fadeWithDuration:0.5];
[self.view presentScene:level2 transition:transition];
}
}

//answer of your second question use a skaction sequence which would fire a function after 1 second
SKAction *Timetofire= [SKAction sequence:#[
//time after you want to fire a function
[SKAction waitForDuration:1],
[SKAction performSelector:#selector(urFunction)
onTarget:self]
]];
[self runAction:Timetofire withKey:#"key"];
//if you want your function eld fire x number of time
[self runAction:[SKAction repeatAction:Timetofire count:10]];
where x in number of times you wan't your function to fire
//if you want your function fire forever
[self runAction:[SKAction repeatActionForever:Timetofire ]];
1)now the answer of your first question used predefined NSMutableArray to store multiple CGPoint. where each CGPoint define the position of your shark,ball and other item be sure that the value of each CGPoint is different from each other which would give your item a random occurrence.

Related

Objective C Sprite Kit Multiple Collisions

I am currently working on a sprite kit game, with Objective-C. So far, I have everything working in order, however I am trying to accomplish multiple collisions and can't seem to accomplish this.
This is my code:
- (void)didBeginContact:(SKPhysicsContact *)contact
{
NSLog(#"contact!");
SKNode * nodeA = contact.bodyA.node;
SKNode *nodeB =contact.bodyB.node;
NSLog(#"%#", nodeA.name);
if ([contact.bodyA.node.name isEqualToString:#"david"] == YES ||
[contact.bodyB.node.name isEqualToString:#"david"] == NO) {
[self runAction:self.soundAction];
SKNode * nodeB = contact.bodyB.node;
SKAction * remove = [SKAction removeFromParent];
[nodeB runAction:remove];
counter++;
updateLabel = true;
}
else if([contact.bodyA.node.name isEqualToString:#"rock"] == YES ||
[contact.bodyB.node.name isEqualToString:#"rock"] == YES) {
SKAction * remove = [SKAction removeFromParent];
[nodeB runAction:remove];
for (int i = 0; i < 100; i++) {
SKSpriteNode * rock = [[SKSpriteNode alloc] initWithColor:[SKColor orangeColor] size:CGSizeMake(10, 10)];
rock.position = CGPointMake(CGRectGetMidX(self.frame) + skRand(-40, 40), CGRectGetMidY(self.frame) + 100 + skRand(-40, 40));
rock.name = #"rock";
rock.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rock.size];
rock.physicsBody.usesPreciseCollisionDetection = YES;
rock.physicsBody.contactTestBitMask = 0x1;
[self addChild:rock];
CGVector dir = CGVectorMake(skRand(-5, 5), skRand(1, 4));
[rock.physicsBody applyImpulse:dir];
}
}
}

UIPinchGestureRecognizer trouble

Ok, i've read a few posts on this one (ex. UIImageView Gestures (Zoom, Rotate) Question) but I can't seem to fix my problem.
I have the following setup: an SKScene, an SKNode _backgroundLayer and 9 SKSpriteNodes that are tiles that make up the background and are attached to the _backgroundLayer.
Since these 9 tiles make a 3x3 square and they are quite large, I need to be able to zoom in and look at other SKSpriteNodes that will be on top of these 9 background images.
There are two problems:
1) When I pinch to zoom in or zoom out it seems like it is zooming in/out from location (0,0) of the _backgroundLayer and not from the touch location.
2) I have added some bounds so that the user can not scroll out of the 9 background images. In general it works. However, if I zoom in then move towards the top of the 9 background images and then zoom out the bounding conditions go berserk and the user can see the black space outside the background images. I need a way to limit the amount of zooming out that the user can do depending on where he's at.
Any ideas? Thanks!
I include my code below:
#import "LevelSelectScene.h"
#import "TurtleWorldSubScene.h"
#interface LevelSelectScene ()
#property (nonatomic, strong) SKNode *selectedNode;
#end
#implementation LevelSelectScene
{
SKNode *_backgroundLayer;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
_backgroundLayer = [SKNode node];
_backgroundLayer.name = #"backgroundLayer";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[_backgroundLayer setScale:0.76];
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && IS_WIDESCREEN) {
} else {
[_backgroundLayer setScale:0.36];
}
[self addChild:_backgroundLayer];
SKTexture *backgroundTexture = [SKTexture textureWithImageNamed:#"levelSelect"];
int textureID = 0;
for (int i = 0; i<3; i++) {
for (int j = 0; j<3; j++) {
SKSpriteNode *background = [SKSpriteNode spriteNodeWithTexture:backgroundTexture];
background.anchorPoint = CGPointZero;
background.position = CGPointMake((background.size.width)*i, (background.size.height)*j);
background.zPosition = 0;
background.name = [NSString stringWithFormat:#"background%d", textureID];
textureID++;
[_backgroundLayer addChild:background];
}
}
[TurtleWorldSubScene displayTurtleWorld:self];
}
return self;
}
- (void)didMoveToView:(SKView *)view {
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanFrom:)];
[[self view] addGestureRecognizer:panGestureRecognizer];
//UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
// [self.view addGestureRecognizer:tapRecognizer];
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinch:)];
[[self view] addGestureRecognizer:pinchGestureRecognizer];
}
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
SKNode *node = [self nodeAtPoint:touchLocation];
_selectedNode = node;
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:recognizer.view];
translation = CGPointMake(translation.x, -translation.y);
CGPoint initialPosition = CGPointAdd(_backgroundLayer.position, translation);
_backgroundLayer.position = [self boundLayerPos:initialPosition];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
float scrollDuration = 0.2;
CGPoint velocity = [recognizer velocityInView:recognizer.view];
CGPoint pos = [_backgroundLayer position];
CGPoint p = CGPointMultiplyScalar(velocity, scrollDuration);
CGPoint newPos = CGPointMake(pos.x + p.x, pos.y - p.y);
newPos = [self boundLayerPos:newPos];
[_backgroundLayer removeAllActions];
SKAction *moveTo = [SKAction moveTo:newPos duration:scrollDuration];
[moveTo setTimingMode:SKActionTimingEaseOut];
[_backgroundLayer runAction:moveTo];
}
}
- (void)handlePinch:(UIPinchGestureRecognizer *) recognizer
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if(_backgroundLayer.xScale*recognizer.scale < 0.76) {
//SKSpriteNode *backgroundTile = (SKSpriteNode *)[_backgroundLayer childNodeWithName:#"background0"];
[_backgroundLayer setScale:0.76];
} else if(_backgroundLayer.xScale*recognizer.scale > 2) {
[_backgroundLayer setScale:2.0];
} else {
[_backgroundLayer runAction:[SKAction scaleBy:recognizer.scale duration:0]];
}
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && IS_WIDESCREEN) {
} else {
if(_backgroundLayer.xScale*recognizer.scale < 0.36) {
[_backgroundLayer setScale:0.36];
} else if(_backgroundLayer.xScale*recognizer.scale > 2) {
[_backgroundLayer setScale:2.0];
} else {
[_backgroundLayer runAction:[SKAction scaleBy:recognizer.scale duration:0]];
}
}
recognizer.scale = 1;
}
- (CGPoint)boundLayerPos:(CGPoint)newPos {
SKSpriteNode *backgroundTile = (SKSpriteNode *)[_backgroundLayer childNodeWithName:#"background0"];
CGPoint retval = newPos;
retval.x = MIN(retval.x, 0);
retval.x = MAX(retval.x, -(backgroundTile.size.width*_backgroundLayer.xScale*3)+self.size.width);
retval.y = MIN(retval.y, 0);
retval.y = MAX(retval.y, -(backgroundTile.size.height*_backgroundLayer.xScale*3)+self.size.height);
return retval;
}

If Else satement working but not updating cocos2d

i have tested my code by changing the starting lives vaule, the problem is it doesn't remove them as the statement becomes valid, How do i fix this? I have tried placing it in my .m file but it doesn't seem to work properly anywhere, any ideas on where it would go? I would post the .m but it is about 500 lines so it is a bit big so i just pasted the relevant bit of it. also i am a 15 year old, and i am fairly new to cocos2d development
The Code
- (void) addMonster {
CCSprite * monster = [CCSprite spriteWithFile:#"startH.png"];
// Determine where to spawn the monster along the Y axis
CGSize winSize = [CCDirector sharedDirector].winSize;
int minY = monster.contentSize.height / 2;
int maxY = winSize.height - monster.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = ccp(winSize.width + monster.contentSize.width/2, actualY);
[self addChild:monster];
// Determine speed of the monster}
if (Strategyscore < 10) {
int minDuration = 5.0;
int maxDuration = 10.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
eate the actions
CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(-monster.contentSize.width/2, actualY)];
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
[_monsters removeObject:node];
Life--;
CCSprite *Life3 = [CCSprite spriteWithFile:#"heart.png"];
Life3.position = ccp(210,200);
CCSprite *Life2 = [CCSprite spriteWithFile:#"heart.png"];
Life2.position = ccp(220,200);
CCSprite *Life1 = [CCSprite spriteWithFile:#"heart.png"];
Life1.position = ccp(230,200);
[self addChild:Life3];
[self addChild:Life2];
[self addChild:Life1];
if(Life == 2) {
[self removeChild:Life3];
}
else if(Life == 1) {
[self removeChild:Life2];
[self removeChild:Life3];
}
else if(Life <= 0) {
[self removeChild:Life1];
[self removeChild:Life2];
[self removeChild:Life3];
// Cr [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[MainMenu scene]]];
}
}];
[monster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
//collision stuff
monster.tag = 1;
[_monsters addObject:monster];
}
Also the .h file
int StrategyBullet;
int Strategyscore;
int high;
int Life;
CCLabelTTF *highlabel;
CCLabelTTF *StrategyBulletLabel;
CCLabelTTF *StrategyscoreLabel;
#interface Strategy: CCLayer
{
NSMutableArray * _monsters;
NSMutableArray * _projectiles;
int _monstersDestroyed;
}
+(CCScene *) scene;
#end
Every time you add a new monster, you add a new set of sprites Life1,Life2, and Life3, superimposed on the previous ones. You probably want to have a single set of life hearts.
in .h
CCSprite *Life1,*Life2,*Life3;
in .m, init method
Life3 = [CCSprite spriteWithFile:#"heart.png"];
Life3.position = ccp(210,200);
Life2 = [CCSprite spriteWithFile:#"heart.png"];
Life2.position = ccp(220,200);
Life1 = [CCSprite spriteWithFile:#"heart.png"];
Life1.position = ccp(230,200);
[self addChild:Life1];
[self addChild:Life2];
[self addChild:Life3];
and in your actionMoveDone call block, dont remove them, just make them not visible
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
[_monsters removeObject:node];
Life--;
if(Life == 2) {
Life3.visible=NO;
}
else if(Life == 1) {
Life3.visible=NO;
Life2.visible=NO;
}
else if(Life <= 0) {
Life3.visible=NO;
Life2.visible=NO;
Life1.visible=NO;
}
}];
for starters. I just made this as 'like your coding style' as possible, but eventually you will find different patterns to do this as you game becomes more complex. Read about normal iOS code and naming conventions, it will help you and also make your code samples more palatable for the people trying to help you here.
Where are you montering the lives value ? In a tick method ?
if(Life == 2) {
[self removeChild:Life3];
}
else if(Life == 1) {
[self removeChild:Life2];
[self removeChild:Life3];
}
else if(Life <= 0) {
[self removeChild:Life1];
[self removeChild:Life2];
[self removeChild:Life3];
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[MainMenu scene]]];
}

How to randomly spawn ccsprites one at a time with a delay in between

Hello I am making a cocos2d side scroller app and I want enemies to fly at the character at random. I am a beginner to objective c and cocos2d so this may seem like a simple question but any help is valuable. Would arc4random help??
Here is my code so far. I want it so that one of these four methods: redEnemyFlight, yellowEnemyFloating, blueEnemyFlight, and spinTheRock is called randomly one at a time in an endless loop one after another.
#import "FlyingEnemy.h"
#implementation FlyingEnemy
+(id)createEnemies{
return [[[self alloc]init]autorelease];
}
-(id)init{
if((self = [super init])){
CGSize size = [[CCDirector sharedDirector]winSize];
screenWidth = size.width;
screenHeight = size.height;
screenBounds = [[UIScreen mainScreen] bounds];
redEnemyFlameCounter = 1;
xPoint = screenWidth - 50;
yPoint = screenHeight/2;
yellowEnemyFlameCounter = 1;
blueEnemyFlameCounter = 1;
xPointBlueEnemy = screenWidth - 50;
yPointBlueEnemy = screenHeight - 50;
[self spinTheRock];
}
return self;
}
-(void)spinTheRock{
spinningRock = [CCSprite spriteWithFile:#"rocks.png"];
spinningRock.position = ccp(screenWidth * 1.5, screenHeight/2);
[self addChild:spinningRock z:-1];
[spinningRock runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:2.0 angle:360]]];
moveTheRock = [CCMoveTo actionWithDuration:39.0 position:ccp(-500, spinningRock.position.y)];
[spinningRock runAction:moveTheRock];
[self schedule:#selector(removeTheSpinningRock:)interval:10.0f/1.0f];
}
-(void)removeTheSpinningRock:(ccTime)delta{
[self unschedule:#selector(removeTheSpinningRock:)];
[self stopAllActions];
[self createFlyingEnemy];
}
-(void)redEnemyFlight{
redEnemy = [CCSprite spriteWithFile:#"redenemy.png"];
redEnemy.position = ccp(xPoint, yPoint);
[self addChild:redEnemy z:-1];
[self schedule:#selector(shootTheBullets:)interval:1.0f/2.0f];
[self schedule: #selector(removeTheEnemy:)interval:18.0f/1.0f];
[self schedule: #selector(redEnemyFlame:)interval:1.0f/5.0f];
}
-(void)redEnemyFlame:(ccTime)delta{
redEnemyFlameCounter ++;
if (redEnemyFlameCounter % 2){
[redEnemy setTexture:[[CCSprite spriteWithFile:#"redenemy2.png"]texture]];
}else{
[redEnemy setTexture:[[CCSprite spriteWithFile:#"redenemy.png"]texture]];
}
}
-(void)removeTheEnemy:(ccTime)delta{
CCMoveBy* moveUp = [CCMoveBy actionWithDuration:2.0 position:ccp(100, screenHeight/2)];
[redEnemy runAction:moveUp];
[self unschedule:#selector(removeTheEnemy:)];
}
-(void)yellowEnemyFloating{
yellowEnemy = [CCSprite spriteWithFile:#"yellowenemy.png"];
yellowEnemy.position = ccp(screenWidth - 50, 50);
[self addChild:yellowEnemy z:-1];
yellowEnemyMoveDown = [CCMoveTo actionWithDuration:2.0 position:ccp(yellowEnemy.position.x, 50)];
yellowEnemyMoveUp = [CCMoveTo actionWithDuration:2.0 position:ccp(yellowEnemy.position.x, screenHeight/2)];
yellowEnemyFloatingSequnece = [CCSequence actions:yellowEnemyMoveUp, yellowEnemyMoveDown, nil];
yellowEnemyFloatingRepeat = [CCRepeat actionWithAction:yellowEnemyFloatingSequnece times:2];
[yellowEnemy runAction:yellowEnemyFloatingRepeat];
[self schedule: #selector(yellowEnemyFlame:)interval:1.0f/5.0f];
}
-(void)yellowEnemyFlame:(ccTime)delta{
yellowEnemyFlameCounter ++;
if (yellowEnemyFlameCounter % 2){
[yellowEnemy setTexture:[[CCSprite spriteWithFile:#"yellowenemy2.png"]texture]];
}else{
[yellowEnemy setTexture:[[CCSprite spriteWithFile:#"yellowenemy.png"]texture]];
}
[self schedule:#selector(yellowEnemyFlight:)interval:8.0f/1.0f];
}
-(void)yellowEnemyFlight:(ccTime)delta{
yellowEnemyMoveLeft = [CCMoveTo actionWithDuration:4.0 position:ccp(-100, bulletY)];
[yellowEnemy runAction:yellowEnemyMoveLeft];
[self schedule:#selector(removeTheYellowEnemy:)interval:4.0f/1.0f];
}
-(void)removeTheYellowEnemy:(ccTime)delta{
CCMoveTo* removeYellowEnemy = [CCMoveTo actionWithDuration:1.0 position:ccp(-100, screenHeight/2)];
[yellowEnemy runAction:removeYellowEnemy];
[self unschedule:#selector(removeTheYellowEnemy:)];
}
-(void)blueEnemyFlight{
blueEnemy = [CCSprite spriteWithFile:#"blueenemy.png"];
blueEnemy.position = ccp(xPointBlueEnemy, yPointBlueEnemy);
[self addChild:blueEnemy z:-1];
[self schedule:#selector(shootTheWaterBullets:)interval:1.0f/2.0f];
CCMoveTo* blueEnemyMoveDown = [CCMoveTo actionWithDuration:3.0 position:ccp(xPointBlueEnemy, 70)];
CCMoveTo* blueEnemyMoveUp = [CCMoveTo actionWithDuration:3.0 position:ccp(xPointBlueEnemy, yPointBlueEnemy - 10)];
CCSequence* blueEnemyFloatingSequence = [CCSequence actions:blueEnemyMoveDown, blueEnemyMoveUp, nil];
CCRepeat* blueEnemyFloatingRepeat = [CCRepeat actionWithAction:blueEnemyFloatingSequence times:3];
[blueEnemy runAction:blueEnemyFloatingRepeat];
[self schedule: #selector(removeTheBlueEnemy:)interval:18.0f/1.0f];
[self schedule: #selector(blueEnemyFlame:)interval:1.0f/5.0f];
}
-(void)blueEnemyFlame:(ccTime)delta{
blueEnemyFlameCounter ++;
if (blueEnemyFlameCounter % 2){
[blueEnemy setTexture:[[CCSprite spriteWithFile:#"blueenemy2.png"]texture]];
}else{
[blueEnemy setTexture:[[CCSprite spriteWithFile:#"blueenemy.png"]texture]];
}
}
-(void)removeTheBlueEnemy:(ccTime)delta{
CCMoveBy* moveUpBlueEnemy = [CCMoveBy actionWithDuration:0.5 position:ccp(200, 400)];
[blueEnemy runAction:moveUpBlueEnemy];
[self unschedule:#selector(removeTheBlueEnemy:)];
}
-(void) createFlyingEnemy{
// I am assuming you have an Enemy class or equivalent,
// and that it subclasses from CCNode somehow
NSUInteger randomEnemy = arc4random() % 3; // will return 0-3
return [self createEnemyOfType:randomEnemy];
}
-(void) createEnemyOfType:(NSUInteger) enemyType {
switch(enemyType) {
case 0: return [self redEnemyFlight];
case 1: return [self yellowEnemyFloating];
case 2: return [self blueEnemyFlight];
default : return [self spinTheRock];
}
}
-(void)checkForOverlap{
if (isRedEnemyOnTheScreen == YES) {
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isYellowEnemyOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isBlueEnemyOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:spinningRock cleanup:YES];
}
if (isSpinningRockOnTheScreen == YES) {
[self removeChild:redEnemy cleanup:YES];
[self removeChild:yellowEnemy cleanup:YES];
[self removeChild:blueEnemy cleanup:YES];
}
}
#end
I would add something like this to your controller:
// in your .h add a few iVars
float minDelay,maxDelay;
BOOL spawnEnabled;
// in your init setup a couple of iVars
minDelay = 0.5; // seconds
maxDelay = 2.0; // seconds
spawnEnabled = NO;
// where you are ready to spawn
spawnEnabled = YES;
[self scheduleOnce:#selector(spawnOneEnemy) delay:0.];
// add the spawning method
-(void) spawnOneEnemy {
if(!spawnEnabled) return; // prevent spawning if this was called
// after a gameOver or Win was declared
// here, compute the random x,y coords where you want to spawn
CGPoint spawnCoords = [self randomSpawnCoordinates];
// create and add an enemy at the random coordinate
Enemy * enemy = [self createEnemy];
enemy.position = spawnCoords;
[self addChild enemy]; // assumes 'self' is a CCNode subclass
// compute the next spawn time
u_int32_t delta = (u_int32_t) (ABS(maxDelay-minDelay)*1000); // ms resolution
float randomDelta = arc4random_uniform(delta)/1000.; // now in seconds
[self scheduleOnce:#selector(spawnOneEnemy) delay:randomDelta];
}
// where you win
spawnEnabled = NO;
// where you lose
spawnEnabled = NO;
// left as an exercise to the reader :
-(CGPoint) randomSpawnCoordinates {
}
-(Enemy *) createEnemy {
// I am assuming you have an Enemy class or equivalent,
// and that it subclasses from CCNode somehow
NSUInteger randomEnemy = arc4random_uniform(4); // will return 0-3
return [self createEnemyOfType:randomEnemy];
}
-(Enemy *) createEnemyOfType:(NSUInteger) enemyType {
// assumes all your enemy types subclass Enemy
switch(enemyType) {
case 0: return [self createEnemyOfType0];
case 1: return [self createEnemyOfType1];
case 2: return [self createEnemyOfType2];
case 3: return [self createEnemyOfType3];
default : return [self createEnemyOfType1];
}
}
EDIT : clarified the iVars declarations.
EDIT : put in some thoughts for random enemies

Scrabble drag technique

I had created an puzzle game which was like Scrabble.
Here is the layout:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
What is my problem?
My problem was when I start touch from 1 and direction to 12, If touch and drag in slow then no problem but when drag in fast, I manage to 1, 6, 12 or 1, 7, 12 only. There is missing a number.
How to make sure the path numbers all be selected?
I am using touch began, touch moved and touch ended and check with coordinate to locate which number is being touched.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentTouchLocation = [touch locationInView:self.numberview];
if(!ispause && [time.text intValue] > 0){
if(!isbegan && !isended){
for(int i = 1; i <= 16; i++)
{
UIView *imageview = [self.numberview viewWithTag:i];
if (CGRectContainsPoint(imageview.frame, currentTouchLocation))
{
isbegan = YES;
isreverse = NO;
if([[ischose objectAtIndex:i-1] boolValue] == 0)
{
currentposition = imageview.tag;
positionvalue += pow(i, 3);
currentanswer += [self converter:[NSString stringWithFormat:#"%#", [allimagenumbers substringWithRange:NSMakeRange(i-1, 1)]]];
[ischose replaceObjectAtIndex:i-1 withObject:[NSNumber numberWithBool:YES]];
[self changeimage:#"selected"];
}
break;
}
}
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentTouchLocation = [touch locationInView:self.numberview];
float gapX = image1.frame.size.width / 8;
float gapY = image1.frame.size.height / 8;
if(isbegan && !isended)
{
if(currentTouchLocation.x >= 0 && currentTouchLocation.x <= self.numberview.frame.size.width && currentTouchLocation.y >= 0 && currentTouchLocation.y <= self.numberview.frame.size.height)
{
for(int i = 1; i <= 16; i++)
{
UIView *imageview = [self.numberview viewWithTag:i];
if (CGRectContainsPoint(imageview.frame, currentTouchLocation))
{
if((currentTouchLocation.x >= imageview.frame.origin.x + gapX && currentTouchLocation.x < imageview.frame.origin.x + imageview.frame.size.width - gapX) && (currentTouchLocation.y >= imageview.frame.origin.y + gapY && currentTouchLocation.y < imageview.frame.origin.y + imageview.frame.size.height - gapY ))
{
if([[ischose objectAtIndex:i-1] boolValue] == 0 && !isreverse)
{
currentposition = imageview.tag;
positionvalue += pow(i, 3);
currentanswer += [self converter:[NSString stringWithFormat:#"%#", [allimagenumbers substringWithRange:NSMakeRange(i-1, 1)]]];
[ischose replaceObjectAtIndex:i-1 withObject:[NSNumber numberWithBool:YES]];
[self changeimage:#"selected"];
}
else
{
if(currentposition != imageview.tag)
{
isreverse = YES;
}
else
{
isreverse = NO;
}
}
break;
}
}
}
}
else
{
isended = YES;
isoutofbound = YES;
if(isbegan && isoutofbound)
[self countinganswer];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
if(!isoutofbound)
{
isended = YES;
[self countinganswer];
}
else
isoutofbound = NO;
}
-(void)changeimage:(NSString *)status{
if([status isEqualToString:#"default"])
{
for(int i = 1; i <=16;i++)
{
UIImageView *imageview = (UIImageView*)[self.numberview viewWithTag:i];
imageview.image = [UIImage imageNamed:[NSString stringWithFormat:#"stone%#", [allimagenumbers substringWithRange:NSMakeRange(i-1, 1)]]];
[image1 setUserInteractionEnabled:YES];
}
}
else if([status isEqualToString:#"correct"] || [status isEqualToString:#"selected"])
{
for(int i = 1; i<= ischose.count; i++)
{
if([[ischose objectAtIndex:i-1] boolValue] == 1)
{
UIImageView *imageview = (UIImageView*)[self.numberview viewWithTag:i];
imageview.image = [UIImage imageNamed:[NSString stringWithFormat:#"stone%#_correct", [allimagenumbers substringWithRange:NSMakeRange(i-1, 1)]]];
}
}
}
else if([status isEqualToString:#"wrong"] || [status isEqualToString:#"repeat"])
{
for(int i = 1; i<= ischose.count; i++)
{
if([[ischose objectAtIndex:i-1] boolValue] == 1)
{
UIImageView *imageview = (UIImageView*)[self.numberview viewWithTag:i];
imageview.image = [UIImage imageNamed:[NSString stringWithFormat:#"stone%#_wrong_repeat", [allimagenumbers substringWithRange:NSMakeRange(i-1, 1)]]];
}
}
}
}
Update:
Chatting with you, it appears that you have solved your problem (where a swipe over one of your UIImageView objects was not being detected). It looks like the solution was a unique issue (i.e. highly "localized" in Stack Overflow language) associated with your code to create reduced size "hit zones" that you constructed with your gap variables. It doesn't look like the solution was anything really associated with touchesMoved, iOS API, or iOS system performance. Regardless, I'm glad you solved the problem.
My original answer below was predicated on the original source code posted, which had the same logic repeated for each of the 16 UIImageView objects. I was just demonstrating how you can use a UIArray to significantly simplify that logic. I also use UIPanGestureRecognizer, which I think unifies the code, and with <UIKit/UIGestureRecognizerSubclass.h> you can cancel the gesture, in case the user's gesture went "out of bounds."
Original answer:
I'm assuming that you simply want to build an array of image numbers as the user drags their finger over the numbers. So the ARC code might look something like:
// NumberGameViewController.m
#import "NumberGameViewController.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface NumberGameViewController ()
{
NSArray *images;
NSMutableArray *results;
}
#end
#implementation NumberGameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// if you build an array of your images, the logic to determine which image you're over is much easier
images = #[self.image1, self.image2, self.image3, self.image4, self.image5, self.image6, self.image7, self.image8, self.image9, self.image10, self.image11, self.image12, self.image13, self.image14, self.image15, self.image16];
// I know you used `touchesMoved` and the like, but I think gesture recognizers are a little easier
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[self.numberview addGestureRecognizer:pan];
}
- (NSInteger)determineImageNumber:(CGPoint)point
{
for (NSInteger i = 0; i < [images count]; i++)
{
UIImageView *imageview = images[i];
// I'm just going to see if the user's finger was over the number in question.
// If you wanted more restrictive logic (e.g. 3/4ths of the frame), just adjust
// adjust the frame variable here.
CGRect frame = imageview.frame;
if (CGRectContainsPoint(frame, point))
return i;
}
return -1;
}
- (void)handlePan:(UIGestureRecognizer *)gesture
{
CGPoint location = [gesture locationInView:self.numberview];
NSInteger imageNumber = [self determineImageNumber:location];
static NSInteger lastImageNumber;
if (gesture.state == UIGestureRecognizerStateBegan)
{
results = [[NSMutableArray alloc] init];
if (imageNumber >= 0)
{
[results addObject:#(imageNumber)];
}
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
if (imageNumber >= 0)
{
if (imageNumber != lastImageNumber)
{
// If you want to do some visual adjustment of the image you're over, do it
// here.
// add the image to our array of results
[results addObject:#(imageNumber)];
// if you want to do some additional validation (e.g. do you have 16 points,
// has the user hit the same number twice, etc.), do that here
}
}
// by the way, let's check to see if we're still within the numberview subview, and if
// not, let's cancel the gesture
if (!CGRectContainsPoint(self.numberview.bounds, location))
{
gesture.state = UIGestureRecognizerStateCancelled;
return;
}
}
else if ((gesture.state == UIGestureRecognizerStateEnded) || (gesture.state == UIGestureRecognizerStateCancelled) || (gesture.state == UIGestureRecognizerStateFailed))
{
// At this point you'd do any final validation of the user's response, to see if they
// succeeded or not. I'm just displaying the results in the console
NSLog(#"%#", results);
}
if (imageNumber >= 0)
lastImageNumber = imageNumber;
}
#end
float gapX = image1.frame.size.width / 8;
float gapY = image1.frame.size.height / 8;
Here is the problem, there is a gap within all images so when fast drag it will be outer part of images