vertices smaller than sprite when rendered on iPhone screen - cocos2d-iphone

I am using vertex helper to get the edges of my sprites. I am using Cocos2d + Box2d on the iPhone. The problem I am getting is that the debug draw on the device I am testing on comes up but the vertices rendered or shown is smaller than my sprites even after tracing the edges of the sprites carefully and using the same sprite.
OK here is a screen shot of the problem!
The green triangle is supposed to fit with the edges of the sprite. Also this is the code I used:
This is the GLESDebugDraw code
- (void)setupDebugDraw {
debugDraw = new GLESDebugDraw(PTM_RATIO* [[CCDirector sharedDirector]
contentScaleFactor]);
world->SetDebugDraw(debugDraw);
debugDraw->SetFlags(b2DebugDraw::e_shapeBit);
}
#import "Box2DSprite.h"
#interface Stalag :Box2DSprite {
b2World *world;
}
- (id)initWithWorld:(b2World *)world atLocation:(CGPoint)location;
#end
#import "Stalag.h"
#implementation Stalag
- (void)createBodyAtLocation:(CGPoint)location {
b2BodyDef bodyDef;
bodyDef.type = b2_staticBody;
bodyDef.position = b2Vec2(location.x/PTM_RATIO,
location.y/PTM_RATIO);
self.body = world->CreateBody(&bodyDef);
body->SetUserData(self);
b2PolygonShape shape;
int num = 8;
b2Vec2 verts[] = {
b2Vec2(36.8f / 100.0, -79.2f / 100.0),
b2Vec2(10.3f / 100.0, 33.2f / 100.0),
b2Vec2(1.8f / 100.0, 80.6f / 100.0),
b2Vec2(-4.6f / 100.0, 84.5f / 100.0),
b2Vec2(-8.5f / 100.0, 80.3f / 100.0),
b2Vec2(-22.6f / 100.0, 19.4f / 100.0),
b2Vec2(-31.8f / 100.0, -45.6f / 100.0),
b2Vec2(-37.5f / 100.0, -75.7f / 100.0)
};
shape.Set(verts, num);
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape;
fixtureDef.density = 1000.0;
body->CreateFixture(&fixtureDef);
}
- (id)initWithWorld:(b2World *)theWorld atLocation:(CGPoint)location {
if ((self = [super init])) {
world = theWorld;
[self setDisplayFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache] spriteFrameByName:#"hill.png"]];
gameObjectType = kStalagupType;
[self createBodyAtLocation:location];
}
return self;
}
#end
Please can anyone tell me what do I do and what I am doing wrong?
Thanks

When specifying vertices coordinates you are dividing it by a "magic number" 100. Actually it is your PixelToMetersRatio (PTM_RATIO in cocos examples). Also you are using box2d debug draw. And when creating debug draw class your must pass PTM_RATIO in it's constructor. I think you are passing another number there (not 100). Does it solve the problem ?

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

Rotated Clipping Node in Cocos2d

