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);
Related
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);
}
Im trying to make a scrolling affect in the background of my app
The sprite moves from north to south
This is successful but how can I repeat the sprite sprite to continuously do this? The sprite moves south and the end of the png file is seen, how could it be made that it repeats at this point so the sprite never ends? Thank you!
- (void) Buildings
{
rightBuilding = [CCSprite spriteWithImageNamed:#"rightBuilding.png"];
rightBuilding.positionType = CCPositionTypeNormalized;
rightBuilding.position = ccp(0.9f, 0.5f);
[self addChild:rightBuilding];
}
- (void) scrollBuildings:(CCTime)dt
{
rightBuilding.position = ccp(rightBuilding.position.x, rightBuilding.position.y - .5);
}
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
How To Have The Same Sprite In Multiple Locations Cocos2d Please Help
I have searched all over and cannot find answer
Just create multiple Sprites (CCSprite instances). They can all use the same texture (bitmap-file).
CCSprite * mySprite1;
CCSprite * mySprite2;
CCSprite * mySprite3;
// create several sprites from the same bitmap file
mySprite1 = [CCSprite spriteWithFile:#"spriteBitmap.png"];
mySprite2 = [CCSprite spriteWithFile:#"spriteBitmap.png"];
mySprite3 = [CCSprite spriteWithFile:#"spriteBitmap.png"];
mySprite1.position = ccp(100, 100);
mySprite2.position = ccp(200, 200);
mySprite3.position = ccp(300, 300);
You can not add the same CCSprite as a child to multiple CCNodes but you can make Cocos2D render the same CCSprite multiple times.
To achieve this you need to create a subclass of CCNode that will store the reference to your CCSprite and draw it in its -draw method applying required transformations.
For example
-(void)draw
{
[super draw];
CGPoint initialPosition = [_node position];
float initialScale = [_node scale];
[_node setScale:self.scale];
[_node setPosition:self.position];
[_node visit];
[_node setPosition:initialPosition];
[_node setScale:initialScale];
}
You may have to to use glScissor if you need picture-in-picture appearance.
Then you just need to addChild an instance of this class for every time you want an additional copy of your original CCSprite rendered.
Put a method on a for loop.
Inside the method create the CCSprite and modify it.
This is best suited for static sprites, since I don't know how you would access these outside of the method.
I have one question when infinite background scrolling is done, is the object remain fixed(like doodle in doodle jump, papy in papi jump) or these object really moves.Is only background move or both (background and object )move.plz someone help me.I am searching for this solution for 4/5 days,but can't get the solution.So plz someone help me. And if object does not move how to create such a illusion of object moving.
If you add the object to the same layer as the scrolling background, then it will scroll as the background scrolls.
If your looking for an effect like the hero in doodle jump, you may want to look at having two or more layers in a scene.
Layer 1: Scrolling Background Layer
Layer 2: Sprite layer
SomeScene.m
CCLayer *backgroundLayer = [[CCLayer alloc] init];
CCLayer *spriteLayer= [[CCLayer alloc] init];
[self addChild:backgroundLayer z:0];
[self addChild:spriteLayer z:1];
//Hero stays in one spot regardless of background scrolling.
CCSprite *squidHero = [[CCSprite alloc] initWithFile:#"squid.png"];
[spriteLayer addChild:squidHero];
If you want objects to scroll with the background add it to the background layer:
//Platform moves with background.
CCSprite *bouncePlatform= [[CCSprite alloc] initWithFile:#"bouncePlatform.png"];
[backgroundLayer addChild:bouncePlatform];
Another alternative is to use a CCFollow action. You would code as if the background is static (which it will be) and the player is moving (which it will be), but add a CCFollow action to the player. This essentially moves the camera so that it tracks your player.
You can also modify the classes so that you can get the CCFollow action to follow with an offset (i.e., so the player is not in the middle of the screen) as well as to have a smoothing effect to it, so that when the player moves, the follow action is not jerky. See the below code:
*NOTE I am using cocos2d-x, the c++ port. The methods are similar in cocos2d, and you should be able to modify these to fit the cocos2d syntax. Or search around -- I found these for cocos2d and then ported to c++.
//defines the action to constantly follow the player (in my case, "runner.p_sprite is the sprite pointing to the player)
FollowWithOffset* followAction = FollowWithOffset::create(runner.p_sprite, CCRectZero);
runAction(followAction);
And separately, I have copied the class definition for CCFollow to create my own class, CCFollowWithAction. This also has a smoothing effect (you can look this up more online) so that when the player moves, the actions are not jerky. I modified "initWithTarget," to take into account an offset, and "step," to add a smoothing action. You can see the modifications in the comments below.
bool FollowWithOffset::initWithTarget(CCNode *pFollowedNode, const CCRect& rect/* = CCRectZero*/)
{
CCAssert(pFollowedNode != NULL, "");
pFollowedNode->retain();
m_pobFollowedNode = pFollowedNode;
if (rect.equals(CCRectZero))
{
m_bBoundarySet = false;
}
else
{
m_bBoundarySet = true;
}
m_bBoundaryFullyCovered = false;
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_obFullScreenSize = CCPointMake(winSize.width, winSize.height);
//m_obHalfScreenSize = ccpMult(m_obFullScreenSize, 0.5f);
m_obHalfScreenSize = CCPointMake(m_obFullScreenSize.x/2 + RUNNER_FOLLOW_OFFSET_X,
m_obFullScreenSize.y/2 + RUNNER_FOLLOW_OFFSET_Y);
if (m_bBoundarySet)
{
m_fLeftBoundary = -((rect.origin.x+rect.size.width) - m_obFullScreenSize.x);
m_fRightBoundary = -rect.origin.x ;
m_fTopBoundary = -rect.origin.y;
m_fBottomBoundary = -((rect.origin.y+rect.size.height) - m_obFullScreenSize.y);
if(m_fRightBoundary < m_fLeftBoundary)
{
// screen width is larger than world's boundary width
//set both in the middle of the world
m_fRightBoundary = m_fLeftBoundary = (m_fLeftBoundary + m_fRightBoundary) / 2;
}
if(m_fTopBoundary < m_fBottomBoundary)
{
// screen width is larger than world's boundary width
//set both in the middle of the world
m_fTopBoundary = m_fBottomBoundary = (m_fTopBoundary + m_fBottomBoundary) / 2;
}
if( (m_fTopBoundary == m_fBottomBoundary) && (m_fLeftBoundary == m_fRightBoundary) )
{
m_bBoundaryFullyCovered = true;
}
}
return true;
}
void FollowWithOffset::step(float dt)
{
CC_UNUSED_PARAM(dt);
if(m_bBoundarySet){
// whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased
if(m_bBoundaryFullyCovered)
return;
CCPoint tempPos = ccpSub( m_obHalfScreenSize, m_pobFollowedNode->getPosition());
m_pTarget->setPosition(ccp(clampf(tempPos.x, m_fLeftBoundary, m_fRightBoundary),
clampf(tempPos.y, m_fBottomBoundary, m_fTopBoundary)));
}
else{
//custom written code to add in support for a smooth ccfollow action
CCPoint tempPos = ccpSub( m_obHalfScreenSize, m_pobFollowedNode->getPosition());
CCPoint moveVect = ccpMult(ccpSub(tempPos,m_pTarget->getPosition()),0.25); //0.25 is the smooth constant.
CCPoint newPos = ccpAdd(m_pTarget->getPosition(), moveVect);
m_pTarget->setPosition(newPos);
}
}