Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm using a tutorial to create a game where if the rocketship is hit by an asteroid, the ship will show an image using SKEmitterNode and will blink then play a sound. This part of the game is working, however the game will not end. How do I fix this error?
Here's my code where I believe the error is
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
// SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blink];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}
}
}
The game is not ending because you are not calling the end-game transition in case of the collsion between the spaceship and asteroid as you do in the case where the collision is between the projectile and the asteroid.
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship]; //What does this do?
[self runAction:[SKAction sequence:#[[SKAction waitForDuration:3.0], [SKAction runBlock:^{
[self gameEndedWithSuccess:NO];
}]]]];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
[self gameEndedWithSuccess:YES];
}
}
}
-(void) gameEndedWithSuccess:(BOOL)success
{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:success];
[self.view presentScene:gameOverScene transition: reveal];
}
Related
I want to rotate my character by tilting the phone left and right, but it only rotate once when DidMoveToView is called. What do I need to change in my code?
self.manager = [[CMMotionManager alloc] init];
if ([self.manager isAccelerometerAvailable] == YES) {
[self.manager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init]
withHandler:^(CMAccelerometerData *data, NSError *error)
{
float destX = 0.0, destY = 0.0;
float currentX = _character.position.x;
float currentY = _character.position.y;
BOOL shouldMoveToRight = NO;
BOOL shouldMoveToLeft = NO;
if(data.acceleration.y < -0.25) { // tilting the device to the right
destX = currentX + (data.acceleration.x * kPlayerSpeed);
destY = currentY;
shouldMoveToRight = YES;
shouldMoveToLeft = NO;
} else if (data.acceleration.y > 0.25) { // tilting the device to the left
destX = currentX + (data.acceleration.x * kPlayerSpeed);
destY = currentY;
shouldMoveToRight = NO;
shouldMoveToLeft = YES;
}
if(shouldMoveToRight) {
SKAction *moveAction = [SKAction moveTo:CGPointMake(destX, destY) duration:1];
[_character runAction:moveAction];
SKAction *rotateAction = [SKAction rotateToAngle:M_PI duration:1];
[_character runAction:rotateAction];
}
if (shouldMoveToLeft) {
SKAction *moveAction = [SKAction moveTo:CGPointMake(destX, destY) duration:1];
[_character runAction:moveAction];
SKAction *rotateAction = [SKAction rotateToAngle:-M_PI duration:1];
[_character runAction:rotateAction];
}
}];
}
I have two SKSpriteNode first Hero
+(id)hero
{
NSMutableArray *walkFrames = [NSMutableArray array];
SKTextureAtlas *heroAnimatedAtlas = [SKTextureAtlas atlasNamed:#"HeroImages"];
int numImages = (int)heroAnimatedAtlas.textureNames.count;
for (int i=1; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"hero%d", i];
SKTexture *temp = [heroAnimatedAtlas textureNamed:textureName];
[walkFrames addObject:temp];
}
Hero *hero = [Hero spriteNodeWithTexture:walkFrames[0]];
hero.heroWalkingFrames = walkFrames;
hero.name =#"Hero";
hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hero.size];
hero.physicsBody.categoryBitMask = heroCategory;
hero.physicsBody.categoryBitMask = obstacleCategory | groundCategory | homeCategory | ~goodiesCategory;
return hero;
}
and second is Coin
SKSpriteNode *coin = [SKSpriteNode spriteNodeWithImageNamed:#"coin"];
coin.size = CGSizeMake(10,10);
coin.position = CGPointMake(100,100);
coin.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:coin.size];
coin.physicsBody.contactTestBitMask = coinCategory;
coin.physicsBody.dynamic=NO;
coin.name = #"coin";
[self.world addChild:coin];
And I am able to get collision detection by
if([contact.bodyA.node.name isEqual: #"coin"] || [contact.bodyB.node.name isEqual: #"coin"])
{
//[self LevelComplete];
SKNode* coinNode ;
if ([contact.bodyA.node.name isEqual: #"coin"]) {
coinNode=contact.bodyA.node;
}
else{
coinNode=contact.bodyB.node;
}
[coinNode removeFromParent];
NSLog(#"Coin touched");
}
Now my problem is every time hero jump and touch the coin it will go down to ground instead to continue jump and reach the height that it should, I know I am missing something here but don't know what it is, So anyone can please show me the right direction to correct this effect .
Create an extra "nilCategory" and set the collisionBitMask of your coin..
coin.physicsBody.collisionBitMask = nilCategory;
Hi I've been making a game with the SpriteKit framework and I set a collision bit mask when 2 objects collide. One of those objects, let's say the object A, can have 2 states: black or normal so when the two objects collide and the A object is on normal state it adds a point but when the two objects collide and the A object is on black state the game is over. This code is working fine for me on iOS 7 but when I run it on iOS 8 and if the A object state is black it acts like if it's on normal state and adds a point. Why this is happening? Is different the code for iOS 7 and 8? Please can anyone help me, here's the code:
-(void)didBeginContact:(SKPhysicsContact *)contact {
SKPhysicsBody *firstBody;
SKPhysicsBody *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (firstBody.categoryBitMask == objectACategory && secondBody.categoryBitMask == objectBCategory) {
NSLog(#"OBJECT A CAUGHT");
[firstBody.node removeFromParent];
[GameState sharedInstance].score++;
_scoreLabel.text = [NSString stringWithFormat:#"%d", [GameState sharedInstance].score];
_scoreLabel_2.text = [NSString stringWithFormat:#"%d", [GameState sharedInstance].score];
gameUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"sound " ofType:#"wav"]];
_gameSound = [[AVAudioPlayer alloc] initWithContentsOfURL:gameUrl error:nil];
_gameSound.delegate = self;
[_gameSound play];
if ([[firstBody.node.userData valueForKey:#"Black"] boolValue]) {
[self removeActionForKey:origamiFallKey];
NSLog(#"YOU LOSE");
[self gameOver];
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:0.5],
[SKAction performSelector:#selector(removeWhenLose) onTarget:self]]]];
}
}
For setting the state I used this code in the method which adds a objectA:
// Black
if(arc4random_uniform(6) == 0) {
_objectA.texture = [SKTexture textureWithImageNamed:#"blackImage.png"];
_objectA.physicsBody.collisionBitMask = objectACategory;
_objectA.userData = [[NSMutableDictionary alloc] init];
[_objectA.userData setValue:#YES forKey:#"Black"];
blackObjectA = YES;
}
I finally solved this problem. First I had to create the collision variable:
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
And with write the collisions using this:
-(void)didBeginContact:(SKPhysicsContact *)contact {
if (collision == (objectACategory | objectBCategory)) {
if ([[firstBody.node.userData valueForKey:#"Black"] boolValue]){
[self removeActionForKey:fallKey];
NSLog(#"YOU LOSE");
[self gameOver];
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:0.5],
[SKAction performSelector:#selector(removeWhenLose) onTarget:self]]]];
} else {
[firstBody.node removeFromParent];
[GameState sharedInstance].score++;
_scoreLabel.text = [NSString stringWithFormat:#"%d", [GameState sharedInstance].score];
_scoreLabel_2.text = [NSString stringWithFormat:#"%d", [GameState sharedInstance].score];
gameUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"origami " ofType:#"wav"]];
_gameSound = [[AVAudioPlayer alloc] initWithContentsOfURL:gameUrl error:nil];
_gameSound.delegate = self;
[_gameSound play];
}
}
I am trying to add a few seconds to countdown timer each time when enemy and player node contacts.
Also when the player reach to some certain point I want player to pass to another level. I am sending part of the code . Could anybody help me to solve this problem. By the way because I am new to programming my code is a little hard to read . Sorry for that.
Thanks
-(void)update:(CFTimeInterval)currentTime{
if (startGamePlay){
startTime = currentTime;
startGamePlay = NO;
}
countDownInt = 10.0 - (int)(currentTime-startTime);
if(countDownInt > 0 ){ //if counting down to 0 show counter
countDown.text = [NSString stringWithFormat:#"%i", countDownInt];
}
else 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];
}
}
- (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");
countDownInt = [countDown.text intValue];
[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]);
}
#import "HudNode.h"
#implementation HudNode
{
SKLabelNode *countDown;
BOOL startGamePlay;
NSTimeInterval startTime;
}
+ (instancetype) hudAtPosition:(CGPoint)position inFrame:(CGRect)frame {
HudNode *hud = [self node];
hud.position = position;
hud.zPosition = 10;
hud.name = #"HUD";
SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Futura-CondensedExtraBold"];
scoreLabel.name = #"Score";
scoreLabel.text = #"0";
scoreLabel.fontSize = 24;
scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
scoreLabel.position = CGPointMake(frame.size.width-20, -10);
scoreLabel.zPosition = 12;
[hud addChild:scoreLabel];
SKLabelNode *countDown = [SKLabelNode labelNodeWithFontNamed:#"Futura-Medium"];
countDown.fontSize = 50;
countDown.position = CGPointMake(30, -10);
countDown.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter; //good for positioning with other sprites
countDown.fontColor = [SKColor whiteColor ];
countDown.name = #"countDown";
countDown.zPosition = 100;
[hud addChild:countDown];
return hud;
}
- (void) addPoints:(NSInteger)points {
self.score += points;
SKLabelNode *scoreLabel = (SKLabelNode *) [self childNodeWithName:#"Score"];
scoreLabel.text = [NSString stringWithFormat:#"Score:%li", (long)self.score];
}
Create a boolean flag that the update method checks to see if it should add seconds.
Add the following variable and set self.addSeconds = NO; initially:
#property (nonatomic) BOOL addSeconds;
Set self.addSeconds =YES; in the method where your player hits your enemy:
Add the following to the very beginning of the Update:
if(self.addSeconds == YES)
{
CountDownInt+= 5 //Change this to add as many seconds as you want
self.addSeconds=NO;
}
This should do the trick.
I tried so much methods but i didn't stop the cats when begin contacts.Here is node moving method:
[self enumerateChildNodesWithName:#"cat" usingBlock:^(SKNode *node, BOOL *stop){
SKSpriteNode *tempCat = (SKSpriteNode *) node;
float actionDuration = 0.1;
CGPoint offset = CGPointSubtract(_zombie.position, tempCat.position);
CGPoint direction = CGPointNormalize(offset);
CGPoint amountToMovePerSec = CGPointMultiplyScalar(direction, CAT_MOVE_POINTS_PER_SEC);
CGPoint amountToMove = CGPointMultiplyScalar(amountToMovePerSec, actionDuration);
node.position = CGPointMake(node.position.x+amountToMove.x, node.position.y+amountToMove.y);
_velocityCat = CGPointMultiplyScalar(direction, CAT_MOVE_POINTS_PER_SEC);
[self rotateNode:tempCat toFace:_velocityCat rotateRadiansPerSec:CAT_ROTATE_RADIANS_PER_SEC];
How can I stop cat when begin contact?
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (enemyCategory | catsCategory)) {
[self enumerateChildNodesWithName:#"cat" usingBlock:^(SKNode *node, BOOL *stop) {
if ([contact.bodyA.node isEqual:node] || [contact.bodyB.node isEqual:node])
{
node.physicsBody = NO;
SKAction *wait = [SKAction waitForDuration:2];
SKAction *catDie = [SKAction runBlock:^{
[node removeFromParent];
}];
SKAction *animation = [SKAction sequence:#[wait, catDie]];
[self runAction:animation];
}
}]; NSLog(#"test 1");
}
Enumerating over all cat nodes is not necessary since you can get the node involved in the contact from the SKPhysicsContact object. The following shows how to do that...
EDIT: you can change the cat node's name to prevent it from chasing the zombie
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (enemyCategory | catsCategory)) {
SKNode *node = contact.bodyA.node;
if (contact.bodyB.categoryBitMask == catsCategory) {
node = contact.bodyB.node;
}
// One way to stop the cat from chasing zombie is by changing its name
node.name = #"not cat";
}
}