0

I just started using SpriteBuilder with cocos2d - v3. It looks promising and a good tool to have.

But my issue is that I want to create a man like character with all body parts as different sprites and put them into a Physics body using joints. I am struggling to find any example of it using spritebuilder or chipmunk.

Will greatly appreciate any help here. Thx in advance.

EDIT : Here's code for body. I used peevedpenquin example from link Here is my code for character body. I just added a block as body part to penguin's tail.

 #import "PenguinWithBlock.h"

@implementation PenguinWithBlock{
    CCNode *_pBlock;
    CCNode *_penguinB;
    CCPhysicsJoint *_penguinJoint;
    CCPhysicsNode *_penguinNode;
}

- (void)didLoadFromCCB {

    _penguinNode.debugDraw = TRUE;

    [_pBlock.physicsBody setCollisionGroup:_penguinB];
    [_penguinB.physicsBody setCollisionGroup:_penguinB];

    // create a joint to connect the catapult arm with the catapult
    _penguinJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_penguinB.physicsBody bodyB:_pBlock.physicsBody anchorA:_penguinB.anchorPointInPoints];
}

This is Gameplay.m file

@implementation Gameplay {
    CCPhysicsNode *_physicsNode;
    CCNode *_catapultArm;
    CCNode *_catapult;
    CCNode *_levelNode;
    CCNode *_contentNode;
    CCPhysicsJoint *_catapultJoint;

    CCNode *_pullbackNode;
    CCPhysicsJoint *_pullbackJoint;
    CCNode *_mouseJointNode;
    CCPhysicsJoint *_mouseJoint;

    PenguinWithBlock *_currentPenguin;
    CCPhysicsJoint *_penguinCatapultJoint;

    CCAction *_followPenguin;
}

// is called when CCB file has completed loading
- (void)didLoadFromCCB {
    // tell this scene to accept touches
    self.userInteractionEnabled = TRUE;
    _physicsNode.collisionDelegate = self;

    CCScene *level = [CCBReader loadAsScene:@"Levels/Level1"];
    [_levelNode addChild:level];

    // visualize physics bodies & joints
    //_physicsNode.debugDraw = TRUE;

    // catapultArm and catapult shall not collide
    [_catapultArm.physicsBody setCollisionGroup:_catapult];
    [_catapult.physicsBody setCollisionGroup:_catapult];

    // create a joint to connect the catapult arm with the catapult
    _catapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_catapultArm.physicsBody bodyB:_catapult.physicsBody anchorA:_catapultArm.anchorPointInPoints];

    // nothing shall collide with our invisible nodes
    _pullbackNode.physicsBody.collisionMask = @[];
    // create a spring joint for bringing arm in upright position and snapping back when player shoots
    _pullbackJoint = [CCPhysicsJoint connectedSpringJointWithBodyA:_pullbackNode.physicsBody bodyB:_catapultArm.physicsBody anchorA:ccp(0, 0) anchorB:ccp(34, 138) restLength:60.f stiffness:500.f damping:40.f];

    _mouseJointNode.physicsBody.collisionMask = @[];

}

- (void)update:(CCTime)delta
{
    if (_currentPenguin.launched) {
        // if speed is below minimum speed, assume this attempt is over
        if (ccpLength(_currentPenguin.physicsBody.velocity) < MIN_SPEED){
            [self nextAttempt];
            return;
        }

        int xMin = _currentPenguin.boundingBox.origin.x;

        if (xMin < self.boundingBox.origin.x) {
            [self nextAttempt];
            return;
        }

        int xMax = xMin + _currentPenguin.boundingBox.size.width;

        if (xMax > (self.boundingBox.origin.x + self.boundingBox.size.width)) {
            [self nextAttempt];
            return;
        }
    }
}

- (void)nextAttempt {
    _currentPenguin = nil;
    [_contentNode stopAction:_followPenguin];

    CCActionMoveTo *actionMoveTo = [CCActionMoveTo actionWithDuration:1.f position:ccp(0, 0)];
    [_contentNode runAction:actionMoveTo];
}

