Adding multiple obstacles causes decrease in FPS - c++

I am new to cocos2d-x and i am developing a game using cocos2d-x in x-code and in my game scene i have a player sprite and obstacle sprites. Player sprite is running on the same place and obstacle sprites are moving from right to left of the scene. After the inclusion of obstacle sprites my scene FPS is keep on decreasing from 50 to below 10. And i am using the following code to add my obstacle sprites. I am assigning the tag to obstacles for collision detection.
bool init()
{
time=1;
schedule( schedule_selector(playscene::spritemovefinished));
void PlayScene::OnObstacle()
{
time=time+1;
i=arcrandom()%9;
obs1->setPosition(ccp((winwsize/5)+(2*winwsize),winhsize/2.45));
this->addChild(obs1,1);
obs1->setVisible(true);
obs1->setTag(2);
_obs1->addObject(obs1);
obs2 = CCSprite::create("obs2.png");
obs2->setPosition(ccp((winwsize/5)+(2*winwsize),winhsize/2.45));
this->addChild(obs2 ,1);
obs2->setVisible(true);
obs2->setTag(2);
_obs2->addObject(obs2);
if(time%60==0&&i>=0&&i<=1)
{
CCFiniteTimeAction* act1=CCMoveTo::create(7.0,ccp(-50,winhsize/2.45));
CCFiniteTimeAction* act1end=CCCallFuncN::create(this,callfuncN_selector(PlayScene::spriteMoveFinished));
obs1->runAction(CCSequence::create(act1,act1end,NULL));
CCRotateBy *rot=CCRotateBy::create(13, -2000);
obs1->runAction(rot);
}
else if(time%60==0&&i>1&&i<=2)
{
CCFiniteTimeAction* act2=CCMoveTo::create(7.0,ccp(-50,winhsize/2.45));
CCFiniteTimeAction* act2end=CCCallFuncN::create(this,callfuncN_selector(PlayScene::spriteMoveFinished));
obs2->runAction(CCSequence::create(act2,act2end,NULL));
CCRotateBy *rot1=CCRotateBy::create(13, -2000);
obs2->runAction(rot1);
}
}
void PlayScene::spritemovefinished(CCNODE* sender)
{
CCSprite *sprite = (CCSprite *)sender;
this->removeChild(sprite, true);
}

Related

How to remove a sprite permanently in Cocos2d-x

I am developing a game using cocos2d-x. I want to remove sprites permanently. I have two sprites & making collision between the sprites. When collision happens, i want to remove those sprites permanently. I am using the following code to making collision & remove sprites.
CCARRAY_FOREACH(_sprrand24, stwentyfour)
{
CCSize size=sprrand24->getContentSize();
CCSprite *sprrand24 = dynamic_cast<CCSprite*>(stwentyfour);
CCRect sprrand24Rect = CCRectMake(
sprrand24->getPosition().x - (size.width/2),
sprrand24->getPosition().y - (size.height/2),
size.width/2,
size.height/2);
CCARRAY_FOREACH(_sprrand25, stwentyfive)
{
CCSize size=sprrand25->getContentSize();
CCSprite *sprrand25 = dynamic_cast<CCSprite*>(stwentyfive);
CCRect sprrand25Rect = CCRectMake(
sprrand25->getPosition().x - (size.width/2),
sprrand25->getPosition().y - (size.height/2),
size.width/2,
size.height/2);
if (sprrand24Rect.intersectsRect(sprrand25Rect))
{
this->removeChild(sprrand24, true);
this->removeChild(sprrand25, true);
}
}
}
To remove the sprite you can use
sprrand24.removeFromParentAndCleanup(true);
if you assign each of your Sprites a tag, you can then do removeChildByTag(tag);
sprite->setTag(99); // i made this up
this->removeChildByTag(99);

CCActionFollow will not follow the target object and scroll layer

I have a ball object that falls straight down a level made in SpriteBuilder as a layer. The level is added to the gameplay scene, which has a ccnode (_levelNode) as a child of the physics node. However, when the game runs it either doesn't scroll, or the view is messed up.
My code is:
- (void)didLoadFromCCB {
//_physicsNode.debugDraw = TRUE;
_loadedLevel = [CCBReader load:#"levels/Level1" owner:self];
[_levelNode addChild: _loadedLevel];
}
- (void)onEnter {
[super onEnter];
self.userInteractionEnabled = TRUE;
self.isGamePaused = FALSE;
_followBall = [CCActionFollow actionWithTarget:_ball worldBoundary:[_loadedLevel boundingBox]];
[_physicsNode runAction:_followBall];
}

How to build Physics Body using Different sprites in spritebuilder

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:
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

ccPhysicsCollisionPostSolve: method isn't called

I just started using the SpriteBuilder with Cocos2d-v3
For the exercise of the SpriteBuilder, I practice in the tutorial of the following WebSite
for the time being.
https://www.makegameswith.us/tutorials/getting-started-with-spritebuilder/collision-detection/
As a flow of the games of the tutorials,at first the catapult and the catapultArm are located on stage,the object(Penguin) which was attached to the arm flies forward when I pull the arm to the rear with a finger and separate a finger from a screen.
When the object(Penguin) hits other objects(is called Seal),output log,"Something collided with a seal!"
In a "Implementing a delegate method" of tutorial, I was going to try to display a letter,"Something collided with a seal!" in Consoll using CCLOG method.
In the Gameplay.m, I implemented ccPhysicsCollisionPostSolve:seal:wildcard method that is called to dispaly a letter "Something collide with a seal!",but this method isn't called when Penguin object hits other objects(seal).
I certainly made Penguin.ccbi and Seal.ccbi in SpriteBuilder,and thier ccbi file is Physics body.
Why ccPhysicsCollisionPostSolve:seal:wildcard method isn't called ?
It's my code that I really implemented as follows
This is Gameplay.m file
#import "Gameplay.h"
#implementation Gameplay{
CCPhysicsNode *_physicsNode;
//To joint betweent catapult and catapultArm
CCNode *_catapultArm;
CCNode *_catapult;
CCPhysicsJoint *_catapultJoint;
//Invisible Physics force
CCNode *_pullbackNode;
CCPhysicsJoint *_pullbackJoint;
//to move catapultArm
CCNode *_mouseJointNode;
CCPhysicsJoint *_mouseJoint;
//to fly penguin
CCNode *_currentPenguin;
CCPhysicsJoint *_penguinCatapultJoint;
//Object
CCNode *_levelNode;
//To Prevent a 'retry' button from moving with a fly penguin
CCNode *_contentNode;
}
//is called when CCB file has completed loading
-(void)didLoadFromCCB{
_physicsNode.collisionDelegate = self;
//tell this scene to accept touches
self.userInteractionEnabled = TRUE;
//loads the Levels/Leve1.ccb we have set up in SpriteBuilder
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 connectedPivoJointWithBodyA:_catapultArm.physicsBody
bodyB:_catapult.physicsBody
anchorA:_catapultArm.anchorPointInPoints];
//nothing shall collide with our invisible nodes
_pullbackNode.physicsBody.collisionMask = #[];
//nothing shall collide with our invisible nodes
_mouseJointNode.physicsBody.collisionMask = #[];
_pullbackJoint = [CCPhysicsJointconnectedSpringJointWithBodyA:_pullbackNode.physicsBody
bodyB:_catapultArm.physicsBody
anchorA:ccp(0,0)
anchorB:ccp(34,138)
restLength:60.f
stiffness:500.f
damping:40.f
];
}
//called on every touch in this scene (called every touch)
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CCLOG(#"touch Began");
CGPoint touchLcation = [touch locationInNode:_contentNode];
//start catapult dragging when a touch inside of the catapult arm occurs
if(CGRectContainsPoint([_catapultArm boundingBox], touchLcation))
{
//move the mouseJointNode to the touch position
_mouseJointNode.position = touchLcation;
_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 ccbFile
_currentPenguin = [CCBReader load:#"Penguin"];
CGPoint penguinPosition = [_catapultArm convertToWorldSpace:ccp(34, 138)];
_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 connectedPivoJointWithBodyA:_currentPenguin.physicsBody
bodyB:_catapultArm.physicsBody
anchorA:_currentPenguin.anchorPointInPoints
];
}
}
-(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event{
CCLOG(#"MOVING!!!!!!!!!!");
//whenever touches move,update the position of the mousejointNode to touch position
CGPoint touchLocation = [touch locationInNode:_contentNode];
_mouseJointNode.position = touchLocation;
}
-(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{
[self releaseCatapult];
}
//destroy our joint and let the catapult snap when a touch ends
-(void)releaseCatapult{
CCLOG(#"Release");
if(_mouseJoint != nil)
{
//releases the joint and lets the catapult snap back
[_mouseJoint invalidate];
_mouseJoint = nil;
//release the joint and lets the penguin fly
[_penguinCatapultJoint invalidate];
_penguinCatapultJoint = nil;
//after snapping rotation is fine
_currentPenguin.physicsBody.allowsRotation = TRUE;
//follow the flying penguin
CCActionFollow *follow =
}
}
-(void)retry
{
[[CCDirector sharedDirector]replaceScene:[CCBReader loadAsScene:#"Gameplay"]];
}
-(void)ccPhysicsCollisionPostSolve:(CCPhysicsCollisionPair *)pair seal:(CCNode *)nodeA
wildcard:(CCNode *)nodeB
{
CCLOG(#"Something collided with a seal!");
}
#end
Most likely you did not set a collision type for the Sealclass.
Double check that you have:
Set the custom class for the Seal in SpriteBuilder to Seal
Have set the collisionType within the didLoadFromCCB method inside the Seal class to "seal"
That should fix you issue.
Also, in Spritebuilder, make sure the seals already loaded in the level (Level1.ccb) have Collision type set to seal.

Collision detection between layers

I have a few layers, which holds CCSprites .
I have a main CCScene that is adding these layers at the start.
I have to check collision between sprites from different layers .
I know how to check a simple collision with CGRectContains , my problem is , that i need some kind of a class that holds all the sprites positions from all layers ,and to check each tick for collision.
Question: what is the right way to create such a class,that save/check sprites from all layers on the scene ?
THanks .
If you don't care about empty space, then you can just set self.contentSize for every layer. You can do it like this:
CGRect rect = CGRectNull;
for (CCNode *node in self.children) {
rect = CGRectUnion(rect, node.boundingBox);
}
self.contentSize = rect.size;
But if you care about empty space, then you need to use something like this:
// put it somewhere outside class implementation
static inline BOOL CCLayerIntersectsCCLayer(CCLayer l1, CCLayer l2) {
for (CCNode *n1 in l1.children) {
for (CCNode *n2 in l2.children) {
CGRect r1 = n1.boundingBox;
CGRect r2 = n2.boundingBox;
r1.origin = [l1.parent convertToNodeSpace:r1.origin];
r2.origin = [l2.parent convertToNodeSpace:r2.origin];
if (CGRectIntersectsCGRect(r1, r2)) {
return YES;
}
}
}
return NO;
}
But you must understand, that all sprites (even circles) are actually rectangles. So if you need very precise collision detection, then you should use box2d in your project. If you are interesting in this, here are some links to read:
Box2d
Intro to Box2D with Cocos2D 2.X Tutorial: Bouncing Balls
Box2D Tutorial for iOS: How To Use Box2D For Just Collision Detection with Cocos2D iPhone