How to add a loop in a game - ios

I'm trying to write a basic cause and effect game. So far I've managed to display an image of a rocket on the screen (appers randomly on the x axles) and when touched launches. The program works fine but I want the rocket to reappear (loop 10 times), can anyone give me some guidance on how I can achieve this.
I have attached the code from my scene.m below...
#import "MyScene.h"
#implementation MyScene
#import AVFoundation;
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor whiteColor];
SKSpriteNode *rocket1 = [SKSpriteNode spriteNodeWithImageNamed:#"rocket.png"];
CGRect rocket1frame = CGRectMake(100, 100, 100, 100);
[rocket1 setSize:rocket1frame.size];
rocket1.position = CGPointMake(CGRectGetMidX(self.frame), 100);
[self addChild:rocket1];
_ship = rocket1;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentLocation = [[touches anyObject] locationInNode:self];
CGPoint previousLocation = [[touches anyObject] previousLocationInNode:self];
CGRect shipRect = _ship.frame;
if (CGRectContainsPoint(shipRect, previousLocation))
{
CGPoint lvPosition = CGPointMake(_ship.position.x - (previousLocation.x - currentLocation.x), _ship.position.y);
_ship.position = lvPosition;
SKAction *sound = [SKAction playSoundFileNamed:#"slideup.mp3" waitForCompletion:NO];
SKAction *moveNode = [SKAction moveByX:lvPosition.x y:3000.0 duration:3.0];
[_ship runAction: sound];
[_ship runAction: moveNode];
}
}
#end;

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentLocation = [[touches anyObject] locationInNode:self];
CGPoint previousLocation = [[touches anyObject] previousLocationInNode:self];
CGRect shipRect = _ship.frame;
if (CGRectContainsPoint(shipRect, previousLocation))
{
[self launch:10 p1:currentLocation p2:previousLocation rect1:shipRect];
}
}
-(void)launch:(int)count p1:(CGPoint) currentLocation p2:(CGPoint) previousLocation rect1:(CGRect) shipRect
{
CGPoint lvPosition = CGPointMake(_ship.position.x - (previousLocation.x - currentLocation.x), _ship.position.y);
_ship.position = lvPosition;
SKAction *sound = [SKAction playSoundFileNamed:#"slideup.mp3" waitForCompletion:NO];
SKAction *moveNode = [SKAction moveByX:lvPosition.x y:3000.0 duration:3.0];
[_ship runAction: sound];
[_ship runAction: moveNode completion:^{
if (count)
[self launch:count-- p1:currentLocation p2:previousLocation rect1:shipRect];
}];
}

Related

Two touches in touchesBegan in objective c

I have two touches in method "touchesBegan" they both starts at the same time, but i want to second touch to wait while first touch end. How can i achieve that? Here are what I have:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location =[touch locationInView:self.view];
SKNode *touchedNode = [self nodeAtPoint:location];
if(touchedNode && [touchedNode.name isEqual:#"tapButton"]){
[self runAction:[SKAction playSoundFileNamed:#"buttons.wav" waitForCompletion:NO]];
[self createBackLn];
[self createBottom];
[self ballCreate];
[tapButton removeFromParent];
}
if (groupSprite.children.count < 3) {
CGPoint touchlocation = [touch locationInNode:self];
CGPoint location = CGPointMake(touchlocation.x, IS_IPAD()?108: 75);
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"board"];
if(IS_IPAD()){
sprite.xScale = 0.5;
sprite.yScale = 0.7;
}else{
sprite.xScale = 0.3;
sprite.yScale = 0.5;
}
sprite.position = location;
sprite.zPosition = 2;
sprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:sprite.frame.size];
sprite.physicsBody.dynamic = NO;
sprite.physicsBody.categoryBitMask = boardCategory;
sprite.physicsBody.contactTestBitMask = ballCategory | secballCategory;
SKAction *delay = [SKAction waitForDuration:IS_IPAD()?0.6:0.4];
SKAction *remove = [SKAction removeFromParent];
SKAction *actionSequence = [SKAction sequence:#[delay,remove]];
[sprite runAction:actionSequence];
[groupSprite addChild:sprite];
}
}
}

SpriteKit allow only one touch

Everytime a touch is made, a node is added and will move to another node. I want to avoid that you can touch the node many times, and the node will been added as many times as you click. It should be only added once, and after the SKAction is done, you can touch the node again.
In my Code below, I tried it with userInteractionEnabled. But after the 'Zauberer' is added the third time, it recognizes no touches anymore.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
self.userInteractionEnabled = NO;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"Zauberer"]){
Wurfstein = [SKSpriteNode spriteNodeWithImageNamed:#"Wurfstein.png"];
Wurfstein.position = CGPointMake(Mensch.position.x, Mensch.position.y);
Wurfstein.zPosition = 1;
Wurfstein.scale = 0.6;
Wurfstein.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:5];
Wurfstein.physicsBody.dynamic = NO;
Wurfstein.physicsBody.allowsRotation = NO;
Wurfstein.physicsBody.usesPreciseCollisionDetection = YES;
Wurfstein.physicsBody.restitution = 0;
Wurfstein.physicsBody.categoryBitMask = SteinCategory ;
Wurfstein.physicsBody.collisionBitMask = ZaubererCategory;
Wurfstein.physicsBody.contactTestBitMask = ZaubererCategory;
SKAction *action = [SKAction moveTo:Zauberer.position duration:0.5];
SKAction *remove = [SKAction removeFromParent];
[self addChild:Wurfstein];
[Wurfstein runAction:[SKAction sequence:#[action,remove]]completion:^{
self.userInteractionEnabled = YES;
[Zauberer removeFromParent];
[self performSelector:#selector(Zauberer) withObject:nil afterDelay:5.0 ];
}];
}
}
Ok, I got it. If you first touch anywhere else on the screen, and than on the 'Zauberer' node, it wouldn't react. You need to put the self.userInteractionEnabled = NO; in the if sentence, to avoid the problem.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"Zauberer"]){
self.userInteractionEnabled = NO;
Wurfstein = [SKSpriteNode spriteNodeWithImageNamed:#"Wurfstein.png"];
Wurfstein.position = CGPointMake(Mensch.position.x, Mensch.position.y);
Wurfstein.zPosition = 1;
Wurfstein.scale = 0.6;
Wurfstein.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:5];
Wurfstein.physicsBody.dynamic = NO;
Wurfstein.physicsBody.allowsRotation = NO;
Wurfstein.physicsBody.usesPreciseCollisionDetection = YES;
Wurfstein.physicsBody.restitution = 0;
Wurfstein.physicsBody.categoryBitMask = SteinCategory ;
Wurfstein.physicsBody.collisionBitMask = ZaubererCategory;
Wurfstein.physicsBody.contactTestBitMask = ZaubererCategory;
SKAction *action = [SKAction moveTo:Zauberer.position duration:0.5];
SKAction *remove = [SKAction removeFromParent];
[self addChild:Wurfstein];
[Wurfstein runAction:[SKAction sequence:#[action,remove]] completion:^{
self.userInteractionEnabled = YES;
[Zauberer removeFromParent];
[self performSelector:#selector(Zauberer) withObject:nil afterDelay:4.0 ];
}];
}
}

