How can we change the fade color in iCarousel? - icarousel

Suppose, I want to apply blue color to fade-in and fade-out image, how can i achieve this?

Fade in and fade out are controlled by the delegate method:
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value;
This method is used to customise the parameters of the standard carousel types. By implementing this method, you can tweak options such as:
iCarouselOptionFadeMin
iCarouselOptionFadeMax
iCarouselOptionFadeRange
These three options control the fading out of carousel item views based on their offset from the currently centered item. FadeMin is the minimum negative offset an item view can reach before it begins to fade. FadeMax is the maximum positive offset a view can reach before if begins to fade. FadeRange is the distance over which the fadeout occurs, measured in multiples of an item width (defaults to 1.0).
So for example fade out from 0.5f to 2.5f:
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value {
switch (option) {
case iCarouselOptionFadeMax:
return 0.5f;
break;
case iCarouselOptionFadeMin:
return -0.5f;
break;
case iCarouselOptionFadeRange:
return 2.5f;
break;
default:
return value;
break;
}
}
Now- to apply the blue color to fade-in and fade-out image you could subclass iCarousel. The following example assumes that as an image fades out (alpha approaches 0.0f), the blue color overlay fades in (alpha approaches 1.0f) using a cosine function.
#import "iCarousel.h"
// Done to suppress compiler warning to super
#interface iCarousel (BlueOverlay)
- (UIView *)containView:(UIView *)view;
- (void)transformItemView:(UIView *)view atIndex:(NSInteger)index;
- (CGFloat)alphaForItemWithOffset:(CGFloat)offset;
#end
#interface BlueCarousel : iCarousel
#end
#implementation BlueCarousel
- (UIView *)containView:(UIView *)view
{
//get container frame
UIView *containerView = [super containView:view];
CGRect frame = containerView.frame;
//create the blue overlay layer
UIView *overlayView = [[UIView alloc] initWithFrame:frame];
overlayView.backgroundColor = [UIColor blueColor];
overlayView.alpha = 0.0f;
[containerView addSubview:overlayView];
return containerView;
}
- (void)transformItemView:(UIView *)view atIndex:(NSInteger)index
{
[super transformItemView:view atIndex:index];
//calculate offset
CGFloat offset = [self offsetForItemAtIndex:index];
//update blue overlay alpha e.g. using cosine function
CGFloat alpha = cosf(M_PI_2*[self alphaForItemWithOffset:offset]);
[(UIView*)[view.superview.subviews lastObject] setAlpha:alpha];
}
#end

Related

cocos2d flappy bird demo