// called on every touch in this scene
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint touchLocation = [touch locationInNode:_contentNode];

    // start catapult dragging when a touch inside of the catapult arm occurs
    if (CGRectContainsPoint([_catapultArm boundingBox], touchLocation))
    {
        // move the mouseJointNode to the touch position
        _mouseJointNode.position = touchLocation;

        // setup a spring joint between the mouseJointNode and the catapultArm
        _mouseJoint = [CCPhysicsJoint connectedSpringJointWithBodyA:_mouseJointNode.physicsBody bodyB:_catapultArm.physicsBody anchorA:ccp(0, 0) anchorB:ccp(34, 138) restLength:0.f stiffness:3000.f damping:150.f];

        // create a penguin from the ccb-file
        _currentPenguin = (PenguinWithBlock*)[CCBReader load:@"PenguinWithBlock"];
        // initially position it on the scoop. 34,138 is the position in the node space of the _catapultArm
        CGPoint penguinPosition = [_catapultArm convertToWorldSpace:ccp(34, 138)];
        // transform the world position to the node space to which the penguin will be added (_physicsNode)
        _currentPenguin.position = [_physicsNode convertToNodeSpace:penguinPosition];
        // add it to the physics world
        [_physicsNode addChild:_currentPenguin];
        // we don't want the penguin to rotate in the scoop
        _currentPenguin.physicsBody.allowsRotation = FALSE;

        // create a joint to keep the penguin fixed to the scoop until the catapult is released
        _penguinCatapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_currentPenguin.physicsBody bodyB:_catapultArm.physicsBody anchorA:_currentPenguin.anchorPointInPoints];
    }
}

- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    // whenever touches move, update the position of the mouseJointNode to the touch position
    CGPoint touchLocation = [touch locationInNode:_contentNode];
    _mouseJointNode.position = touchLocation;
}

- (void)launchPenguin {
    // loads the Penguin.ccb we have set up in Spritebuilder
    CCNode* penguin = [CCBReader load:@"PenguinWithBlock"];
    // position the penguin at the bowl of the catapult
    penguin.position = ccpAdd(_catapultArm.position, ccp(16, 50));

    // add the penguin to the physicsNode of this scene (because it has physics enabled)
    [_physicsNode addChild:penguin];

    // manually create & apply a force to launch the penguin
    CGPoint launchDirection = ccp(1, 0);
    CGPoint force = ccpMult(launchDirection, 8000);
    [penguin.physicsBody applyForce:force];

    // ensure followed object is in visible are when starting
    self.position = ccp(0, 0);
    CCActionFollow *follow = [CCActionFollow actionWithTarget:penguin worldBoundary:self.boundingBox];
    [_contentNode runAction:follow];
}

-(void) touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
    // when touches end, meaning the user releases their finger, release the catapult
    [self releaseCatapult];
}

-(void) touchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
    // when touches are cancelled, meaning the user drags their finger off the screen or onto something else, release the catapult
    [self releaseCatapult];
}

- (void)releaseCatapult {
    if (_mouseJoint != nil)
    {
        // releases the joint and lets the catapult snap back
        [_mouseJoint invalidate];
        _mouseJoint = nil;

        // releases the joint and lets the penguin fly
        [_penguinCatapultJoint invalidate];
        _penguinCatapultJoint = nil;

        // after snapping rotation is fine
        _currentPenguin.physicsBody.allowsRotation = TRUE;
        _currentPenguin.launched = TRUE;


        // follow the flying penguin
        _followPenguin = [CCActionFollow actionWithTarget:_currentPenguin worldBoundary:self.boundingBox];
        [_contentNode runAction:_followPenguin];
    }
}

-(void)ccPhysicsCollisionPostSolve:(CCPhysicsCollisionPair *)pair seal:(CCNode *)nodeA wildcard:(CCNode *)nodeB
{
    float energy = [pair totalKineticEnergy];

    // if energy is large enough, remove the seal
    if (energy > 5000.f)
    {
        [self sealRemoved:nodeA];
    }
}

- (void)sealRemoved:(CCNode *)seal {
    // load particle effect
    CCParticleSystem *explosion = (CCParticleSystem *)[CCBReader load:@"SealExplosion"];
    // make the particle effect clean itself up, once it is completed
    explosion.autoRemoveOnFinish = TRUE;
    // place the particle effect on the seals position
    explosion.position = seal.position;
    // add the particle effect to the same node the seal is on
    [seal.parent addChild:explosion];

    // finally, remove the destroyed seal
    [seal removeFromParent];
}