SpriteKit Clicker Game Select Spawn Area for Clickable things?

I'm New to SpriteKit and build a simple CLickerGame in SpriteKit. Now i have the game finish but the thing which should spawn to click on it, spawns from time to time outside the screen. Where can i select the arc4random area where the thing should spawn?
#implementation MyScene
-(void)CreateTestObject
{
SKSpriteNode *TestObject = [SKSpriteNode spriteNodeWithImageNamed:#"TestObject"];
int maxX = CGRectGetMaxX(self.frame);
float ranX = (arc4random()%maxX) + 1;
int maxY = CGRectGetMaxY(self.frame);
float ranY = (arc4random()%maxY) + 1;
TestObject.position = CGPointMake(ranX, ranY);
TestObject = CGSizeMake(75, 75);
TestObject = #"Object";
[self addChild:TestObject];
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
bg = [SKSpriteNode spriteNodeWithImageNamed:#"bg.png"];
bg.position = CGPointMake(160, 284);
bg.size = CGSizeMake(self.frame.size.width, self.frame.size.height);
[self addChild:bg];
[self CreateTestObject];
}
return self;
}
-(void)selectNodeForTouch:(CGPoint)touchLocation
{
SKSpriteNode *touchedNode = (SKSpriteNode *)[self nodeAtPoint:touchLocation];
if([[touchedNode name] isEqualToString:#"TestObject"])
{
SKSpriteNode *TestObject = (SKSpriteNode *)[self childNodeWithName:#"TestObject"];
TestObject.name = #"DisabledTestObject";
SKAction *grow = [SKAction scaleTo:1.2 duration:0.1];
SKAction*shrink = [SKAction scaleTo:0 duration:0.07];
SKAction *removeNode = [SKAction removeFromParent];
SKAction *seq = [SKAction sequence:#[grow, shrink, removeNode]];
[TestObject runAction:seq];
[self CreateTestObject];
[self runAction:[SKAction playSoundFileNamed:#"Sound.aif" waitForCompletion:NO]];
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
//CGPoint location = [touch locationInNode:self];
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];
}
}
#end
Modify the max values for your (x,y) coordinates of any object being added to your view.
For example, on an iPhone 5 display in landscape mode and the spawned object being of size width=100, height=100, the max x value should be no more than 518. Width of screen being 568 less half the width of your object (50).
The same logic applies for the y value. The max y value should be 270 given the same object dimensions.
The above assumes that you have not changed your object's anchor point from (0.5,0.5) to another value.

After rotating SKLabelNode it becomes difficult to get location in touchesBegan:

I have an SKLabel Node setup as a button in my app and it works fine. However, when I rotate the SKLabelNode with this code my touchesBegan method no longer executes correctly and it becomes very difficult to have the SKLabelNode touches register correctly:
[_menuButton runAction:[SKAction sequence:#[[SKAction rotateByAngle:M_PI duration:.2],
[SKAction moveByX:0 y:-15 duration:.2]]]];
Here is my touches began method:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];
if ([node.name isEqualToString:menuButtonName]) {
//Touched Menu Button
[self animateMenuAndShow:YES];
}
}
EDIT: One additional piece of information is that I'm using SKTEffects which requires that instead of using self.scene as my base I'm using _worldLayer to add all elements in the scene to. Is it possible that this is throwing off my touch calculations? And if so how can I correct this?
self.scaleMode = SKSceneScaleModeResizeFill;
self.anchorPoint = CGPointMake(0.5, 0.5);
// The origin of the pivot node must be the center of the screen.
_worldPivot = [SKNode node];
[self addChild:_worldPivot];
// Create the world layer. This is the only node that is added directly
// to the pivot node. If you have a HUD layer you would add that directly
// to the scene and make it sit above the world layer.
_worldLayer = [SKNode node];
_worldLayer.position = self.frame.origin;
[_worldPivot addChild:_worldLayer];
Also after following sangony's advice here is my updated touchesBegan: method which works well at first, but runs into the same problem after rotating the label by M_PI
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:_worldLayer];
CGPoint locationInMenu = [touch locationInNode:_menuBackground];
if (CGRectContainsPoint(_menuButton.frame, location)) {
//Touched Menu Button
if (!self.menuVisible) {
[self animateMenuAndShow:YES];
}
else
{
[self animateMenuAndShow:NO];
}
}
}
EDIT2:
Here is my animateMenuAndShow: method
-(void)animateMenuAndShow:(BOOL)show
{
if (show == YES) {
// self.paused = YES;
self.menuVisible = !self.menuVisible;
[self createMenu];
SKAction *showMenuAction = [SKAction sequence:#[
[SKAction moveTo:CGPointMake(self.size.width / 2, self.size.height/2) duration:0.3],
[SKAction runBlock:^{
[self jelly:self.menuBackground];
}],
[SKAction waitForDuration:1.5]
]];
[self.menuBackground runAction: showMenuAction completion:^{
self.paused = YES;
}];
if (_flipped == YES) {
[self.menuBackground runAction:[SKAction sequence:#[
[SKAction moveByX:0 y:0 duration:.2],[SKAction rotateByAngle:M_PI duration:.2]]]];// [SKAction rotateByAngle:M_PI duration:.2]
}
}
else
{
self.paused = NO;
SKAction *removeMenuAction = [SKAction sequence:#[
[SKAction moveTo:CGPointMake(self.size.width / 2, -self.size.height + 300) duration:0.3],
]];
[self.menuBackground runAction:removeMenuAction completion:^{
[self.menuBackground removeFromParent];
}];
self.menuVisible = !self.menuVisible;
}
}
Try this touchesBegan instead:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if (CGRectContainsPoint(myLabel.frame, touchLocation))
{
[self animateMenuAndShow:YES];
}
}

