Cocos2D 2.0 - changing the rect of a CCSprite / stretching a sprite - cocos2d-iphone

I have created an atlas with all images I will use in a class. If this was a sprite created from an image, I would create it like
mySprite = [CCSprite spriteWithFile:#"white.png" rect:frame];
"white.png" is a 1x1 pixel image that I am stretching to cover the entire CCSprite size, that is defined by rect:frame on that API.
But in order to optimize I/O and memory, I put white.png in an atlas and my idea was to create it using
mySprite = [CCSprite spriteWithSpriteFrameName:#"white.png"];
but this will create a 1x1 pixel sprite. So, my idea was to create a category to extend CCSprite with these lines
#implementation CCSprite (CCSprite_Resize)
-(void)resizeTo:(CGSize) theSize
{
CGFloat newWidth = theSize.width;
CGFloat newHeight = theSize.height;
float startWidth = self.contentSize.width;
float startHeight = self.contentSize.height;
float newScaleX = newWidth/startWidth;
float newScaleY = newHeight/startHeight;
self.scaleX = newScaleX;
self.scaleY = newScaleY;
}
so I could do this
mySprite = [CCSprite spriteWithSpriteFrameName:#"white.png"];
[mySprite resizeTo:frame.size];
and the 1x1 sprite would be stretched to cover the size I want.
The problem is that this is not working.
any clues? thanks.

Make shore you are not overriding somthing like - (CGAffineTransform)nodeToParentTransform. I'm using Box2d physics with cocos2d, and provided be template class PhysicsSprite (subclass of CCSprite) overrided it, and there was a bug: scale property didn't change anything. I fixed it like this:
- (CGAffineTransform)nodeToParentTransform
{
b2Vec2 pos = body_->GetPosition();
float x = pos.x * PTM_RATIO;
float y = pos.y * PTM_RATIO;
// Make matrix
float radians = body_->GetAngle();
float c = cosf(radians);
float s = sinf(radians);
if (!CGPointEqualToPoint(anchorPointInPoints_, CGPointZero))
{
x += c * -anchorPointInPoints_.x * scaleX_ + -s * -anchorPointInPoints_.y * scaleY_;
y += s * -anchorPointInPoints_.x * scaleX_ + c * -anchorPointInPoints_.y * scaleY_;
}
// Rot, Translate Matrix
transform_ = CGAffineTransformMake( c * scaleX_, s * scaleX_,
-s * scaleY_, c * scaleY_,
x, y );
return transform_;
}
In original, there was no scaleX_ and scaleY_ multiplying.

It seems that in your case you can use CCLayerColor to create one-color layer. There is no need to use sprite for it.
About your question - make sure, that frame.size is not zero (CGSizeZero)

Related

Cocos2d-x smooth drawing

i'm developing freehand drawing game, and the drawing isn't very smooth , i used this code:
void Canvas::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event) {
Canvas::drawEvenlySpacedSprites(touch->getLocation(),touch->getPreviousLocation());
}
void Canvas::drawEvenlySpacedSprites(Vec2 start, Vec2 end) {
// begin drawing to the render texture
_target->begin();
float distance = start.getDistance(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;
Sprite * sprite = Sprite::create("brush3.png");
sprite->setColor(Color3B::BLUE);
sprite->setPosition(Vec2(start.x + (difx * delta), start.y + (dify * delta)));
sprite->visit();
}
}
// finish drawing and return context back to the screen
_target->end();
}
I'm working with cocos2d-x V3.3
Please help me to get smooth drawing
Thanks
As Nadarian says, you should not create a new Sprite each time you draw it.
Even though you cannot reuse same sprite, you can create sprite from same SpriteFrame.
First, you need to store SpriteFrame on some variable. Or, you can use SpriteFrameCache if you want.
I will show the code which will use SpriteFrame.
// create sprite
auto sprite = cocos2d::Sprite::create("brush3.png");
// get spriteframe from sprite
auto spriteframe = sprite->getSpriteFrame();
and on Canvas::drawEvenlySpacedSprites, create Sprite from the stored spriteframe.
Here is the example, change the this code
Sprite * sprite = Sprite::create("brush3.png");
to this code,
Sprite * sprite = Sprite::createWithSpriteFrame(spriteframe);
I've found this implementation, I hope it will helps you: http://build-failed.blogspot.it/2012/08/freehand-drawing-with-cocos2d-x-and.html

Moving a box2d object along the x axis while gravity pulls on the y axis

I have a box2d object that is being moved down the screen via gravity
int32 velocityIterations = 6;
int32 positionIterations = 2;
self.world->Step(dt, velocityIterations, positionIterations);
self.world->ClearForces();
for(b2Body *b = self.world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
id object = (id)b->GetUserData();
if([object isKindOfClass:[FallingObject class]])
{
CCSprite *sprite = (CCSprite *)b->GetUserData();
sprite.position = CGPointMake(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
When the user moves their finger across the screen either left or right i want to move the box2d object left or right while the object is still moving down the screen.
Can anyone suggest the best way to do this. I have tried applying linear velocity but it just seems to shoot of screen.
Any suggestions
Thanks
There some ways to do this, and you need to try the best for your case.
You can apply forces, impulse, or change the body velocity manually just for X parameter:
// x axis force
b2Vec2 xAxisForce = b2Vec2(10, 0);
// Try one of these
b->ApplyForce(xAxisForce, b->GetWorldCenter());
b->ApplyForceToCenter(xAxisForce);
b->ApplyLinearImpulse(xAxisForce, b->GetWorldCenter());
// Or change the body velocity manually
b->SetLinearVelocity(b2Vec2(10, b->GetLinearVelocity().y));

How to rotate the physics or dynamic body along an arc path in cocos2d(box2D)

As I am newbie to cocoa2d I am struggling alot to rotate the physics or dynamic body along an arc path.
The way I tried is as follows:
#define COS_ANIMATOR(position, timeCount, speed, waveMagnitude) ((cosf(timeCount * speed) * waveMagnitude) + position)
#define SIN_ANIMATOR(position, timeCount, speed, waveMagnitude) ((sinf(timeCount * speed) * waveMagnitude) + position)
CCSpriteBatchNode *pipe_parent = [CCSpriteBatchNode batchNodeWithFile:#"pipe.png" capacity:100];
CCTexture2D *pipeSpriteTexture_ = [pipe_parent texture];
PhysicsSprite *pipeSprite = [PhysicsSprite spriteWithTexture:pipeSpriteTexture_ rect:CGRectMake(0 ,0 ,55,122)];
//pipe = [CCSprite spriteWithFile:#"pipe.png"
// rect:CGRectMake(0, 0, 55, 122)];
[self addChild:pipeSprite];
// pipe.position = ccp(s.width/2 , 420.0);
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody; //this will be a dynamic body
myBodyDef.position.Set(((s.width/2) - 90)/PTM_RATIO, 420.0/PTM_RATIO); //set the starting position
myBodyDef.angle = 0; //set the starting angle
b2Body* staticBody = world->CreateBody(&myBodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
boxFixtureDef.userData = pipeSprite;
boxFixtureDef.filter.groupIndex = -1;
staticBody->CreateFixture(&boxFixtureDef);
[pipeSprite setPhysicsBody:staticBody];
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
const CGPoint newSpritePosition = ccp(COS_ANIMATOR(150, mTimeCounter, 0.05,50), SIN_ANIMATOR(400, mTimeCounter, -0.05, 50));
pipeSprite.position = newSpritePosition;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
on following this approach my sprite rotating in circular motion instead of rotating in an arc path.
Please give your ideas or suggestions.
Thanks all
I'm not entirely sure what it is you are looking to accomplish when you talk about rotating in an arc path. I only see you setting a position, not a rotation, so are you just wanting to set a position, or a rotation, or both? Your position code looks like you are trying to achieve a circular (or elliptical) path because you are using the sine and cosine in the x,y position.
If you're looking to move a sprite along a sine curve, I did that today and it took a bit of trial and error. I had some variables for the amplitude and period, and from there I traced out a nice sine curve movement in the sprite's update: method.
CGPoint initialPosition; // set this to the sprite's initial position
float amplitude; // in points
float period; // in points
float y, x = initialPosition.x;
-(void) update:(ccTime)dt
{
x += dt * 100; // speed of movement across the screen. Picked by trial and error.
y = initalPosition.y + amplitude * sinf((x - initialPosition.x)/period);
sprite.position = ccp(x,y);
sprite.rotation = cosf((x - initialPosition.x)/period); // optional if you want to rotate along the path as well
}
Don't know if this is anything you are looking for but it might give you some ideas.

Box2D object speed

I have a little issue with my game. In my main game scene I create a Player object from a class, like this:
player = [Player spriteWithFile:#"Icon-Small#2x.png"];
player.position = ccp(100.0f, 180.0f);
[player createBox2dObject:world];
Below is the main chunk of my small Player class that creates the body and the fixture so I can use it in a box2d world.
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_dynamicBody;
playerBodyDef.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
playerBodyDef.userData = self;
playerBodyDef.fixedRotation = true;
playerBodyDef.linearDamping = 4.0;
body = world->CreateBody(&playerBodyDef);
b2CircleShape circleShape;
circleShape.m_radius = 0.7;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 1.0f;
fixtureDef.friction = 1.0f;
fixtureDef.restitution = 1.0f;
body->CreateFixture(&fixtureDef);
The result of this code is a Box2d object with Icon-Small#2x.png over it. When I move a joystick, a Box2D impulse is applied and the player moves. Simple enough, right?
In non-retina displays, this works fine. However, when I switch to Retina in the simulator, Icon-Small#2x.png is created a little higher and farther to the right, not over the Box2D circle. Then, gravity is applied and they both fall down to the platform. Icon-Small#2x.png falls twice as fast. When I move the joystick, the Box2D circle moves, but Icon-Small#2x.png moves twice as fast and the camera follows it, soon leaving the circle off the screen. I doubt this issue has really anything to do with the code I have here, I feel like its a scaling issue hidden somewhere in my game. Does anyone have suggestions?
Edit:
I move the sprite with:
[player moveRight];
This is moveRight in the player class:
-(void) moveRight {
b2Vec2 impulse = b2Vec2(2.0f, 0.0f);
body->ApplyLinearImpulse(impulse, body->GetWorldCenter());
}
Shouldn't be any issue here, right?
Edit (again):
Here's my update: method-
- (void) update:(ccTime)dt {
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(dt, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor.position = CGPointMake( b->GetPosition().x *PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
b2Vec2 pos = [player body]->GetPosition();
CGPoint newPos = ccp(-1 * pos.x * PTM_RATIO + 50, self.position.y * PTM_RATIO);
[self setPosition:newPos];
}
I have a feeling that the issue is somewhere in here. I've tried changing PTM_RATIO around, but it doesn't affect the speed. Any ideas?
Edit: see comment below, almost have this figured out
You problem probably stems from the fact you are using a #2x image... Read, http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:how_to_develop_retinadisplay_games_in_cocos2d
There it states:
WARNING: It is NOT recommend to use the ”#2x” suffix. Apple treats those images in a special way which might cause bugs in your cocos2d application.
So to solve your problem read through the information on using png files with the -hd suffix.
For the comment:
Do you have some code that looks something like...
world->Step(dt, 10, 10);
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO);
}
}
See how the code loops through all the box2d bodies in the word and sets the position of the sprite that is associated with the box2d body?

How to move a sprite at a certain angle with a joystick

Hi I have finally made a working joystick in cocos2d. I am able to rotate a sprite to the exact angle that the joystick thumb, or cap, is 'pointing'. However, I am unable to move the sprite in that same direction. Is there an easy way to move the sprite with the way I have the rotating code set up? Also is there a way to keep it moving if your thumb is still pressed, but not moving the joystick?. PS this code is all within the TouchesMoved method. PPS. the cap is the thumb, the pad is the joystick background, and the Sprite2 is the sprite that I want to move. (95, 95) is the center of the pad sprite.
if(capSprite.position.x>=padSprite.position.x){
id a3 = [CCFlipX actionWithFlipX:NO];
[sprite2 runAction:a3];
}
if(capSprite.position.x<=padSprite.position.x){
id a4 = [CCFlipX actionWithFlipX:YES];
[sprite2 runAction:a4];
}
CGPoint pos1 = ccp(95, 95);
CGPoint pos2 = ccp(capSprite.position.x, capSprite.position.y);
int offX = pos2.x-pos1.x;
int offY = pos2.y-pos1.y;
float angleRadians = atanf((float)offY/(float)offX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float theAngle = -1 * angleDegrees;
sprite2.rotation = theAngle;
I'm not familiar with cocos2d but I had a quick look at the documentation and this sample might be of use to you:
if keys[key.UP]:
self.target.acceleration = (200 * rotation_x, 200 * rotation_y)
I had written a long explanation answering your second question but I believe this "self.target.acceleration" solves that too. You can read more at the cocos2d API documentation.
What I generally do is get the angle, convert it to a CGPoint with ccpForAngle(float) and then multiply the CGPoint by a value:
float angle = whatever;
CGPoint anglePoint = ccpForAngle(angle);
// You will need to play with the mult value
angle = ccpMult(angle, 2.5);
// This also works with box2D or probably Chipmunk.
sprite.position = angle;