how can I create a menu screen for my spritekit game? - objective-c

I already put my actual Gamescene inside the MyScene class. How can I create a menu screen even If I already put the game in the MyScene class. I tried to include the menu before the actual gamescene but that didnt work
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
if (self = [super initWithSize:size]){
SKSpriteNode *startButton = [SKSpriteNode spriteNodeWithImageNamed:#"startButton"];
startButton.position = CGPointMake(160, 300);
startButton.size = CGSizeMake(200, 200);
startButton.name = #"startButton";
[self addChild:startButton];
}
return self;
/* Setup your scene here */
self.anchorPoint = CGPointMake(0.5, 0.5);
self.physicsWorld.contactDelegate = self;
//SKSpriteNode *bgImage = [SKSpriteNode spriteNodeWithImageNamed:#""];
//[self addChild:bgImage];
self.backgroundColor = [SKColor colorWithRed:0.171875 green:0.2421875 blue:0.3125 alpha:1.0];
world = [SKNode node];
[self addChild:world];
self.physicsWorld.contactDelegate = self;
generator = [SPWorldGenerator generatorWithWorld:world];
[self addChild:generator];
[generator populate];
hero = [SPHero hero];
[world addChild:hero];
[self loadScoreLabels];
cloud1 = [SPHero cloud1];
[world addChild:cloud1];
cloud2 = [SPHero cloud2];
[world addChild:cloud2];
cloud3 = [SPHero cloud3];
[world addChild:cloud3];
cloud4 = [SPHero cloud4];
[world addChild:cloud4];
//uihui//
SKLabelNode *tapToBeginLabel = [SKLabelNode labelNodeWithFontNamed:GAME_FONT];
tapToBeginLabel.name = #"tapToBeginLabel";
tapToBeginLabel.text = #"tap to begin";
tapToBeginLabel.fontSize = 20.0;
[self addChild:tapToBeginLabel];
[self animateWithPulse:tapToBeginLabel]; // ** GETS RESET LABEL PULSING ** //
// ** PULSING TEXT ** //
SKAction *disappear = [SKAction fadeAlphaTo:0.0 duration:0.6];
SKAction *appear = [SKAction fadeAlphaTo:1.0 duration:0.6];
SKAction *pulse = [SKAction sequence:#[disappear, appear]];
[tapToBeginLabel runAction:[SKAction repeatActionForever:pulse]];
// ** PULSING TEXT ** //
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"startButton"]) {
SKTransition *transition = [SKTransition doorsOpenVerticalWithDuration:1.0];
MyScene *game = [[MyScene alloc] initWithSize: CGSizeMake(self.size.width, self.size.height)];
[self.scene.view presentScene:game transition:transition];
}
}

Related

How to achieve this animation with Spritekit?