I am working with the flappy bird demo trying different things just to get to "know each other".
Going through the demo, I've managed to change the direction of the game to vertical scroll moving upwards.
Having reversed the CGFloat to negative values makes my obstacles move upward but once they are out of bounds they do not re-spawn.
If I change the values for a downward scroll they re-spawn as per the update method.
Can someone explain to me what I'm doing wrong with the x to y conversion? Why is the bottom recognized and the top of my screen not?
Thanks in advance
#import "MainScene.h"
static const CGFloat scrollSpeed = -280.f; //upwards
static const CGFloat firstObstaclePosition = -568.f;
static const CGFloat distanceBetweenObstacles = 80;
#implementation MainScene {
CCSprite *_hero;
CCPhysicsNode *_physicsNode;
NSMutableArray *_obstacles;
}
- (void)spawnNewObstacle {
CCNode *previousObstacle = [_obstacles lastObject];
CGFloat previousObstacleYPosition = previousObstacle.position.y;
if (!previousObstacle) {
// this is the first obstacle
previousObstacleYPosition = firstObstaclePosition;
}
CCNode *obstacle = [CCBReader load:#"Obstacle"];
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles);
[_physicsNode addChild:obstacle];
[_obstacles addObject:obstacle];
}
- (void)update:(CCTime)delta {
_hero.position = ccp(_hero.position.x, _hero.position.y + delta * scrollSpeed);//move on Y axis
_physicsNode.position = ccp(_physicsNode.position.x, _physicsNode.position.y - (scrollSpeed *delta));//scroll in Y axis
//spawn more
NSMutableArray *offScreenObstacles = nil;
for (CCNode *obstacle in _obstacles) {
CGPoint obstacleWorldPosition = [_physicsNode convertToWorldSpace:obstacle.position];
CGPoint obstacleScreenPosition = [self convertToNodeSpace:obstacleWorldPosition];
if (obstacleScreenPosition.y < -obstacle.contentSize.height) {
if (!offScreenObstacles) {
offScreenObstacles = [NSMutableArray array];
}
[offScreenObstacles addObject:obstacle];
}
}
for (CCNode *obstacleToRemove in offScreenObstacles) {
[obstacleToRemove removeFromParent];
[_obstacles removeObject:obstacleToRemove];
// for each removed obstacle, add a new one
[self spawnNewObstacle];
}
}
- (void)didLoadFromCCB {
self.userInteractionEnabled = TRUE;
_obstacles = [NSMutableArray array];
[self spawnNewObstacle];
[self spawnNewObstacle];
[self spawnNewObstacle];
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
}
#end
I've attached the _physicsNode screenshot from SB.
It looks like your obstacles will be spawning fine if they are a short, constant height, and the distance between them value is large enough. It may be better to incorporate the height of the obstacles to get a more meaningful value of the distance variable. Just a thought.
The line -
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles);
Could be -
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles + previousObstacle.contentSize.height);
As for the problem of the vertical scrolling working downwards and not upwards I believe it is due to this line:
if (obstacleScreenPosition.y < -obstacle.contentSize.height) {
Since this line is responsible for determining when an obstacle is off the screen it has an effect on the spawning of the next obstacle. It makes sense why this line works for downwards scrolling but needs to be changed for upwards scrolling.
Try:
if (obstacleScreenPosition.y > (_physicsNode.contentSize.height + obstacle.contentSize.height)) {
You may or may not need the size of the obstacle depending on where it is anchored.
I hope this works, Good luck.

Collision with sprite having another sprite as parent

Seems impossible but there has to be a solution.
I have the following classes:
#interface EnemiesEntities : CCSprite {
bool isFunctional;
CCSprite * laserBeam; // <----------- !!!!! That's where I want to check the collision.
CCSprite * leftRingEffect;
CCSprite * rightRingEffect;
}
#interface ShipEntity : CCSprite
{}
And I simply want to verify the collision between the ShipEntity and the laserBeam sprite (laserBeam is a member variable and child of EnemiesEntities class).
The method [laserBeam boundingBox] doesn't work as the boundingBox converts the coordinates relative to the parent node.
I tried thend adding to CCNode a method computing the boundingBox relative to the world but also this one did not work:
- (CGRect) worldBoundingBox
{
CGRect rect = CGRectMake(0, 0, contentSize_.width, contentSize_.height);
return CGRectApplyAffineTransform(rect, [self nodeToWorldTransform]);
}
I checked online and found only unuseful (to me) answers to the same question.
I then tried a different approach and tried to start from the boudningBox and change the position of the rectangle so obtained in respect to the parent position as following:
-(BOOL) collidesWithLaser:(CCSprite*)laserBeam
{
CGPoint newPosition = [laserBeam convertToWorldSpace:laserBeam.position];
[laserBeam worldBoundingBox];
CGRect laserBoundingBox = [laserBeam boundingBox];
CGRect laserBox = CGRectMake(laserBeam.parent.position.x, laserBeam.parent.position.y, laserBoundingBox.size.width, laserBoundingBox.size.height);
CGRect hitBox = [self hitBox];
if(CGRectIntersectsRect([self boundingBox], laserBox))
{
laserBeam.showCollisionBox=TRUE;
return TRUE;
}
else {
return FALSE;
}
}
Unfortunately this does work only when the rotation of the parent sprite is set to 0.0 but when it actually changes then it doesn't work (is probably because the boundingBox is relative to the parent node and not world).
I am a bit lost and was wondering if any of you had better luck in solving this problem and which solution (code snippets please :)) you used.
EDIT in Response to #LearnCocos2D answer:
I followed the suggestion and added the following code which doesn't work properly (e.g. try with an EnemiesEntities object is rotated to -130.0f).
-(BOOL) collidesWithLaser:(CCSprite*)laserBeam
{
CCLOG(#"rotation %f", laserBeam.rotation);
CGRect laserBoundingBox = [laserBeam boundingBox];
laserBoundingBox.origin = [self convertToWorldSpace:laserBeam.position];
CGRect shipBoundingBox = [self boundingBox]; //As we are in ShipEntity class
shipBoundingBox.origin = [self convertToWorldSpace:shipBoundingBox.origin];
//As this method is in the ShipEntity class there is no need to convert the origin to the world space. I added a breakpoint here and doing in this way the CGRect of both ShipEntity and gets misplaced.
if(CGRectIntersectsRect(shipBoundingBox, laserBoundingBox))
{
return TRUE;
}
else {
return FALSE;
}
}
The problem is in this line I think:
CGPoint newPosition = [laserBeam convertToWorldSpace:laserBeam.position];
laserBeam isn't in laserBeam's space but laserBeams parent space. So the correct is:
CGPoint newPosition = [[laserBeam parent] convertToWorldSpace:laserBeam.position];
The whole code
-(BOOL) collidesWithLaser:(CCSprite*)laserBeam
{
CGPoint newPosition = [laserBeam convertToWorldSpace:laserBeam.position];
CGRect laserBoundingBox = [laserBeam boundingBox];
laserBoundingBox.origin = newPosition;
CGRect hitBox = [self boundingBox];
hitbox.origin = [[self parent] convertToWorldSpace:hitbox.origin];
if(CGRectIntersectsRect(hitbox, laserBoundingBox))
{
laserBeam.showCollisionBox=TRUE;
return TRUE;
}
else {
return FALSE;
}
}
for both boundingboxes do:
bbox.origin = [self convertToWorldSpace:bbox.origin];
now you can compare the rects...
Update to update:
The boundingBox is an axis-aligned bounding box.
If the entity is rotated, the bounding box size increases to encompass all of the sprite's corners. Therefore collision (intersection) may be detected even relatively far away from the node when testing axis-aligned bounding boxes.
In ccConfig.h there's an option you can turn on to draw sprite bounding boxes, you should set this to 1 to see the bounding boxes: #define CC_SPRITE_DEBUG_DRAW 1
For oriented rectangles you need a different data structure and different intersection test, see for example this tutorial.

How to pinch/zoom on a cocos2d (Kobold2D) CCLayer

I have been trying to implement a standard pinch/zoom on a CCLayer in cocos2d (using the Kobold2D gesture recognisers) but with only partial success.
Below is my code which does make pinch/zoom work, so long as the pinch point doesn't move. However if I zoom in over one point on the layer and then lift off and move my fingers to zoom in further over another point, there is an instantaneous jump of the layer. It jumps to where the layer would have been if I'd been zooming in over the second point from the start, instead of simply zooming smoothly from where it was.
Can you see what I'm doing wrong or have I missed an existing simple pinch/zoom algorithm that does this job for CCLayers?
NB: I've left the default (YES) value for ignoreAnchorInPosition. Also, at the start self.scalePrePinch = 1.0f
-(void) update:(ccTime)delta
{
KKInput* input = [KKInput sharedInput];
if (input.gesturePinchBegan) {
CGSize scr = [[CCDirector sharedDirector] screenSize];
CGPoint pinchLocation = [self convertToNodeSpace:input.gesturePinchLocation];
CGPoint anchor = ccp(pinchLocation.x/scr.width, pinchLocation.y/scr.height);
CGFloat newScale = input.gesturePinchScale * self.scalePrePinch;
self.anchorPoint = ccp(self.anchorPoint.x + self.scale / newScale * (anchor.x - self.anchorPoint.x),
self.anchorPoint.y + self.scale / newScale * (anchor.y - self.anchorPoint.y));
self.scale = newScale;
}
else
self.scalePrePinch = self.scale;
}

How to change the particle angle in Cocos2D

Now I met a new question. How to modify every particle's angle to make it toward the center. Just like the images:
Image 1: normal particles effecing:
Image 2: which I need:
Image 2: which I need http://tinypic.com/images/404.gif
How about this code? You need to override CCParticleSystemQuad update: or updateQuadWithParticle:newPosition: method for specify the rotation of the particles. CCParticleSystemPoint can't rotate particles.
#interface MyParticleSystem : CCParticleSystemQuad
#end
#implementation MyParticleSystem
- (void)updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos
{
particle->rotation = ccpToAngle(particle->pos) * 180.0f / M_PI;
[super updateQuadWithParticle:particle newPosition:pos];
}
#end
In order to turn particles towards their direction of movement (in your case: towards the center), you can do the following:
Add the oldPos property to the particle tCCParticle struct in CCParticleSystem.h
Initialize the oldPos property with the initial particle position in initParticle: in CCParticleSystem.m
Update the oldPos property with the current particle position in update: in CCParticleSystem.m before the new position is computed. I do this in line 512 immediately after checking whether the particle is still alive.
Override CCParticleSystemQuad as suggested by Kazuki:
- (void)updateQuadWithParticle:(tCCParticle *)particle
newPosition:(CGPoint)pos
{
CGPoint direction = ccpSub(particle->pos, particle->oldPos);
CGPoint n = ccpNormalize(direction);
CGFloat a = -CC_RADIANS_TO_DEGREES(ccpToAngle(n) - M_PI_2);
particle->rotation = a;
[super updateQuadWithParticle:particle newPosition:pos];
}

Is object remain fixed when scrolling background in cocos2d

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);
}
}