CCSprite children coordinates transform fails when using CCLayerPanZoom and CCRenderTexture? - cocos2d-iphone

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.

Related

Rotating image around a point

I'm trying to solve this one for hours and I can't figure out where I am going wrong..
On my page there is an image and a "selection frame". This frame can be moved and resized.
I am trying to make the image turn with the center point of the turn being the center of the frame.
I created a small handle at the top for rotation.
Here's the fiddle: http://jsfiddle.net/8PhqX/7/ (give it a minute to load)
The code in the fiddle is very long because I couldn't isolate the specific area relevant to my question. As you play around with it you'll see that the first rotation usually works fine, but then, things go crazy.
Here's the codeline for the rotation:
//selfRotator.handle.angle is the angle(clockwise) at which the rotation handle was rotated
//selfSelector.rotator.ox/oy is the position of the middle of the selection frame
//selfDefaults.imageArea.y is the y position of the section with the image (because of the red stripe in the top)
//selfImageArea.page.startX/Y is starting position of the image storing its position when the drag begins
//rotating by angle, at center point of selection
selfImageArea.page.transform(
['r', -selfRotator.handle.angle, selfSelector.rotator.ox - selfImageArea.page.startX, selfSelector.rotator.oy - (selfImageArea.page.startY - selfDefaults.imageArea.y)]
)
//tracking the image's start position and compensating
selfImageArea.page.attr({
transform: "...T" + (selfImageArea.page.startX) + "," + (selfImageArea.page.startY - selfDefaults.imageArea.y)
});
It looks like it gets messed up because of the getBBox values that don't follow the picture outlines.
I've added gridlines to illustrate the problem
also, iv'e came across this code(https://groups.google.com/forum/#!topic/raphaeljs/b8YG8DfI__g) for "getBBoxRotated()" function that should solve my issue but I can't seem to implement it.

changing textureRect of a CCSprite created by CCRenderTexture

I have a CCSprite which gradually needs to be exhausted linearly from one end, lets say from left to right.For this purpose ,I am trying to change the textureRect property of the sprite so that the part that got exhausted from one end is 'outside' the displaying frame of the sprite.
I did this sort of thing before with a sprite that gets loaded from a spritesheet.And it worked perfectly.But I created this CCSprite using CCRenderTexture and by changing the textureRect property,the entire sprite gets disappeared.
The first image is the original CCSprite which I get from CCRenderTexture.The second image shows what I want to achieve.The black dotted rectangular portion of the Sprite needs to be omitted out.Only the blue dotted portion of the sprite needs to be displayed.Essentially,this blue dotted rectangle is my textureRect.
Is there any way how I could make my sprite reduce from one end.
Also is there any difference between a sprite created normally,and one created using CCRenderTexture.
I have done similar thing like this before using some low-level hack.
There is a work around solution if you use CCProgressTimer, that's very easy and I think it should be enough for your examples.
But you said in comment that you have some special requirements like "exhaust it from both the ends at once" then some low-level hack is needed. My solution from my last object is:
1) Get the texture image's raw data. In cocos2d you can use CCRenderTexture and in cocos2d-x you can use CCImage.
2) CCRenderTexture has a method of - (BOOL) saveToFile: (NSString *) name
format: (tCCImageFormat) format
. You can read its source code then try to save it into an 2D array instead like byte raw[1024][768]. Each element in this array represents one pixel on your picture(the type may not be byte, I'm not sure, nearly forget the details). The format MUST BE PNG since transparency will be needed.
3) Modify raw data directly, set pixel's transparency to 0x0 which you want it to disappear.
4) Re-initialize a CCRenderTexture using picture data you modified.
I can't provide the code directly since is a trade secret and core part of one of my projects. But I can share you my solution. You also need some knowledge about how PNG file works. Read:
https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
Turns out I was making a silly mistake.While supplying values to the textureRect(CGRect),I was actually setting the textureRect.origin.y to the height of the texture which made my textureRect go beyond(above) the texture area.This explains why they were disappearing.

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

How to move background in cocos 2d

Hi i want to develop game like 'Doodle jump'.But i have some problem with the following features-
1.How to move background scene/image.
2.How to detect collision between object.Is it needed a physics engine like box2d or i should just use manual collision.
3.what should be the size of the background image.
4.In fact i have no idea how does background move .So i need a explanation from someone.
Background Movement
A) You could create a TMX Tilemap and then make a very high Tiled-Map.
B) You could create one texture and then cycle the texture coords instead of really moving it.
Detect it manually. Best is detect it via "Point in Boundingbox" or "Rect in Rect".
For more detail visit my blog entry for collision detection with cocos2d : http://www.anima-entertainment.de/?p=262
Size of an Image
Keep in Mind that textures are always at power of 2 in the memory. If you want to create one Background-Image at retina highresolution (960x640 Pixel) in the memory will be a texture of 1024x1024. If possible use smaller Background-Images and stretch them. (like 512x512). But I really would recommend for big scrolling images the TMX Support.
CCTMXTiledMap * tmxNode = [CCTMXTiledMap tiledMapWithGMXFile:#"Level.tmx"];
// lets say you want to move it 50 pixels down in 1 second :
[tmxNode runAction:[CCMoveBy actionWithDuration:1.0 position:ccp(0,-50)];
To create a tilemap : http://www.mapeditor.org/
In the folder of cocos2d, you could get many demos of tilemap.
TileMapTest.h
TileMapTest.m
refer this tutorial this will helpful for you.
http://www.raywenderlich.com/2343/how-to-drag-and-drop-sprites-with-cocos2d
this is used screen movement with pan recognizer