Question:
How to achieve this animation with Spritekit?
What I've done:
Problem:
1) I can draw all four petals,but once I lift my finger to draw the circle, it will still create a line from the previous point where I lift my finger to the new touches begin point. refer to gif below:
2) How to remove the solid orange line from the view incrementally (mine is too abrupt)?
3) Need to tune the .sks file properties.
4) https://stackoverflow.com/questions/29792443/set-the-initial-state-of-skemitternode
This is my code:
#import "GameScene.h"
#interface GameScene()
#property (nonatomic) SKEmitterNode* fireEmmitter;
#property (nonatomic) SKEmitterNode* fireEmmitter2;
#end
#implementation GameScene
NSMutableArray *_wayPoints;
NSTimer* myTimer;
-(void)didMoveToView:(SKView *)view {
_wayPoints = [NSMutableArray array];
//Setup a background
self.backgroundColor = [UIColor blackColor];
//setup a fire emitter
NSString *fireEmmitterPath = [[NSBundle mainBundle] pathForResource:#"magic" ofType:#"sks"];
_fireEmmitter = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath];
_fireEmmitter.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2 - 200);
_fireEmmitter.name = #"fireEmmitter";
_fireEmmitter.zPosition = 1;
_fireEmmitter.targetNode = self;
_fireEmmitter.particleBirthRate = 0;
[self addChild: _fireEmmitter];
//setup another fire emitter
NSString *fireEmmitterPath2 = [[NSBundle mainBundle] pathForResource:#"fireflies" ofType:#"sks"];
_fireEmmitter2 = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath2];
_fireEmmitter2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
_fireEmmitter2.name = #"fireEmmitter";
_fireEmmitter2.zPosition = 1;
_fireEmmitter2.targetNode = self;
_fireEmmitter2.particleBirthRate = 0;
[self addChild: _fireEmmitter2];
//Setup a LightNode
SKLightNode* light = [[SKLightNode alloc] init];
light.categoryBitMask = 1;
light.falloff = 1;
light.ambientColor = [UIColor whiteColor];
light.lightColor = [[UIColor alloc] initWithRed:1.0 green:1.0 blue:0.0 alpha:0.5];
light.shadowColor = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.3];
[_fireEmmitter addChild:light];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
CGMutablePathRef ref = CGPathCreateMutable();
CGPoint p = touchPoint;
p = [self.scene convertPointToView:p];
CGPathMoveToPoint(ref, NULL, p.x, p.y);
_fireEmmitter.position = CGPointMake(touchPoint.x, touchPoint.y);
_fireEmmitter.particleBirthRate = 2000;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
//On Dragging make the emitter with the attached light follow the position
for (UITouch *touch in touches) {
[self addPointToMove:touchPoint];
CGPoint location = [touch locationInNode:self];
[self childNodeWithName:#"fireEmmitter"].position = CGPointMake(location.x, location.y);
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
_fireEmmitter.particleBirthRate = 0;
[self performSelector:#selector(userHasCompletedTheDrawing) withObject:nil afterDelay:3];
}
- (void)userHasCompletedTheDrawing{
CGMutablePathRef path = CGPathCreateMutable();
if (_wayPoints && _wayPoints.count > 0) {
CGPoint p = [(NSValue *)[_wayPoints objectAtIndex:0] CGPointValue];
//p = [self.scene convertPointToView:p];
CGPathMoveToPoint(path, nil, p.x, p.y);
_fireEmmitter2.position = CGPointMake(p.x,p.y);
_fireEmmitter2.particleBirthRate = 1000;
for (int i = 0; i < _wayPoints.count; ++i) {
p = [(NSValue *)[_wayPoints objectAtIndex:i] CGPointValue];
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
SKAction *followTrack = [SKAction followPath:path asOffset:NO orientToPath:YES duration:1];
[_fireEmmitter2 runAction:followTrack completion:^{
_fireEmmitter2.particleBirthRate = 0;
[_fireEmmitter2 runAction:[SKAction waitForDuration:1] completion:^{
//_fireEmmitter2.particleBirthRate = 0;
}];
}];
}
//myTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: #selector(removePointToMove) userInfo: nil repeats: YES];
[self performSelector:#selector(removeAllPointToMove) withObject:nil afterDelay:1];
}
- (void)addPointToMove:(CGPoint)point {
[_wayPoints addObject:[NSValue valueWithCGPoint:point]];
}
- (void)removeAllPointToMove{
[_wayPoints removeAllObjects];
}
- (void)removePointToMove{
if ([_wayPoints count]>0) {
[_wayPoints removeObjectAtIndex:0];
}
}
- (void)drawLines {
//1
NSMutableArray *temp = [NSMutableArray array];
for(CALayer *layer in self.view.layer.sublayers) {
if([layer.name isEqualToString:#"line"]) {
[temp addObject:layer];
}
}
[temp makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
//3
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.name = #"line";
lineLayer.strokeColor = [UIColor orangeColor].CGColor;
lineLayer.fillColor = nil;
lineLayer.lineWidth = 3;
lineLayer.lineJoin = kCALineJoinRound; /* The join style used when stroking the path. Options are `miter', `round'
* and `bevel'. Defaults to `miter'. */
lineLayer.zPosition = -1;
//4
CGPathRef path = [self createPathToMove];
lineLayer.path = path;
CGPathRelease(path);
[self.view.layer addSublayer:lineLayer];
}
- (CGPathRef)createPathToMove {
//1
CGMutablePathRef ref = CGPathCreateMutable();
//2
for(int i = 0; i < [_wayPoints count]; ++i) {
CGPoint p = [_wayPoints[i] CGPointValue];
p = [self.scene convertPointToView:p];
//3
if(i == 0 ) {
CGPathMoveToPoint(ref, NULL, p.x, p.y);
} else {
CGPathAddLineToPoint(ref, NULL, p.x, p.y);
}
}
return ref;
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
[self drawLines];
if ([_wayPoints count]==0) {
[myTimer invalidate];
}
}
#end
This is my .sks files properties:
Concerning your first question, you need to split your CGPathRef into multiple subpaths so that no line gets drawn between the petals and the center. Use the CGPathCloseSubpath function when you are done drawing the petals so that you can call CGPathMoveToPoint and CGPathAddLineToPoint afterwards.

SprikeKit physics - How can i make my character stand up after falling down?

I'm new to sprite kit and game physics in general. I want my character to stand up upright whenever he falls over or knocked down. A bit like a floor-mounted punch bag. Here's my current code:
#import "MyScene.h"
#interface MyScene () <SKPhysicsContactDelegate> {
SKSpriteNode *_body;
SKSpriteNode *_leg1;
SKSpriteNode *_leg2;
SKSpriteNode *_foot1;
SKSpriteNode *_foot2;
}
#end
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//self.backgroundColor = [SKColor greenColor];
self.physicsWorld.gravity = CGVectorMake(0, -2.0);
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *button = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
button.position = CGPointMake(40, 40);
button.zPosition = 10;
button.name = #"button";
[self addChild: button];
[self createCharacter];
}
return self;
}
-(void)createCharacter {
// Add sprites
_body = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(40, 60)];
_body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild: _body];
_leg1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg1.position = CGPointMake(_body.position.x+20-7, _body.position.y-65);
[self addChild:_leg1];
_foot1 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot1.position = CGPointMake(_leg1.position.x-2.5, _leg1.position.y-40);
[self addChild:_foot1];
_leg2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(14, 60)];
_leg2.position = CGPointMake(_body.position.x-20+7, _body.position.y-65);
[self addChild:_leg2];
_foot2 = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(20, 10)];
_foot2.position = CGPointMake(_leg2.position.x-2.5, _leg2.position.y-40);
[self addChild:_foot2];
// Add physics bodies to sprites
_body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_body.size];
_leg1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg1.size];
_foot1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot1.size];
_foot1.physicsBody.mass = 1;
_leg2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_leg2.size];
_foot2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_foot2.size];
_foot2.physicsBody.mass = 0.5;
// Add joints
SKPhysicsJoint *hipJoint = [SKPhysicsJointFixed jointWithBodyA:_body.physicsBody bodyB:_leg1.physicsBody anchor:_leg1.position];
SKPhysicsJoint *ankleJoint = [SKPhysicsJointFixed jointWithBodyA:_leg1.physicsBody bodyB:_foot1.physicsBody anchor:_foot1.position];
SKPhysicsJointPin *hipJoint2 = [SKPhysicsJointPin jointWithBodyA:_body.physicsBody bodyB:_leg2.physicsBody anchor:CGPointMake(_leg2.position.x, CGRectGetMaxY(_leg2.frame))];
[hipJoint2 setShouldEnableLimits:YES];
[hipJoint2 setLowerAngleLimit:-M_PI_2];
[hipJoint2 setUpperAngleLimit:0.0];
SKPhysicsJoint *ankleJoint2 = [SKPhysicsJointFixed jointWithBodyA:_leg2.physicsBody bodyB:_foot2.physicsBody anchor:_foot2.position];
[self.scene.physicsWorld addJoint:hipJoint];
[self.scene.physicsWorld addJoint:ankleJoint];
[self.scene.physicsWorld addJoint:hipJoint2];
[self.scene.physicsWorld addJoint:ankleJoint2];
}
-(void)characterJump {
CGFloat radianFactor = 0.0174532925;
CGFloat rotationInDegrees = _body.zRotation / radianFactor;
CGFloat newRotationDegrees = rotationInDegrees + 90;
CGFloat newRotationRadians = newRotationDegrees * radianFactor;
CGFloat r = 500;
CGFloat dx = r * cos(newRotationRadians);
CGFloat dy = r * sin(newRotationRadians);
[_body.physicsBody applyImpulse:CGVectorMake(dx, dy)];
NSLog(#"leg2 rotation: %f", _foot2.zRotation / radianFactor);
}
-(void)characterKick {
NSLog(#"Kick..");
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"button"]) {
[self characterJump];
[self characterKick];
}
}
-(void)update:(CFTimeInterval)currentTime {
}
#end
Run the code and tap the button to make him jump and eventually fall over. Also, the joint limits don't work as it breaks through the limits sometimes.
Help would be really appreciated.
I resolved this issue by checking the _body SKSpriteNode's 'y' position in the scene's update method. If the 'y' position was below a certain limit, I applied an impulse to the body's physicsBody from below to stand it up again.
This worked as required/desired.
-(void)update:(CFTimeInterval)currentTime {
if(_body.position.y < 30) {
[self upOnYourFeet];
}
}
-(void)upOnYourFeet {
[_body.physicsBody applyImpulse:CGVectorMake(0, 80)];
}

