iOS7 SKScene how to make a sprite bounce off the edge of the screen?
Asked Answered
M

4

5

I'm building a game with balls bouncing within the iPad's screen. Similar to a Pong game. I see that SKScene's SKPhysicsWorld has gravity property, and also controls how objects collide with each other.

Is there some way I can automatically detect if a sprite's edge has collided with the screen's edge, so it can bounce off that? Or do I need to write my own collision code?

Mussel answered 9/11, 2013 at 22:26 Comment(0)
Q
10

You don't need to write much code to make the ball bounce off the edge of the screen. the physics environment can handle all of the above, you just need to instantiate the sprites in the correct way.

First, you will have to set the physicsBody of the scene as such:

self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];

In your scene's .h file create two bitmask categories:

static const uint8_t ballCategory = 1;
static const uint8_t wallCategory = 2;

And give the scene's physics body a category:

self.physicsBody.categoryBitMask = wallCategory;

Then create your sprite:

SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:@"ball.png"]; 

spriteNode.name = @"ball";

spriteNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:25];
spriteNode.position = CGPointMake(10.0,10.0); //or anything you want
spriteNode.physicsBody.dynamic = YES;
spriteNode.physicsBody.affectedByGravity = NO;

spriteNode.physicsBody.categoryBitMask = ballCategory;
spriteNode.physicsBody.collisionBitMask = wallCategory;

spriteNode.physicsBody.restitution = 1.0;
spriteNode.physicsBody.friction = 0.0;
spriteNode.physicsBody.linearDamping = 0.0;
spriteNode.physicsBody.angularDamping = 0.0;

[self addChild:spriteNode];

Instead of giving the spriteNode a [SKAction moveTo: duration:], apply an impulse to it's physics body.

CGVector impulse = CGVectorMake(1.0,1.0);
[spriteNode.physicsBody applyImpulse:impulse];

And voila! The ball will be bouncing off the walls with nothing to stop it.

This is what the .h file should look like:

#import <SpriteKit/SpriteKit.h>

static const uint8_t ballCategory = 1;
static const uint8_t wallCategory = 2;

@interface BallBounce : SKScene

@end

And this is how the .m file should look like:

#import "BallBounce.h"

@implementation BallBounce

-(instancetype)initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size])
    {
        self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
        self.physicsBody.categoryBitMask = wallCategory;

        SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(50, 50)];

        spriteNode.name = @"ball";

        spriteNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:25];
        spriteNode.position = CGPointMake(10.0,10.0); //or anything you want
        spriteNode.physicsBody.dynamic = YES;
        spriteNode.physicsBody.affectedByGravity = NO;

        spriteNode.physicsBody.categoryBitMask = ballCategory;
        spriteNode.physicsBody.collisionBitMask = wallCategory;

        spriteNode.physicsBody.restitution = 1.0;
        spriteNode.physicsBody.friction = 0.0;
        spriteNode.physicsBody.linearDamping = 0.0;
        spriteNode.physicsBody.angularDamping = 0.0;

        [self addChild:spriteNode];

        CGVector impulse = CGVectorMake(100.0,100.0);
        [spriteNode.physicsBody applyImpulse:impulse];

    }

    return self;
}

@end
Qr answered 5/12, 2013 at 10:57 Comment(8)
my ball is just staying in the position without moving. Something wrong?Woodie
Yes. Try increasing the value of the impulse. Use 100,100 for a startQr
strange, I copied your code exactly and set the impulse to 100,100 but it still just sits on the screenWoodie
in the self init right after I add the ball as a subview.Woodie
This code runs perfectly on my side... I am changing the answer to show the whole .h and .m fileQr
let us continue this discussion in chatQr
I just test your code, It work if i reduce the impulse value, square don't bounce on edge side. It rises on the edge side. Any idea?Stylus
This depends upon your physics environment as well as the properties of the physicsBodies. The restitution and friction properties may need to be adjusted. A perfect bounce on all directions is achieved using a circular physicsBody.Qr
O
7

Have you tried setting the physics body of SKScene

[self setPhysicsBody:[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]];  //Physics body of Scene

That should keep your node's inside the frame.

W

Oldtime answered 10/11, 2013 at 22:37 Comment(0)
W
2

This is from the http://www.raywenderlich.com/49721/how-to-create-a-breakout-game-using-spritekit

    SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
    // 2 Set physicsBody of scene to borderBody
    self.physicsBody = borderBody;
    // 3 Set the friction of that physicsBody to 0
    self.physicsBody.friction = 0.0f;

    // 1
    SKSpriteNode* ball = [SKSpriteNode spriteNodeWithImageNamed: @"Sphere.png"];
    ball.name = @"ball";
    ball.position = CGPointMake(self.frame.size.width/3, self.frame.size.height/3);
    [self addChild:ball];

    // 2
    ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
    // 3
    ball.physicsBody.friction = 0.0f;
    // 4
    ball.physicsBody.restitution = 1.0f;
    // 5
    ball.physicsBody.linearDamping = 0.0f;
    // 6
    ball.physicsBody.allowsRotation = NO;
    ball.physicsBody.affectedByGravity = NO;

    [ball.physicsBody applyImpulse:CGVectorMake(10.0f, 10.0f)];
Woodie answered 7/3, 2014 at 5:47 Comment(0)
S
2

This will bring your node in the frame in Swift:

self.physicsBody = SKPhysicsBody (edgeLoopFromRect: self.frame)
Sketch answered 10/8, 2015 at 6:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.