- (void)retry {
    // reload this level
    [[CCDirector sharedDirector] replaceScene: [CCBReader loadAsScene:@"Gameplay"]];
}

PenguinWithBlock settings in SpriteBuilder: enter image description here enter image description here enter image description here

James Webster
  • 31,873
  • 11
  • 70
  • 114
ganesh
  • 166
  • 3
  • 10
  • SpriteBuilder does not yet support Cocos3D components. Development for that is underway, and should be available within the next few months. However, did you mean to mention Cocos3D? From your description, you seem to want to use 2D sprites, and not a 3D model. If that is the case, then Cocos2D and SpriteBuilder should be able to get you there. – Bill Hollings Mar 14 '14 at 02:30
  • I'm pretty sure you meant cocos2d-iphone **v3** and not cocos **3d**. Also your question is pretty broad, it's not exactly straightforward to build a ragdoll but you can try searching for the term "ragdoll" on google to possibly find some tutorials or related resources. – CodeSmile Mar 14 '14 at 08:45
  • Hi Bill, its cocos2d-iphone v3 as LearnCocos2d mentioned. I am looking for how we can structure body parts in spritebuilder & then add joints in xcode. – ganesh Mar 14 '14 at 14:58

1 Answers1

1

You can use a "blank" CCNode with all others parts of the body being children of it, maybe even have children of another body parts. The tree of nodes will heavily depend on the body design.

Give a look at this tutorial, as it teaches the basics to do so. Also, SpriteBuilder still doesn't have the feature to create the joints inside it, but you can easily do this programmatically as the tutorial does.

EDIT: This can help you

Felizardo
  • 298
  • 1
  • 8
  • Thanks Felizardo, Do I also need to add CCPhysicsNode under CCNode like this : CCNode -> CCPhysicsNode -> {Torso, Head, arm etc} ? I tried this structure but when I add it in peevedpenguin tutorial it didn't quiet work because catapult arm & penguin joint have to be on same physicsNode but in this case they are on different nodes. I am posting my code in Question for reference. – ganesh Mar 14 '14 at 15:02
  • Hello ganesh, add the physicsNode as a common root for all the bodies, and you should not have a problem. I also highly recommend to set the position and contentSize of the physicsNode as (0,0). On the angry birds tutorial you can check previous sections that teach you this. – Felizardo Mar 15 '14 at 18:50
  • Hi Felizardo, appreciate your comment. I tried as you suggested i.e in Penguin.ccb I defined structure as follows: CCNode->CCPhysicsNode->{Body1, Body2}. Also added position and contentSize of CCPhysicsNode to (0,0). But it fails as soon as I tap on catapult to load a penguin. It fails when creating joint b/w catapult & penguin at "_penguinCatapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_currentPenguin.physicsBody bodyB:_catapultArm.physicsBody anchorA:_currentPenguin.anchorPointInPoints];" with error reason: 'Bodies connected by a joint must be added to the same CCPhysicsNode.' – ganesh Mar 15 '14 at 20:43
  • I have added screenshots above from SpriteBuilder – ganesh Mar 15 '14 at 20:51
  • You shouldn't add another CCPhysicsNode on penguin.ccb, only on the level/gameplay as a parent for ALL the Penguins and other sprites/bodies. Download the source code of the tutorial to check how it is done. https://github.com/MakeGamesWithUs/PeevedPenguins.spritebuilder – Felizardo Mar 16 '14 at 22:34
  • I removed physicsNode from penguin.ccb but still it's failing with same error 'Bodies connected by a joint must be added to the same CCPhysicsNode.' at this line: _penguinCatapultJoint = [CCPhysicsJoint connectedPivotJointWithBodyA:_currentPenguin.physicsBody bodyB:_catapultArm.physicsBody anchorA:_currentPenguin.anchorPointInPoints];" . Not sure what I am missing. I looked at above project, it's not opening in SpriteBuilder and in xcode I didn't see any character defined with multiple body parts. Please correct me if wrong. Thx – ganesh Mar 17 '14 at 20:15
  • Under penguin.ccb, Enable Physics is disabled on root CCNode. After enabling it, its not crashing anymore but physics behaviour is all weird now. Not sure if this is correct approach to enable physics on root CCNode and then also on it's children body parts individually? – ganesh Mar 17 '14 at 20:23