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

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)];
}

Related

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

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];
}
}

No bounce of physics bodies?

I have very simple code:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor whiteColor];
self.anchorPoint = CGPointMake(0.5, 0.5);
self.physicsWorld.gravity = CGVectorMake(0, -1.0);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.dynamic = YES;
self.physicsBody.affectedByGravity = NO;
self.physicsBody.categoryBitMask = wallCategory;
self.physicsBody.collisionBitMask = nodeCategory;
self.physicsBody.contactTestBitMask = nodeCategory;
self.physicsWorld.contactDelegate = self;
SKSpriteNode *node1 = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(50, 50)];
SKSpriteNode *node2 = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(20, 20)];
node2.position = CGPointMake(0, -node1.frame.size.height/2+node2.frame.size.height/2);
node1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node1.frame.size];
node1.physicsBody.dynamic = YES;
node1.physicsBody.categoryBitMask = nodeCategory;
node1.physicsBody.collisionBitMask = wallCategory;
node1.physicsBody.contactTestBitMask = wallCategory;
node1.physicsBody.restitution = 1.0;
node1.physicsBody.friction = 0.0;
node1.physicsBody.linearDamping = 0.0;
node1.physicsBody.angularDamping = 0.0;
[node1 addChild:node2];
[self addChild:node1];
}
return self;
}
Yet the node1 just falls through(affected by gravity) the screen without bouncing off the bottom. What am I doing wrong?
Give node1 a position:
node1.position = CGPointMake(self.frame.size.width/2,self.frame.size.height/2);

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;