Zooming in and out of Scene in Cocos 2D-X 3.2 - c++

I'm pretty new to Cocos 2D-X but have some decent background in C++. I have a sprite _rocket (tied to a Box2D body) that occasionally moves outside the visible view of my screen. I'd like for the view to automatically zoom out as the sprite approaches the edge of the screen, so that the sprite is always in the view. When the sprite returns to the original view frame, the view should scale back to its original size.
I was able to zoom out with the following code in the update function:
Size winSize = Director::getInstance()->getWinSize();
if ((_rocket->getPosition().x - _rocket->getContentSize().width/2 < 10.0) ||
(_rocket->getPosition().x + _rocket->getContentSize().width/2 > winSize.width - 10.0) ||
(_rocket->getPosition().y - _rocket->getContentSize().width/2 < 10.0) ||
(_rocket->getPosition().y + _rocket->getContentSize().width/2 > winSize.height - 10.0))
{
this->setScale(this->getScale()-0.005);
}
However, because winSize isn't updated, this essentially scales forever, until the sprite returns to the original view. I am not sure how to update winSize so that it can be used iteratively to find the screen's edge. There may also be a much easier way of approaching this.

i don't understand why the winSize should change.
if you mean the _rock's contentsize not change
you should use
auto size = _rocket->getBoundingBox().size;

They removed some useful camera functions in cocos2d-x 3.+
The workaround is to scale/move the layer containing the game instead of trying to move the camera.

Related

Cocos2d-x Sprite flickers during scale animation sequence

I have a grow / shrink animation sequence. But for some reason the sprite does not scale smoothly. I did change the animation interval and disabled depth test but it did not fix this.
What can be the reason behind this?
Does does have something to do with art asset that is used?
ScaleTo* grow = ScaleTo::create(1, 1.5);
ScaleTo* shrink = ScaleTo::create(1, 1);
Sequence* anim = Sequence::create(grow, shrink , NULL);
RepeatForever *rep = RepeatForever::create(anim);
station_image->runAction(rep);
Solved
I was able to fix this issue by enabling ‘CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL’ in ccConfig.h

CCParallaxNode adding childs while scrolling

I'am using a CCParallaxNode to scroll 3 backgrounds along with Ray Wenderlich's category to move the backgrounds when they go out of the screen.
It is working just fine, my problem is that i want to add childs (enimies) on the fly, like every 5 seconds. Normally i would just add the enemies to the parent layer using a CCMoveTo action to animate him over the screen but I want my enimies to follow the foreground of the parallax layer.
I'am increasing the scroll speed slowly as the game progresses.
I can't seem to figure out the right offset when calling
CGFloat offset = self.gameBackground.position.x;
[self.gameBackground addChild:enimy z:5 parallaxRatio:ccp(0.1, 0.1) positionOffset:ccp(offset, 85)];
Can someone help me out with this?
edit:
I'am doing this to move the background:
- (void)update:(ccTime)delta
{
self.speed -= 0.5f;
CGPoint backgroundScrollVel = ccp(self.speed, 0);
self.gameBackground.position = ccpAdd(self.gameBackground.position, ccpMult(backgroundScrollVel, delta));
}
Thanks
Rays article: http://www.raywenderlich.com/3611/how-to-make-a-space-shooter-iphone-game
Final solution:
I ended up just adding the enimies to the CCLayer instead of the Parallax. To move the enimies in the same speed as the foremost layer child in Parallax i did the following:
in update:(ccTime)delta:
CGFloat parallaxRatio = 0.1f;
CGPoint backgroundScrollVel = ccp((self.backgroundSpeed * - 1) * parallaxRatio, 0);
for(WKEnimy *enemy in self.enimies)
{
enemy.position = ccpAdd(enemy.position, ccpMult(backgroundScrollVel, delta));
}
You could add your enemy CCSprites to your foreground CCLayer (instead of directly adding them to your CCParallaxNode). Besides, I wouldn't recommend using actions (such as CCMoveTo) for this particular case; you may update your sprites positions as your doing with your gameBackground, and 'manually' check wether or not they're off the screen.

Cocos2d iPhone. Scrollayer contentSize. Layers

I want to set the contentsize of scrollayer.
I have a scrollayer, it's CCLayer type and moving is set by ccTouchMove. I have one schedule for smoothing. BUT.
Problem is that scrolling layer is big like the whole display. I want to set the contentsize of scrollayer. Content in this layer will be scroll and showing ONLY in this layer. Not taking up the whole display. Something like this
Scrolling just in gray CCLayer (scrollayer) ....NOT WHOLE SCREEN.
Can you help me?
P.S.: Setting CCLayerColor and initWithColor:Width:Height: is not working. It just makes some stupid color box and it's moving too.
ok, honestly i would put the window frame at a higher z than the scrolling object ... if you dont you may have to crop and change sprite on the fly for the window content, nasty (at least that is the one way i could do this, without further research).
so :
// initialize this logic somewhere useful
CCNode scrollableContent;
CCSprite windowFrame;
BOOL isScrollPossible;
[self addChild:scrollableContent z:0];
[self addChild:windowFrame z:1];
// and in the touch delegate methods
-(void) ccTouchBegan:{
check if the touch happened in the window, if yes, scrolling is possible
}
-(void) ccTouchMoved:{
if (isScrollPossible) {
compute displacement
compute nextPosition for scrollableContent node;
if ( nextPosition in window ) {
// make scrollableContent follow touch
scrollableContent.position=nextPosition;
} else {
// stop any further scrolling until the next 'touch began'
isScrollPossible=NO;
}
} else {
// scroll not possible, do nothing
}
}
This is the basic idea. You may need clamping logic to prevent the creeping of scrollableContent beyond the edges of the window.
Edited for typos.
After trying desperately with masking and GL_SCISSOR, I settled on cutting a hole in the foreground and only moving the background object when onTouchMoved updated.
To see it in action, have a look at the Stats page of Angry Gran.

