scaleX of CCSprite on a CCBatchNode looks like total trash? - cocos2d-iphone

I have a line which I am scaling just the X of the sprite down to 23%... If I do this in a graphics program, it looks fine:
However, if I do this in cocos by saying scaleX = 0.23; I get:
Why is cocos making this look like trash? Is there anything I can do to fix this? I tried doing mipmapping, but that only smoothed it a little, it still looks horrible.
Note, the way this is being rendered is:
ccnode (main container)
ccspritebatchnode
ccsprite (container, scaled 0.5)
ccsprite (container, unscaled)
ccsprite (actual sprite, scaled 0.23)
So I suspect this has something to do with using multiple levels of nested ccsprite containers with their own scaling.
I am using cocos2d v2.x
UPDATE: this has nothing to do with CCSprite containers. I tried adding this directly to a CCNode and it looks like the exact same garbage. Can someone PLEASE help?

Related

Cocos2d: algorithm to get a shadow following a CCSprite in a realistic way

I am working with Cocos2d 2.0 and no else (no BOX2D etc..). I have a character and added a shadow to it as CCSprite child node. It gives a nice "flying effect" when it moves but unfortunately, when the character rotates also the children do and the shadow child moves in an unrealistic way. See this picture:
In 3D gaming this would be taken care in the graphic engine with a 3D Matrix and the the position of the light source in the game. However my game is much simpler and does not require any 3D graphics so I need to find a programmatic approximation of this.
To first attempted to ovverride the "setPosition" and "setRotation" methods but did not help much (the shadow doesn't change position).
-(void) setPosition:(CGPoint)position
{
[super setPosition:position];
CCSprite * shadow = (CCSprite *)[self getChildByTag:belowByOneZFirst];
if (shadow!=nil) {
[shadow setPosition:shadowOriginalPosition];
CCLOG(#"Setting shadow position");
}
}
-(void) setRotation:(float)rotation
{
[super setRotation:rotation];
CCSprite * shadow = (CCSprite *)[self getChildByTag:belowByOneZFirst];
if (shadow!=nil) {
[shadow setRotation:0];
CCLOG(#"Setting shadow rotation");
}
}
I have two possible paths to follow now. One is to make the shadow an indipendent CCSprite (and not add it as child) and the other one is to attempt to ovverride the setters modifying the "SET_DIRTY_RECURSIVELY()" macro (it could check if a child has a specific tag and if so does not apply the change).
The first approach is a bit overcomplicated and the second one sounds ok but still a bit too complex.
Also, just not "changing" the shadow relative position does not solve the matter fully. I should instead write some code to adapt the shadow relative position taking account of the relative position of the Sprite within the screen (say I set my sun to be in the top left corner then the shadow will change shape according to the relative position to the sun).
Has anyone else had a similar algorithm to implement with Cocos2d and if so are there any common patterns to solve this?
tip: add both sprite and shadow (with position offset) as child of a ccnode. Move the node, rotate only the sprite, shadow position is still an offset to sprite position. Problem solved (as far as I understood).

Animate CCSprite on Each Update

I have a CCSprite object of which I need to update the on screen (x,y) position as quickly as possible. It is an augmented reality app so the on screen position needs to appear fixed to a real world location.
Currently, during each update I check the heading and attitude of the device then move the sprite accordingly by determining the new x and y positions
[spriteObject setPosition:ccp(newX, newY)];
Each degree change in heading corresponds to 10 pixels in on screen position, so by setting the position this way the sprite jumps around in intervals of 10 pixels which looks stupid. I'd like to animate it smoothly, maybe by using
[spriteObject runAction:[CCMoveTo actionWithDuration:0.2f position:ccp(newX, newY)]];
but the problem here is that a new position update comes in while the sprite is animating and it sort of screws the whole thing up. Anyone know of a nice solution to this problem? Any help is much appreciated as I've tried numerous failed solutions to this point.
You can try to just animate your sprite movement to the point. I mean, you can several times during one second run animated position correction with duration of 1/numberOfUpdates in one second. Something like
- (void) onEnter
{
[super onEnter];
[self schedule:#selector(updatePositionAnimated) interval:0.2f];
}
- (void) updatePositionAnimated
{
[spriteObject runAction:[CCMoveTo actionWithDuration:0.2f position:ccp(newX, newY)]];
}
I suppose, you will have smooth enough animation in this case

CCSprite children coordinates transform fails when using CCLayerPanZoom and CCRenderTexture?

Thanks for reading.
I'm working on a setup in Cocos2D 1.x where I have a huge CCLayerPanZoom in a scene with free panning and zooming.
Every frame, I have to additionally draw a CCRenderTexture on top to create "darkness" (I'm cutting out the light). That works well.
Now I've added single sprites to the surface, and they are managed by Box2D. That works as well. I can translate to the RenderTexture where the light sources ought to be, and they render fine.
And then I wanted to add a HUD layer on top, by adding a CCLayer to the scene. That layer needs to contain several sprites stacked on top of each other, as user interface elements.
Only, all of these elements fail to draw where I need them to be: Exactly in the center of screen. The Sprites added onto the HUD layer are all off, and I have iterated through pretty much every variation "convertToWorldSpace", "convertToNodeSpace", etc.
It is as if the constant scaling by the CCPanZoomLayer in the background throws off anchor points in the layer above each frame, and resetting them doesn't help. They all seem to default into one of the corners of the node bounding box they are attached to, as if their transform is blocked or set to zero when it comes to the drawing.
Has anyone run into this problem? Is this a known issue when using CCLayerPanZoom and drawing a custom CCRenderTexture on top each frame?
Ha! I found the culprit! There's a bug in Cocos2D' way of using Zwoptex data. (I'm using Cocos2D v 1.0.1).
It seems that when loading in Zwoptex v3 data, sprite frames' trim offset data is ignored when the actual sprite frame anchor point is computed. The effect is that no anchor point on a sprite with trim offset in its definition (eg in the plist) has its anchor point correctly set. Really strange... I wonder whether this has occurred to anybody else? It's a glaring issue.
Here's how to reproduce:
Create any data for a sprite frame in zwoptex v3 format (the one that uses the trim data). Make sure you actually have a trimmed sprite, i.e. offset must be larger than zero, and image size must be larger than source.
Load in sprite, and try to position it at center of screen. You'll see it's off. Here's how to compute your anchor point correctly:
CCSprite *floor = [CCSprite spriteWithSpriteFrameName:#"Menu_OmeFloor.png"]; //create a sprite
CCSpriteFrame *frame=[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"Menu_OmeFloor.png"]; //get its frame to access frame data
[floor setTextureRectInPixels:frame.rect rotated:frame.rotated untrimmedSize:frame.originalSizeInPixels]; //re-set its texture rect
//Ensure that the coordinates are right: Texture frame offset is not counted in when determining normal anchor point:
xa = 0.5 + (frame.offsetInPixels.x / frame.originalSizeInPixels.width);
ya = 0.5 + (frame.offsetInPixels.y / frame.originalSizeInPixels.height);
[floor setAnchorPoint:ccp(xa,ya)];
floor.position=(where you need it);
Replace the 0.5 in the xa/ya formula with your required anchor point values.

Retina Display Bug? (Cocos2d)

I am using enableRetinaDisplay in my project and it is working very well except when I use this code.
//+++VRope
//create batchnode to render rope segments
CCSpriteBatchNode *ropeSegmentSprite = [CCSpriteBatchNode batchNodeWithFile:#"rope.png" ];
[game addChild:ropeSegmentSprite];
//Create two cgpoints for start and end point of rope
CGPoint pointA = ccp(73, 330); //Top
CGPoint pointB = ccp(self.position.x +5, self.position.y +30); //Bottom
//create vrope using initWithPoints method
verletRope = [[VRope alloc] initWithPoints:pointA pointB:pointB spriteSheet:ropeSegmentSprite];
Instead of drawing one high-res image of the rope, this code is drawing two rope images. I know that it is the retina display that is causing this because I tested it on an iphone 3gs and the simulator and it works great... until I test it on my iphone 4 then it draws two ropes instead of one. Am I doing something wrong?
I know it's too late but I found this question on the first page when searching google so I'll post this answer for others to find in the future.
In VRope.mm search for
[[[spriteSheet textureAtlas] texture] pixelsHigh]
and replace with
[[[spriteSheet textureAtlas] texture] pixelsHigh]/CC_CONTENT_SCALE_FACTOR()
That's it.

Problem with cocos2d and orientation changes, textures are deformed

I'm using cocos2d v0.99.5-beta2 and I have a strange problem only on iPhone 1st gen and iPhone 3g.
When I change iPhone's orientation all my CCSprite are deformed and duplicated.
I already have tested many methods to rotate my scene but I always have the same result.
But I haven't this problem on simulator, iPhone 4 and iPad.
See screenshots
I wonder if it's not a problem linked to the hardware. It looks like as the graphic hardware doesn't support orientation changes. But it's only suppositions.
I hope someone can help me.
Not sure if this will make a difference but are you specifying the content size of the texture or are you letting cocos2d define it? Here I am using a subclass of CCSprite (spuButton):
CCTexture2D *redButtonNormal = [[CCTextureCache sharedTextureCache] addImage:#"RedButtonNormal.png"]; //I don't specify the content size.
spuButton *redButton = [spuButton spuButtonWithTexture:redButtonNormal];
redButton.position = ccp(((size.width / 2) - (redButton.contentSize.width / 2)), ((size.height / 2) + (redButton.contentSize.height / 2)));
[self addChild:redButton];
Hope this helps 8)