How can I make the score equal to the elapsed time playing the game( in seconds) in spritekit

Okay, so I tried the orbivoid tutorial, however I want that the elapsed time (in seconds) would be the score of the player and not the number of enemy respawned. I tried so many things with regards to NSTimer, NSTimeInterval and CFTimeInterval but needless to say, I failed. Can somebody help me with regards to this -- What code to add, tips or something? BTW, this is the GameScene.m in the orbivoid tutorial.
Thank you in advance!
#implementation GameScene
{
BOOL _dead;
SKNode *_player;
NSMutableArray *_enemies;
SKLabelNode *_scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.physicsWorld.contactDelegate = self;
_enemies = [NSMutableArray new];
_player = [SKNode node];
SKShapeNode *circle = [SKShapeNode node];
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-10, -10, 20, 20)].CGPath;`
circle.fillColor = [UIColor blueColor];
circle.glowWidth = 5;
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.position = CGPointMake(CGRectGetMidX(circle.frame), CGRectGetMidY(circle.frame));
_player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_player.physicsBody.mass = 100000;
_player.physicsBody.categoryBitMask = CollisionPlayer;
_player.physicsBody.contactTestBitMask = CollisionEnemy;
[_player addChild:trail];
_player.position = CGPointMake(size.width/2, size.height/2);
[self addChild:_player];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
}
-(void)spawnEnemy
{
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
SKNode *enemy = [SKNode node];
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.particleScale /= 2;
trail.position = CGPointMake(10, 10);
trail.particleColorSequence = [[SKKeyframeSequence alloc] initWithKeyframeValues:#[
[SKColor redColor],
[SKColor colorWithHue:0.1 saturation:.5 brightness:1 alpha:1],
[SKColor redColor],
] times:#[#0, #0.02, #0.2]];
[enemy addChild:trail];
enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:6];
enemy.physicsBody.categoryBitMask = CollisionEnemy;
enemy.physicsBody.allowsRotation = NO;
enemy.position = CGPointMake(50, 50);
[_enemies addObject:enemy];
[self addChild:enemy];
if(!_scoreLabel) {
_scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Courier-Bold"];
_scoreLabel.fontSize = 200;
_scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
_scoreLabel.fontColor = [SKColor colorWithHue:0 saturation:0 brightness:1 alpha:0.5];
[self addChild:_scoreLabel];
}
_scoreLabel.text = [NSString stringWithFormat:#"%02d", _enemies.count];
// Next spawn
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:5],
[SKAction performSelector:#selector(spawnEnemy) onTarget:self],
]]];
}
-(void)dieFrom: (SKNode*)killingEnemy
{
_dead = YES;
SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:#"Explosion"];
explosion.position = _player.position;
[self addChild:explosion];
[explosion runAction:[SKAction sequence:#[
[SKAction playSoundFileNamed:#"Explosion.wav" waitForCompletion:NO],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
// TODO: Revove these more nicely
[killingEnemy removeFromParent];
[_player removeFromParent];
}],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
explosion.particleBirthRate = 0;
}],
[SKAction waitForDuration: 1.2],
[SKAction runBlock:^{
ORBMenuScene *menu = [[ORBMenuScene alloc] initWithSize:self.size];
[self.view presentScene:menu transition:[SKTransition doorsCloseHorizontalWithDuration:0.4]];
}],
]]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved: (NSSet *) touches withEvent:(UIEvent *)event
{
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:.01]];
}
-(void)update:(CFTimeInterval)currentTime
{
CGPoint playerPos = _player.position;
for(SKNode *enemyNode in _enemies)
{
CGPoint enemyPos = enemyNode.position;
/* Uniform speed: */
CGVector diff = TCVectorMinus(playerPos, enemyPos);
CGVector normalized = TCVectorUnit(diff);
CGVector force = TCVectorMultiply(normalized, 4);
[enemyNode.physicsBody applyForce:force];
}
_player.physicsBody.velocity = CGVectorMake (0, 0);
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
if(_dead)
return;
[self dieFrom:contact.bodyB.node];
contact.bodyB.node.physicsBody = nil;
}
#end
Simple Version: create a score integer (_block needed because you're going to use it in a block)
__block int score123=0;
Run an action that increases your integer then waits 1.0 seconds before doing it again. This sequence repeats forever. Give the action the key "scoreIncrease" so you can stop it later.
SKAction *scoreIncrease = [SKAction repeatActionForever:[SKAction sequence:#[[SKAction runBlock:^{ score123++; }],[SKAction waitForDuration:1.0f]]]];
[self runAction:scoreIncrease withKey:#"scoreIncrease"];
When you want to stop the counting, use this:
[self removeActionForKey:#"scoreIncrease"];

How can I have a definite number of enemies(ex.10 only) randomly spawned outside of screen then going inside?

This is the orbivoid tutorial GameScene.m. So my problem is that, enemies spawning is just located somewhere in the lower left due to the CGPointMake. I want to make them already spawned outside of the screen at the start of the game with a definite number, randomly located(ex. 10 enemies already spawned outside of the screen at different locations). Can somebody please help me (some code, tips or something to implement for this)? I did not change anything in the GameScene.m so for the convenience of those who wants to help me. Thanks!
#implementation GameScene
{
BOOL _dead;
SKNode *_player;
NSMutableArray *_enemies;
SKLabelNode *_scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.physicsWorld.contactDelegate = self;
_enemies = [NSMutableArray new];
_player = [SKNode node];
SKShapeNode *circle = [SKShapeNode node];
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-10, -10, 20, 20)].CGPath;`
circle.fillColor = [UIColor blueColor];
circle.glowWidth = 5;
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.position = CGPointMake(CGRectGetMidX(circle.frame), CGRectGetMidY(circle.frame));
_player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_player.physicsBody.mass = 100000;
_player.physicsBody.categoryBitMask = CollisionPlayer;
_player.physicsBody.contactTestBitMask = CollisionEnemy;
[_player addChild:trail];
_player.position = CGPointMake(size.width/2, size.height/2);
[self addChild:_player];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
}
-(void)spawnEnemy
{
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
SKNode *enemy = [SKNode node];
SKEmitterNode *trail = [SKEmitterNode orb_emitterNamed:#"Trail"];
trail.targetNode = self;
trail.particleScale /= 2;
trail.position = CGPointMake(10, 10);
trail.particleColorSequence = [[SKKeyframeSequence alloc] initWithKeyframeValues:#[
[SKColor redColor],
[SKColor colorWithHue:0.1 saturation:.5 brightness:1 alpha:1],
[SKColor redColor],
] times:#[#0, #0.02, #0.2]];
[enemy addChild:trail];
enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:6];
enemy.physicsBody.categoryBitMask = CollisionEnemy;
enemy.physicsBody.allowsRotation = NO;
enemy.position = CGPointMake(50, 50);
[_enemies addObject:enemy];
[self addChild:enemy];
if(!_scoreLabel) {
_scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Courier-Bold"];
_scoreLabel.fontSize = 200;
_scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
_scoreLabel.fontColor = [SKColor colorWithHue:0 saturation:0 brightness:1 alpha:0.5];
[self addChild:_scoreLabel];
}
_scoreLabel.text = [NSString stringWithFormat:#"%02d", _enemies.count];
// Next spawn
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:5],
[SKAction performSelector:#selector(spawnEnemy) onTarget:self],
]]];
}
-(void)dieFrom: (SKNode*)killingEnemy
{
_dead = YES;
SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:#"Explosion"];
explosion.position = _player.position;
[self addChild:explosion];
[explosion runAction:[SKAction sequence:#[
[SKAction playSoundFileNamed:#"Explosion.wav" waitForCompletion:NO],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
// TODO: Revove these more nicely
[killingEnemy removeFromParent];
[_player removeFromParent];
}],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
explosion.particleBirthRate = 0;
}],
[SKAction waitForDuration: 1.2],
[SKAction runBlock:^{
ORBMenuScene *menu = [[ORBMenuScene alloc] initWithSize:self.size];
[self.view presentScene:menu transition:[SKTransition doorsCloseHorizontalWithDuration:0.4]];
}],
]]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved: (NSSet *) touches withEvent:(UIEvent *)event
{
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:.01]];
}
-(void)update:(CFTimeInterval)currentTime
{
CGPoint playerPos = _player.position;
for(SKNode *enemyNode in _enemies)
{
CGPoint enemyPos = enemyNode.position;
/* Uniform speed: */
CGVector diff = TCVectorMinus(playerPos, enemyPos);
CGVector normalized = TCVectorUnit(diff);
CGVector force = TCVectorMultiply(normalized, 4);
[enemyNode.physicsBody applyForce:force];
}
_player.physicsBody.velocity = CGVectorMake (0, 0);
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
if(_dead)
return;
[self dieFrom:contact.bodyB.node];
contact.bodyB.node.physicsBody = nil;
}
#end
This is only an educated guess, since I can’t test my code.
I think in your didMoveToView method you can do this
for (int i = 0; i < 10; i++)
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
to spawn 10 enemies at once.
In your spawnEnemy method you set the position of the enemies similar to this:
CGFloat x = arc4random() % 100 + size.width/2;
CGFLoat y = arc4random() % (int)size.height;
if (arc4random() % 2 == 0)
x = size.width/2 + x;
else
x = size.width/2 - x;
enemy.position = CGPointMake(x, y);
This should spawn the enemies beyond the left and right side of the screen, but within 100 points of the edge of the screen.
Of course you need to tweak this to your needs.