Move a SKSpriteNode with a single tap, but move continously when long tap - Sprite Kit

I'm trying to change some SKActions of an existing Sprite Kit tutorial project, but I'm running into issues when it comes to movement. The Tutorial and GitHub project is here:
https://www.codefellows.org/blogs/simple-sprite-kit-game-tutorial-part1
https://github.com/megharastogi/GameTutorial
As you can see in the code below, each tap only moves the node once. How do I change it so that a long tap will move continuous move the node? I tried a few things like repeatActionForever, but that didn't work very well.
-(void)addShip
{
//initalizing spaceship node
ship = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
[ship setScale:0.5];
ship.zRotation = - M_PI / 2;
//Adding SpriteKit physicsBody for collision detection
ship.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ship.size];
ship.physicsBody.categoryBitMask = shipCategory;
ship.physicsBody.dynamic = YES;
ship.physicsBody.contactTestBitMask = obstacleCategory;
ship.physicsBody.collisionBitMask = 0;
ship.physicsBody.usesPreciseCollisionDetection = YES;
ship.name = #"ship";
ship.position = CGPointMake(120,160);
actionMoveUp = [SKAction moveByX:0 y:30 duration:.2];
actionMoveDown = [SKAction moveByX:0 y:-30 duration:.2];
[self addChild:ship];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y >ship.position.y){
if(ship.position.y < 270){
[ship runAction:actionMoveUp];
}
}else{
if(ship.position.y > 50){
[ship runAction:actionMoveDown];
}
}
}
- (void)didMoveToView:(SKView *)view
{
UILongPressGestureRecognizer *tapper = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tappedScreen:)];
tapper.minimumPressDuration = 0.1;
[view addGestureRecognizer:tapper];
}
- (void)tappedScreen:(UITapGestureRecognizer *)recognizer
{
float touchY = [self convertPointFromView:[recognizer locationInView:self.view]].y;
SKSpriteNode *ship = [self childNodeWithName:#"ship"];
if (recognizer.state == UIGestureRecognizerStateBegan) {
if(touchY >ship.position.y){
[ship runAction:[SKAction repeatActionForever:actionMoveUp] withKey:#"longTap"];
}else{
[ship runAction:[SKAction repeatActionForever:actionMoveDown] withKey:#"longTap"];
}
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
[ship removeActionForKey:#"longTap"];
}
}
Add these two methods in your code.

Resources