Parallax scrolling on iPhone 4 and 5 screens - cocos2d-iphone

I am trying to implement landscape parallax scrolling which works both on iPhone 4 and the new iPhone 5. I started with a sprite which is 1136px in width (HD) and thought that I could use the same for the iPhone 4 as well. The problem is that it won't work on iPhone 4 anymore. If you're using an iPhone 5, screensize and sprite size are the same. Not so on the iPhone 4 which will result in awkward replacing of the sprite after you reached 1136px sidewards motion (i.e. the length of the sprite/iPhone 5's screen).
How can I implement endless parallax scrolling independent of the screen size / sprite size ratios?
Here is the code which updates the sprites so that they go ad infinitum (based on the code of the new Cocos2D 2 book by Itterheim):
for (CCSprite* sprite in spriteBatch.children)
{
NSNumber* factor = [speedFactors objectAtIndex:sprite.zOrder];
CGPoint pos = sprite.position;
pos.x -= (scrollSpeed * factor.floatValue) * (delta * 50);
// Reposition stripes when they're out of bounds
CGSize screenSize = [CCDirector sharedDirector].winSize;
if (pos.x < -screenSize.width)
{
pos.x += (screenSize.width * 2) - 2;
}
sprite.position = pos;
}
Here is its context:
#implementation ParallaxBackground
-(id) init
{
if ((self = [super init]))
{
CGSize screenSize = [[CCDirector sharedDirector] winSize];
// Get the game's texture atlas texture by adding it. Since it's added already it will simply return
// the CCTexture2D associated with the texture atlas.
CCTexture2D* gameArtTexture = [[CCTextureCache sharedTextureCache] addImage:#"game-art.pvr.ccz"];
// Create the background spritebatch
spriteBatch = [CCSpriteBatchNode batchNodeWithTexture:gameArtTexture];
[self addChild:spriteBatch];
bgLayerTotal = 3;
// Add the 6 different layer objects and position them on the screen
for (int i = 0; i < bgLayerTotal; i++)
{
NSString* frameName = [NSString stringWithFormat:#"bg%i.png", i];
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(0, screenSize.height / 2);
[spriteBatch addChild:sprite z:i];
}
// Add 7 more stripes, flip them and position them next to their neighbor stripe
for (int i = 0; i < bgLayerTotal; i++)
{
NSString* frameName = [NSString stringWithFormat:#"bg%i.png", i];
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:frameName];
// Position the new sprite one screen width to the right
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(screenSize.width - 1, screenSize.height / 2);
// Flip the sprite so that it aligns perfectly with its neighbor
sprite.flipX = YES;
// Add the sprite using the same tag offset by numStripes
[spriteBatch addChild:sprite z:i tag:i + bgLayerTotal];
}
// Initialize the array that contains the scroll factors for individual stripes.
speedFactors = [NSMutableArray arrayWithCapacity:bgLayerTotal];
[speedFactors addObject:[NSNumber numberWithFloat:0.1f]];
[speedFactors addObject:[NSNumber numberWithFloat:3.0f]];
[speedFactors addObject:[NSNumber numberWithFloat:4.0f]];
NSAssert(speedFactors.count == (unsigned int)bgLayerTotal, #"speedFactors count does not match bgLayerTotal!");
scrollSpeed = 1.0f;
[self scheduleUpdate];
}
return self;
}
-(void) update:(ccTime)delta
{
for (CCSprite* sprite in spriteBatch.children)
{
NSNumber* factor = [speedFactors objectAtIndex:sprite.zOrder];
CGPoint pos = sprite.position;
pos.x -= (scrollSpeed * factor.floatValue) * (delta * 50);
// Reposition stripes when they're out of bounds
CGSize screenSize = [CCDirector sharedDirector].winSize;
if (pos.x < -screenSize.width)
{
pos.x += (screenSize.width * 2) - 2;
}
sprite.position = pos;
}
}

Rather than using the screensize to repeat the background, just use the width of the largest background sprite (or the sum of the widths of the bg pieces, if they are broken up). You could also just hard-code the max width to 1136.
So, change:
CGSize screenSize = [CCDirector sharedDirector].winSize;
if (pos.x < -screenSize.width)
{
pos.x += (screenSize.width * 2) - 2;
}
To something like:
CCSprite *bg = (CCSprite*)[spriteBatch getChildByTag:0];
if (pos.x < -bg.contentSize.width)
{
pos.x += (bg.contentSize.width * 2) - 2;
}

Related

cocos2d sprite tag not being set

I'm using the following to create sprites with b2bodys
but I cant get the sprites tag to set. why isn't [sprite setTag:3]; working?
When I detect a collision with one of these sprites it says the sprite tag is 0
-(void) addNewSpriteAtPosition:(CGPoint)p
{
// CCLOG(#"Add sprite %0.2f x %02.f",p.x,p.y);
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 2;
fixtureDef.friction = 0.2f;
body->CreateFixture(&fixtureDef);
CCNode *parent = [self getChildByTag:kTagParentNode];
//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is
//just randomly picking one of the images
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
CCPhysicsSprite *sprite = [CCPhysicsSprite spriteWithTexture:spriteTexture_ rect:CGRectMake(32 * idx,32 * idy,32,32)];
[parent addChild:sprite];
[sprite setPTMRatio:PTM_RATIO];
[sprite setB2Body:body];
[sprite setPosition: ccp( p.x, p.y)];
[sprite setTag:3];
}

How to make stretch body(trigger) and apply physics on it in box2d in iphone?

I want to make trigger so that user can stretch the trigger and give the direction and then trigger hit to the ball and the ball will go accordingly.
The Ball speed and direction will depend on the trigger.
I am new in box2d.
Please check the link what I want.
http://dc694.4shared.com/img/Nw7YYLNL/s7/pool.png?async&0.2852371991612017
-(id) init
{
if( (self=[super init])) {
CGSize winSize = [CCDirector sharedDirector].winSize;
// Create a world
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
_world = new b2World(gravity);
// Create sprite and add it to the layer
CCSprite *Trigger = [CCSprite spriteWithFile:#"Trigger.png"];
Trigger.position = ccp(10, 50);
Trigger.tag = 1;
[self addChild:Trigger];
// Create Trigger body
b2BodyDef TriggerBodyDef;
TriggerBodyDef.type = b2_dynamicBody;
TriggerBodyDef.position.Set(127/PTM_RATIO, 210/PTM_RATIO);
TriggerBodyDef.userData = ball;
TriggerBody = _world->CreateBody(&TriggerBodyDef); // b2Body * ballBody
// Create circle shape
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
// Create shape definition and add to body
b2FixtureDef TriggerShapeDef;
TriggerShapeDef.shape = &circle;
TriggerShapeDef.density = 15.0f;
TriggerShapeDef.friction = 2.f;
TriggerShapeDef.restitution = 0.0f;
_TriggerFixture = TriggerBody->CreateFixture(&TriggerShapeDef);
b2Vec2 force = b2Vec2(10, -12);
TriggerBody->ApplyLinearImpulse(force, TriggerBodyDef.position);
///////////////////////// Ball ///////////////////////////////
// Create sprite and add it to the layer
CCSprite *ball = [CCSprite spriteWithFile:#"ball.png"];
ball.position = ccp(100, 200);
ball.tag = 1;
[self addChild:ball];
// Create ball body
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(127/PTM_RATIO, 210/PTM_RATIO);
ballBodyDef.userData = ball;
ballBody = _world->CreateBody(&ballBodyDef); // b2Body * ballBody
// Create circle shape
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 15.0f;
ballShapeDef.friction = 2.f;
ballShapeDef.restitution = 0.0f;
_ballFixture = ballBody->CreateFixture(&ballShapeDef);
b2Vec2 force = b2Vec2(73, -52);
ballBody->ApplyLinearImpulse(force, ballBodyDef.position);
//ballBody->SetLinearVelocity(b2Vec2(10,0)); // try
// ballBody->SetAngularVelocity(0); // try
///////////////////////// Ball ///////////////////////////////
// Create paddle and add it to the layer
CCSprite *paddle = [CCSprite spriteWithFile:#"paddle.png"];
paddle.position = ccp(winSize.width/2, 50);
[self addChild:paddle];
// Create paddle body
b2BodyDef paddleBodyDef;
paddleBodyDef.type = b2_staticBody; //b2_staticBody, b2_dynamicBody
paddleBodyDef.position.Set(winSize.width/2/PTM_RATIO, 50/PTM_RATIO);
paddleBodyDef.userData = paddle;
paddleBodyDef.angle = 75;
_paddleBody = _world->CreateBody(&paddleBodyDef);
// Create paddle shape
b2PolygonShape paddleShape;
paddleShape.SetAsBox(paddle.contentSize.width/PTM_RATIO/2, paddle.contentSize.height/ PTM_RATIO/2);
// Create shape definition and add to body
b2FixtureDef paddleShapeDef;
paddleShapeDef.shape = &paddleShape;
paddleShapeDef.density = 25.0f;
paddleShapeDef.friction = 1.1f;
paddleShapeDef.restitution = 0.1f;
_paddleFixture = _paddleBody->CreateFixture(&paddleShapeDef);
// Restrict paddle along the x axis
b2PrismaticJointDef jointDef;
b2Vec2 worldAxis(0.0f, 0.0f);
jointDef.collideConnected = true;
jointDef.Initialize(_paddleBody, _groundBody, _paddleBody->GetWorldCenter(), worldAxis);
_world->CreateJoint(&jointDef);
[self schedule:#selector(tick:)];
self.touchEnabled = YES;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (_mouseJoint != NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
if (_paddleFixture->TestPoint(locationWorld)) {
b2MouseJointDef md;
md.bodyA = _groundBody;
md.bodyB = _paddleBody;
md.target = locationWorld;
md.collideConnected = true;
md.maxForce = 1000.0f * _paddleBody->GetMass();
_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md);
_paddleBody->SetAwake(true);
}
// [self kick];
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (_mouseJoint == NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
_mouseJoint->SetTarget(locationWorld);
}
I am not able to make trigger and not able to apply physics on trigger image. How to apply physics on trigger body? And how the ballbody will move according to trigger?
I have implemented this as follow:
HelloWorldLayer.h
#import "cocos2d.h"
#import "Box2D.h"
#define PTM_RATIO 32.0
#interface HelloWorldLayer : CCLayer {
b2World *_world;
b2Body *_body;
CCSprite *_ball;
CGPoint firstlocation;
CGPoint lastlocation;
b2Vec2 pre_velocity;
}
+ (id) scene;
- (void)kick;
#end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
#implementation HelloWorldLayer
+ (id)scene {
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild:layer];
return scene;
}
- (id)init {
if ((self=[super init])) {
CGSize winSize = [CCDirector sharedDirector].winSize;
_ball = [CCSprite spriteWithFile:#"ball.png" rect:CGRectMake(0, 0, 52, 52)];
_ball.position = ccp(100, 100);
[self addChild:_ball];
//create world
b2Vec2 gravity = b2Vec2(0.0f, -8.0f);
_world = new b2World(gravity);
// Create ball body and shape
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(26/PTM_RATIO, 26/PTM_RATIO);
ballBodyDef.userData = _ball;
_body = _world->CreateBody(&ballBodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 1.0f;
ballShapeDef.friction = 0.2f;
ballShapeDef.restitution = 0.8f;
_body->CreateFixture(&ballShapeDef);
//ground edge
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
b2Body *groundBody = _world->CreateBody(&groundBodyDef);
b2EdgeShape groundEdge;
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &groundEdge;
//wall definitions
groundEdge.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(0,0), b2Vec2(0,winSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(0, winSize.height/PTM_RATIO),
b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO),
b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
[self schedule:#selector(tick:)];
// [self schedule:#selector(kick) interval:3.0];
self.isTouchEnabled = YES;
self.isAccelerometerEnabled = YES;
}
return self;
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
b2Vec2 gravity(acceleration.y * 30, -acceleration.x * 30);
_world->SetGravity(gravity);
}
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 1);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *ballData = (CCSprite *)b->GetUserData();
ballData.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
- (void)kick {
b2Vec2 force = b2Vec2(-30, 30);
_body->ApplyLinearImpulse(force,_body->GetPosition());
}
- (void)ccTouchesBegan:(NSSet *)touch withEvent:(UIEvent *)event {
/* b2Vec2 force = b2Vec2(-30, -30);
_body->ApplyLinearImpulse(force, _body->GetPosition());*/
UITouch *touchpoint = [touch anyObject];
firstlocation = [touchpoint locationInView:[touchpoint view]];
firstlocation = [[CCDirector sharedDirector] convertToGL:firstlocation];
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touchpoint = [touches anyObject];
lastlocation = [touchpoint locationInView:[touchpoint view]];
lastlocation = [[CCDirector sharedDirector] convertToGL:lastlocation];
//NSLog(#"start location %2f %2f",firstlocation.x,firstlocation.y);
//NSLog(#"last location %2f %2f",lastlocation.x,lastlocation.y);
GLfloat y = firstlocation.y - lastlocation.y;
GLfloat x = firstlocation.x - lastlocation.x;
GLfloat lengthOfFlick = sqrt(x*x + y*y);
NSLog(#"%2f",lengthOfFlick);
/* GLfloat basAngle = atan2(-x, -y);
GLfloat radians = (basAngle + (180/3.14));
//GLfloat angle = 180 + radians;*/
//GLfloat theta = atan2(y,x)* 180 / 3.14;
//NSLog(#"theta: %2f",theta);
float ratio = lengthOfFlick/90;
NSLog(#"%f",ratio);
if(ratio > 1){
ratio = 1;
}
NSLog(#"%f",ratio);
if(firstlocation.x > lastlocation.x){
if(firstlocation.y > lastlocation.y){
b2Vec2 force = b2Vec2((int)(45 * ratio),(int)(45 * ratio));
_body->ApplyLinearImpulse(force, _body->GetPosition());
}else{
b2Vec2 force = b2Vec2((int)( -1 * 45 * ratio), (int)(45 * ratio));
_body->ApplyLinearImpulse(force, _body->GetPosition());
}
}else{
if(firstlocation.y > lastlocation.y){
b2Vec2 force = b2Vec2((int)( -1 * 45 * ratio),(int)(45 * ratio));
_body->ApplyLinearImpulse(force, _body->GetPosition());
}else{
b2Vec2 force = b2Vec2((int)(-1* 45 * ratio),(int)(-1 * 45 * ratio));
_body->ApplyLinearImpulse(force, _body->GetPosition());
}
}
}
-(void)dealloc{
delete _world;
_body = NULL;
_world = NULL;
[super dealloc];
}
#end
Or you can download this code from:4shared.com/zip/PRv8c1Pz/BOX2D.html

Making sprite bounce in an angle in box2d

In the game I'm trying to make, I have a ball sprite which bounces thanks to box2d. Here's how my current code looks:
-(id)init
{
ball = [CCSprite spriteWithFile:#"ball.png"];
ball.position = ccp(150, winSize.height * 0.78);
[self addChild:ball];
ball.tag = 2;
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(150/PTM_RATIO, 450/PTM_RATIO);
ballBodyDef.userData = ball;
_body = _world->CreateBody(&ballBodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 0.5f;
ballShapeDef.friction = 1.0f;
ballShapeDef.restitution = 1.0f;
_ballFixture = _body->CreateFixture(&ballShapeDef);
b2Vec2 force = b2Vec2(160, 375);
_body->ApplyLinearImpulse(force, ballBodyDef.position);}
- (void)update:(ccTime) dt {
if(_isPaused == FALSE)
{
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if(sprite.tag == 2)
{
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}}
Bouncing itself works fine, my problem is there are instances wherein the ball would bounce on a straight line so to speak, either vertically or horizontally continuously which I am trying to avoid. So my question is, how can I make my ball sprite bounce at an angle instead of a straight line so it wouldn't get stuck bouncing infinitely in the same direction?
You could apply a tiny force or gravity change to the body or the world, "randomly" or at equal intervals.

moving CCRendertexture

I'm new in cocos2d and I'm working in a coloring app, I'm Using CCRenderTexture for drawing:
target = [[CCRenderTexture alloc] initWithWidth:size.width height:size.height pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[target setPosition:ccp(size.width/2, size.height/2)];
[target clear:255 g:255 b:255 a:1];
[self addChild:target];
but I need to move the position of the drawing area (CCRenderTexture) a little up to show a submenu that hides in the bottom of the screen, so im using CCMove:
[CCMoveTo actionWithDuration:0.2 position:ccp(self.position.x, self.position.y+menuOffset)]
the rendertexture moves up as expected, but the "touchable area" stays in the same place, so when im touching the submenu area(outside the rendertexture frame) im still drawing inside the rendertexture.
this is the method for drawing
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint start = [touch locationInView: [touch view]];
start = [[CCDirector sharedDirector] convertToGL: start];
CGPoint end = [touch previousLocationInView:[touch view]];
end = [[CCDirector sharedDirector] convertToGL:end];
// begin drawing to the render texture
[target begin];
// scale/rotation/offset
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[brush setRotation:rand()%360];
[brush setScale:drawratio];
[brush setColor:brush.color];
[brush visit];
}
}
[target end];
}
so, how can I change the position of CCRendertexture in a proper way?
Thanks in advance.
You just need to convert the GL coordinates to your target object's node space
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint start = [touch locationInView: [touch view]];
start = [[CCDirector sharedDirector] convertToGL: start];
start = [target convertToNodeSpace: start];
CGPoint end = [touch previousLocationInView:[touch view]];
end = [[CCDirector sharedDirector] convertToGL:end];
end = [target convertToNodeSpace: end];
// begin drawing to the render texture
[target begin];
// scale/rotation/offset
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[brush setRotation:rand()%360];
[brush setScale:drawratio];
[brush setColor:brush.color];
[brush visit];
}
}
[target end];
}

Does cocos2d support scaled position of ccsprite?

This is a diagram of question.
Below diagram is sprites of cocos2d.
I want to get a position of yellow sprite when green sprite scaled from 1.0 to 0.5 ratio.
I want to know if cocos2d support scaled position.
this is some code.
CCSprite *green = [CCSprite spriteWithFile:#"green.png"];
CCSprite *yellow = [CCSprite spriteWithFile:#"yellow.png"];
green.anchorPoint = CGPointZero;
yellow.anchorPoint = CGPointZero;
green.position = CGPointMake(0, 0);
yellow.position = CGPointMake(100, 100);
[green addChild:yellow];
[self addChild:green];
green.scale = 0.5;
CGPoint scaled = yellow.scaledposition(?) <=== How to get?
Try this:
CGPoint scaled = ccp(yellow.postion.x * green.scale, yellow.position.y * green.scale);