I'm using the clipping node here: http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode
ClippingNode.h
#import "cocos2d.h"
#interface ClippingNode : CCNode {
CGRect clippingRegionInNodeCoordinates;
CGRect clippingRegion;
}
#property (nonatomic) CGRect clippingRegion;
#end
ClippingNode.m
#import "ClippingNode.h"
#interface ClippingNode (PrivateMethods)
-(void) deviceOrientationChanged:(NSNotification*)notification;
#end
#implementation ClippingNode
-(CGRect) clippingRegion {
return clippingRegionInNodeCoordinates;
}
-(void) setClippingRegion:(CGRect)region {
// keep the original region coordinates in case the user wants them back unchanged
clippingRegionInNodeCoordinates = region;
self.position = clippingRegionInNodeCoordinates.origin;
self.contentSize = clippingRegionInNodeCoordinates.size;
// convert to retina coordinates if needed
region = CC_RECT_POINTS_TO_PIXELS(region);
// respect scaling
clippingRegion = CGRectMake(region.origin.x * scaleX_, region.origin.y * scaleY_,
region.size.width * scaleX_, region.size.height * scaleY_);
}
-(void) setScale:(float)newScale {
[super setScale:newScale];
// re-adjust the clipping region according to the current scale factor
[self setClippingRegion:clippingRegionInNodeCoordinates];
}
-(void) deviceOrientationChanged:(NSNotification*)notification {
// re-adjust the clipping region according to the current orientation
[self setClippingRegion:clippingRegionInNodeCoordinates];
}
-(void) visit {
glEnable(GL_SCISSOR_TEST);
CGPoint worldPosition = [self convertToWorldSpace:CGPointZero];
const CGFloat s = [[CCDirector sharedDirector] contentScaleFactor];
glScissor((clippingRegion.origin.x) + (worldPosition.x*s), (clippingRegion.origin.y) + (worldPosition.y*s),
(clippingRegion.size.width), (clippingRegion.size.height));
[super visit];
glDisable(GL_SCISSOR_TEST);
}
#end
However, I need to clip a rotated CCNode. Any idea on how I could accomplish such a task?
Replace the visit method in the class ClippingNode by this
-(void) visit
{
float rotationAngle = 15;
glPushMatrix();
CCRenderTexture* renderTexture = [[CCRenderTexture renderTextureWithWidth:512 height:512] retain];
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, clippingRegion.size.width, clippingRegion.size.height);
[renderTexture begin];
glPushMatrix();
glRotatef(rotationAngle, 0, 0, 1);
glTranslatef(-clippingRegion.origin.x, -clippingRegion.origin.y, 0);
[super visit];
glPopMatrix();
[renderTexture end];
glDisable(GL_SCISSOR_TEST);
renderTexture.sprite.position = CGPointMake(clippingRegion.origin.x , clippingRegion.origin.y);
renderTexture.sprite.anchorPoint = CGPointMake(0, 1);
renderTexture.sprite.rotation = rotationAngle;
[renderTexture.sprite visit];
[renderTexture release];
glPopMatrix();
}
Basically it creates a texture where to render the ClippingNode contents
Then translate the scene so that the origin in the clipping region is now at (0,0)
Rotate the entire scene by rotationAngle
Enable the scissor
Render the scene
Translate, rotate, and render the sprite containing the texture
It only needs CCRenderTexture to finish the job. Any suggestion will be greatly appreciated.
ClippingNode.h
#import "cocos2d.h"
#interface ClippingNode : CCNode
#property (nonatomic, assign) CGSize clippingSize;
#end
ClippingNode.m
#import "ClippingNode.h"
#interface ClippingNode()
#property (nonatomic, strong) CCRenderTexture * renderTexture;
#property (nonatomic, strong) CCSprite * clippedSprite;
#end
#implementation ClippingNode
#synthesize renderTexture;
#synthesize clippedSprite;
#synthesize clippingSize;
- (void) setClippingSize:(CGSize)newClippingSize {
//assignment
clippingSize = newClippingSize;
//set contentSize
self.contentSize = clippingSize;
//configure renderTexture
self.renderTexture = [CCRenderTexture renderTextureWithWidth:clippingSize.width height:clippingSize.height];
renderTexture.contentSize = CGSizeMake(clippingSize.width, clippingSize.height);
//configure the renderTexture sprite
self.clippedSprite = [CCSprite spriteWithTexture:renderTexture.sprite.texture];
clippedSprite.position = self.position;
clippedSprite.rotation = rotation_;
clippedSprite.scaleY = -1;
}
- (void)visit {
[renderTexture beginWithClear:0 g:0 b:0 a:1];
[super visit];
[renderTexture end];
[clippedSprite visit];
}
#end
Usage:
CCSprite * spriteImage = ...;
spriteImage.position = ccp(0,0);
spriteImage.anchorPoint = ccp(0.5,0.5);
//configure clipping Node
self.clippingNode = [ClippingNode node];
clippingNode.position = ccp(size.width * 0.5f, size.height * 0.5f);
clippingNode.anchorPoint = ccp(0.5f, 0.5f);
clippingNode.rotation = -10.0f;
//configure clipping region
[clippingNode setClippingSize:CGSizeMult(spriteImage.boundingBox.size, 1.5f)];
//add content to the clipping node
[clippingNode addChild:spriteImage]