So the collision effect(explosion) doesn't work anymore after changing the player and enemy from SKShapeNode to a .png file [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I changed the custom circular shapes (SKShapeNode *circle) of the player and enemy to a .png file. Before changing the player and enemy to a .png file, there was this explosion effect after collision. However, after changing to .png file, the explosion effect does not happen anymore. Yes, the images bump each other which basically shows that there's collision. But the explosion effect after colliding with each other does not show anymore. How can I implement it again, I need some help please. Thank you very much!
#import "GameScene.h"
#import "CGVector+TC.h"
#import "ORBMenuScene.h"
enum {
CollisionPlayer = 1<<1,
CollisionEnemy = 1<<2,
};
#interface GameScene () <SKPhysicsContactDelegate>
#end
#implementation GameScene
{
BOOL _dead;
SKNode *_player;
NSMutableArray *_enemies;
SKLabelNode *_scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.physicsWorld.contactDelegate = self;
_enemies = [NSMutableArray new];
_player = [SKNode node];
_player = [SKSpriteNode spriteNodeWithImageNamed:#"Player.png"];
_player.position = CGPointMake(size.width/2, size.height/2);
_player.physicsBody.dynamic = YES;
_player.physicsBody.mass = 0.2;
_player.physicsBody.categoryBitMask = CollisionPlayer;
_player.physicsBody.contactTestBitMask = CollisionEnemy;
_player.physicsBody.collisionBitMask = CollisionEnemy;
_player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_player.position = CGPointMake(size.width/2, size.height/2);
_player.physicsBody.allowsRotation = YES;
_player.physicsBody.usesPreciseCollisionDetection = YES;
_player.name = #"Player";
[_player setScale:1];
[self addChild:_player];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[self performSelector:#selector(spawnEnemy) withObject:nil afterDelay:1.0];
}
-(void)spawnEnemy
{
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
SKNode *enemy = [SKNode node];
enemy = [SKSpriteNode spriteNodeWithImageNamed:#"Enemy.png"];
enemy.physicsBody.categoryBitMask = CollisionEnemy;
enemy.physicsBody.contactTestBitMask = CollisionPlayer;
enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:6];
enemy.physicsBody.collisionBitMask = CollisionPlayer;
enemy.physicsBody.allowsRotation = YES;
enemy.physicsBody.dynamic = YES;
enemy.name = #"Enemy";
[enemy setScale:0.5];
CGFloat x = arc4random() % 70 + self.size.width/2;
CGFloat y = arc4random() % (int) self.size.height;
if (arc4random() % 2 == 0)
x = self.size.width/2 + x;
else
x = self.size.width/2 - x;
enemy.position = CGPointMake(x, y);
[_enemies addObject:enemy];
[self addChild:enemy];
if(!_scoreLabel) {
_scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Courier-Bold"];
_scoreLabel.fontSize = 200;
_scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
_scoreLabel.fontColor = [SKColor colorWithHue:0 saturation:0 brightness:1 alpha:0.5];
[self addChild:_scoreLabel];
}
_scoreLabel.text = [NSString stringWithFormat:#"%02d", _enemies.count];
if (_enemies.count == 18) {
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:99999],
[SKAction performSelector:#selector(spawnEnemy) onTarget:self],
]]];
}
else {
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:1],
[SKAction performSelector:#selector(spawnEnemy) onTarget:self],
]]];
}
}
-(void)dieFrom: (SKNode*)killingEnemy
{
_dead = YES;
SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:#"Explosion"];
explosion.position = _player.position;
[self addChild:explosion];
[explosion runAction:[SKAction sequence:#[
[SKAction playSoundFileNamed:#"Explosion.wav" waitForCompletion:NO],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
// TODO: Revove these more nicely
[killingEnemy removeFromParent];
[_player removeFromParent];
}],
[SKAction waitForDuration:0.4],
[SKAction runBlock:^{
explosion.particleBirthRate = 0;
}],
[SKAction waitForDuration: 1.2],
[SKAction runBlock:^{
ORBMenuScene *menu = [[ORBMenuScene alloc] initWithSize:self.size];
[self.view presentScene:menu transition:[SKTransition doorsCloseHorizontalWithDuration:0.4]];
}],
]]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
-(void)touchesMoved: (NSSet *) touches withEvent:(UIEvent *)event
{
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:.01]];
}
-(void)update:(CFTimeInterval)currentTime
{
CGPoint playerPos = _player.position;
for(SKNode *enemyNode in _enemies)
{
CGPoint enemyPos = enemyNode.position;
/* Uniform speed: */
CGVector diff = TCVectorMinus(playerPos, enemyPos);
CGVector normalized = TCVectorUnit(diff);
CGVector force = TCVectorMultiply(normalized, 4);
[enemyNode.physicsBody applyForce:force];
}
_player.physicsBody.velocity = CGVectorMake (0, 0);
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
if(_dead)
return;
[self dieFrom:contact.bodyB.node];
contact.bodyB.node.physicsBody = nil;
}
#end
It seems to me you did not initialize physicsBody before setting its properties.
After creating a player or enemy you should first initialize a body to use. Otherwise it will be nil indicating that the node does not participate in the physics simulation at all. And all property setting will be useless.
This should do for you, dont forget to move that line for the enemy as well!
_player = [SKSpriteNode spriteNodeWithImageNamed:#"Player.png"];
_player.position = CGPointMake(size.width/2, size.height/2);
_player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_player.physicsBody.dynamic = YES;
_player.physicsBody.mass = 0.2;