screen size in cocos2d

i would like to change the screen size so that sprites will disappear before they reach the real screen edges.
BUT i still want my background to stay on all of the screen size.
Imagine a paper on my screen so i want to game to exist only on that paper, and around that paper there still will be some background.
so, how do i set my CCSprites to move in and out from that paper and slowly disappear when coming to its edges ?
my sprites are moves with : (i need to put some code to get published cause site "standard" )
id moveclouds1 = [CCMoveTo actionWithDuration:30 position:ccp(420,380)];
thanks.
you can use glscissor for that
simply subclass a CCLayer to make your "paper screen". Then add you sprites inside this layer.
on this layer override the visit method
- (void) visit
{
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(x,y, width, height); //here put the position and the size of the paper/screen
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
a sprite reaching the border of the paper/screen will be scissored off.
REMEMBER: glScissor will use PIXEL values not points, so it`s your job to use double values for retina display ( CC_CONTENT_SCALE_FACTOR() can come in handy )

Animate Sprite From Tile Map

I would like to animate a sprite at a specific location on an isometric tilemap. I can animate a sprite on a given layer, but not when its a sprite from a tilemap. For example the following works just fine:
// make a frame cache
CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"spellanim.plist" textureFile:#"spellanim.pvr.ccz"];
// create a sprite
CCSprite *effectSprite = [CCSprite spriteWithSpriteFrameName:#"spell_strength__33.png"];
// set sprite at center of screen
CGSize screenSize = [[CCDirector sharedDirector] winSize];
effectSprite.position = CGPointMake(screenSize.width / 2, screenSize.height / 2);
// create animation using an animation helper (since animationWithName:delay:frames: will be deprecated)
CCAnimation *animation = [CCAnimation animationWithFrame:#"spell_strength__" frameCount:13 delay:0.3f startAt:33];
CCAnimate *animate = [CCAnimate actionWithAnimation:animation];
// run animation on sprite
[effectSprite runAction:animate];
// add sprite as a child of the layer
[self addChild:effectSprite];
Now the following does not work, I assume it has to do with how tile maps work (I get an assertion failure in CCSprite setTexture:):
// add one to x to offset the spell animation from the player
CGPoint tileCoord = CGPointMake(player.entityTileCoordinate.x + 1, player.entityTileCoordinate.y);
// get the effects layer from the tile map
CCTMXTiledMap *tileMap = (CCTMXTiledMap *)[[TileMapLayer sharedTileMapLayer] getChildByTag:TileMapNode];
CCTMXLayer *effectsLayer = [tileMap layerNamed:#"Effects"];
// get a sprite from the effects layer
CCSprite *effectSprite = [effectsLayer tileAt:CGPointMake(0, 0)];
// move the sprite to the desired location (this works just fine)
CGPoint pointPixel = [effectsLayer positionAt:tileCoord];
[effectSprite runAction:[CCMoveTo actionWithDuration:0.0f position:pointPixel]];
// now animate the sprite
CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"spellanim.plist" textureFile:#"spellanim.pvr.ccz"];
CCAnimation *animation = [CCAnimation animationWithFrame:#"spell_strength__" frameCount:13 delay:0.3f startAt:33];
CCAnimate *animate = [CCAnimate actionWithAnimation:animation];
[effectSprite runAction:animate];
My guess it is because the animation sprites aren't a part of the tile set for that layer of the tile map. Is there a way to dynamically add these animation sprites to some cache used to draw on that layer (basically modify the tile set at runtime)? Can I later then remove these sprites from that modified tile set? Is there still a 1024x1024 limitation when you modify a tileset at runtime?
At the end of the day I really want to be able to have an animated sprite move from one tile to another on the tile map but I'm just not sure how to do that in the most efficient way. It seems really clunky to have an effects layer on the tile map and a tile set with all spell animations (especially if you can't fit them in 1024x1024) as assembling an animation would be chaining together tile GID updates as the effect moves across the tile map.
I know I can do what I want when the layer isn't a part of a tilemap - I can animate and move a sprite using screen coordinates, but when what I know are tile coordinates, translating those to screen coordinates (if the tile is even visible on the screen) has evaded my understanding so far. How do you determine what tiles the screen can actually 'see'? What then is the pixel coordinate on the screen of a visible tile?
I appreciate any thoughts on how to go about this process.
what you guess is the real cuase of the problem, tile maps are created using spritebatchnode. spritebatchnode is just like a layer with higher performance that you can only add sprites to it but there is a single restriction all the sprites in a spritebatchnode must share their textures. so when you are trying to change a tile to show an animation you are trying to draw something from diffrent texture alongside other tiles (which have default tile texture) and it causes crashes or malfunctioning. i didn't test it myself but i think if you try putting all your frames in a same texture you put other tiles, the problem would be solved.