box2d bodies fall up instead of down

Im working with cocos2d v1.0.1 & the respective Box2d version. In the simulator it all works. Its just a body created at a touch location that drops down to the ground. But I ran it on the device, iphone4, and the objects float upwards.
Why would this happen?
Gravity is set to -0.3f. I have another dynamic body in the scene and it appears on the bottom of the ground as it should. Its just the touch objects that float up. Sleep is True.
I just set sleep to false and now the rover also floats up. But it should not float up. here is my world creation method:
- (void)setupWorld {
b2Vec2 gravity = b2Vec2(0.0f, -0.3f);
bool doSleep = false;
world = new b2World(gravity, doSleep);
}
and here is my body creation from init:
Box2DSprite *roverSprite = [Box2DSprite spriteWithSpriteFrameName:#"rover.png"];
[self createBoxAtLocation:ccp(100,15) withSize:CGSizeMake(50, 50) forSprite:roverSprite isBox:TRUE];
[sceneSpriteBatchNode addChild:roverSprite];
and here is the createBox method:
- (void)createBoxAtLocation:(CGPoint)location withSize:(CGSize)size forSprite:(Box2DSprite *)sprite isBox:(BOOL)isBox{
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
b2Body *body = world->CreateBody(&bodyDef);
//
body->SetUserData(sprite);
sprite.body = body;
b2FixtureDef fixtureDef;
//
if (isBox) {
b2PolygonShape shape;
shape.SetAsBox(sprite.contentSize.width/3/PTM_RATIO,
sprite.contentSize.height/3/PTM_RATIO);
fixtureDef.shape = &shape;
} else {
b2CircleShape shape;
shape.m_radius = sprite.contentSize.width/2/PTM_RATIO;
fixtureDef.shape = &shape;
}
fixtureDef.density = 1.0;
fixtureDef.friction = 1.0;
fixtureDef.restitution = 0.5;
body->CreateFixture(&fixtureDef);
}
The same method is also used for the touch created objects which are created from these lines:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
//b2Vec2 locationWorld = b2Vec2(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);
Box2DSprite *sprite = [Box2DSprite spriteWithSpriteFrameName:#"koko1.png"];
[self createBoxAtLocation:touchLocation withSize:CGSizeMake(50, 50) forSprite:sprite isBox:TRUE];
[sceneSpriteBatchNode addChild:sprite];
return TRUE;
}
Are you in portrait or landscape mode? If in landscape, perhaps you have the device rotated left instead of right. The device orientation can swap the y-values of the accelerometer on you. Not sure if this is related to your issue.
Turns out I had the Target Settings Rotation to Right instead of Left.

Box2D debug test

I have a problem with Box2d. I created an object (circle) in the center of the screen that rotates to see if I set Box2d well, following the tutorial that I found on internet. The problem is that the circle is created, but I can't rotate despite I followed exactly the tutorial found on internet. This is the code:
file .h:
b2World * _world;
GLESDebugDraw * _debugDraw;
file .mm:
-(void)setupWorld {
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
bool doSleep = false;
_world = new b2World(gravity, doSleep);
}
-(void)setupDebugDraw {
_debugDraw = new GLESDebugDraw(PTM_RATIO*[[CCDirector sharedDirector] contentScaleFactor]);
_world->SetDebugDraw(_debugDraw);
_debugDraw->SetFlags(b2DebugDraw::e_shapeBit |b2DebugDraw::e_jointBit);
}
-(void)testBox2D {
CGSize winSize = [CCDirector sharedDirector].winSize;
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(winSize.width/2/PTM_RATIO,winSize.height/2/PTM_RATIO);
b2Body *body = _world->CreateBody(&bodyDef);
b2CircleShape circleShape;
circleShape.m_radius = 25.0/PTM_RATIO;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 1.0;
body->CreateFixture(&fixtureDef);
body->ApplyAngularImpulse(0.01);
}
-(void)updateBox2D:(ccTime)dt {
_world->Step(dt, 1, 1);
[self updateBox2D:dt];
}
-(void) draw {
glDisable(GL_TEXTURE_2D); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
_world->DrawDebugData();
glEnable(GL_TEXTURE_2D); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

in init:
[self setupWorld];
[self setupDebugDraw];
[self testBox2D];
Two problems:
Are you recursively calling updateBox2D? This looks like an infinite loop to me, and I'm surprised that it's not crashing your application.
Instead, you should only call your world's step once (or a few times depending on how you've setup your time step) during your CCScene tick method.
Your next problem is that you're applying a small impulse to your body, but it is only a one-time impulse... Angular impulses are still affected by damping, so the body will not rotate indefinitely by default. To keep your body rotating, you need to set the angular damping to zero:
bodyDef.angularDamping = 0.0f;

Cocos2d draw a polygon using CCSprite

Can you help. Want to draw a polygon (beams at different angles) and apply box 2d body to it. Can you please let me know how to create a CCSprite with a polygon shape
Any examples would help
Cheers
Create Polygon body.
-(void) createDynamicPoly {
b2BodyDef bodyDefPoly;
bodyDefPoly.type = b2_dynamicBody;
bodyDefPoly.position.Set(3.0f, 10.0f);
b2Body *polyBody = world->CreateBody(&bodyDefPoly);
int count = 8;
b2Vec2 vertices[8];
vertices[0].Set(0.0f / PTM_RATIO,0.0f / PTM_RATIO);
vertices[1].Set(48.0f/PTM_RATIO,0.0f/PTM_RATIO);
vertices[2].Set(48.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[3].Set(42.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[4].Set(30.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[5].Set(18.0f/PTM_RATIO,12.0f/PTM_RATIO);
vertices[6].Set(6.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[7].Set(0.0f/PTM_RATIO,30.0f/PTM_RATIO);
b2PolygonShape polygon;
polygon.Set(vertices, count);
b2FixtureDef fixtureDefPoly;
fixtureDefPoly.shape = &polygon;
fixtureDefPoly.density = 1.0f;
fixtureDefPoly.friction = 0.3f;
polyBody->CreateFixture(&fixtureDefPoly);
}
Create your sprite
Attach your sprite to the Polygon body via Fixture and UserData
fixtureDefPoly.SetUserData() = spriteObject;
b2Fixture *fixture;
fixture = circleBody->CreateFixture(&fixtureDefPoly);
fixture->SetUserData(#"spriteObject");
Then Iterate the sprite to the body in your update method.
The easiest way is to open an image editor (such as paint for example or photoshop) and create the image you want. The use it in your program.
Also there is a helloWorld scene when creating an xcode application using cocos2d box2d template. It creates a set of squares with a texture.
CGPoint startPt = edge.start ;
CGPoint endpt = edge.end ;
//length of the stick body
float len = abs(ccpDistance(startPt, endpt))/PTM_RATIO;
//to calculate the angle and position of the body.
float dx = endpt.x-startPt.x;
float dy = endpt.y-startPt.y;
//position of the body
float xPos = startPt.x+dx/2.0f;
float yPos = startPt.y+dy/2.0f;
//width of the body.
float width = 1.0f/PTM_RATIO;
b2BodyDef bodyDef;
bodyDef.position.Set(xPos/PTM_RATIO, yPos/PTM_RATIO);
bodyDef.angle = atan(dy/dx);
NSLog([NSString stringWithFormat:#"Setting angle %f",bodyDef.angle]);
CCSprite *sp = [CCSprite spriteWithFile:#"material-wood.png" rect:CGRectMake(0, 0, 12, 12)];
//TODO: fix shape
[self addChild:sp z:1 ];
bodyDef.userData = sp;
bodyDef.type = b2_dynamicBody;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape shape;
b2Vec2 rectangle1_vertices[4];
rectangle1_vertices[0].Set(-len/2, -width/2);
rectangle1_vertices[1].Set(len/2, -width/2);
rectangle1_vertices[2].Set(len/2, width/2);
rectangle1_vertices[3].Set(-len/2, width/2);
shape.Set(rectangle1_vertices, 4);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.300000f;
fd.restitution = 0.600000f;
body->CreateFixture(&fd);