middle screen in cocos2d-2? - cocos2d-iphone

Did they changed the positioning method in this cocos2d version 2 ?
i do this :
mainBack=[CCSprite spriteWithFile:#"plus.png"];
mainBack.position=ccp(winSize.width/2,winSize.height/2);
NSLog(#"THE PLACE IS IN:%#",NSStringFromCGPoint(mainBack.position) );
[self addChild:mainBack z:0];
its not in the middle but next to it.
it does prints 160, 240.
i am in a retina display when the image is twice bigger .
why is it not in the middle of the screen ?
thanks.

i think u r doing this in ur init method of first scene. Try same thing in onEnter method..everything works fine.
-(void)onEnter
{
[super onEnter];
CGSize winSize = [CCDirector sharedDirector].winSize;
mainBack=[CCSprite spriteWithFile:#"plus.png"];
mainBack.anchorPoint = ccp(0.5f,0.5f);
mainBack.position=ccp(winSize.width/2,winSize.height/2);
NSLog(#"THE PLACE IS IN:%#",NSStringFromCGPoint(mainBack.position) );
[self addChild:mainBack z:0];
}

Related

Cocos2d Screen capture and get sprite from UIImage

I'm very headache about this problem, I'm using these code for capturing a part of the screen
-(UIImage *) glToUIImage {
userphotoCount++;
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [CCDirector sharedDirector].winSize;
CCLayerColor* whitePage = [CCLayerColor layerWithColor:ccc4(255, 255, 255, 0) width:winSize.width height:winSize.height];
whitePage.position = ccp(winSize.width/2, winSize.height/2);
CCRenderTexture* rtx = [CCRenderTexture renderTextureWithWidth:815 height:532];
[rtx begin];
[whitePage visit];
[[[CCDirector sharedDirector] runningScene] visit];
[rtx end];
return [rtx getUIImageFromBuffer];
}
I can get my UIImage by
image = [self glToUIImage];
Then I try to use this code to generate a sprite by the UIImage
-(void) ImageSprite{
image = [self glToUIImage];
userAns = [CCSprite spriteWithCGImage:image.CGImage key:[NSString stringWithFormat:#"photoCap%d.png", userphotoCount]];
userAns.position=ccp(780,410);
userAns.scale=0.6;
[self addChild:userAns z:20];
}
I can get image by these code at first time, but after I changed the screen's contents and use these code to generate new sprite(new UIImage) with the new contents, I'm failed.... the image doesn't change to new image...
How can I get the new image sprite when every time I run the "imageSprite" code?
You can get the new image sprite, but you must to change key
[CCSprite spriteWithCGImage:image.CGImage key:key];

Cocos2d: ARC releasing CCSprite too soon?

I enabled ARC for my cocos2d project.
Now i try doing the following:
BuildTowerMenu *menu = [BuildTowerMenu menuAtLocation:tileScreenPos];
[self addChild:menu];
And in the BuildTowerMenu class:
+(id)menuAtLocation:(CGPoint)location {
return [[self alloc] initMenuAt:location];
}
-(id) initMenuAt:(CGPoint)location {
if (self = [super init]) {
self.position = location;
CCSprite *item1 = [CCSprite spriteWithFile:#"Icon.png"];
item1.position = location;
[self addChild:item1];
}
return self;
}
But for some reason, the Sprite never shows up. After a bit of debugging i see that when i return from menuAtLocation, the CCSprite is still in the Array of children of BuildTowerMenu, but empty (only got an id).
If i actually add the sprite from outside it works and the Sprite is displayed:
BuildTowerMenu *menu = [BuildTowerMenu menuAtLocation:tileScreenPos];
CCSprite *item1 = [CCSprite spriteWithFile:#"Icon.png"];
item1.position = location;
[menu addChild:item1];
[self addChild:menu];
Any hints on what i did wrong here?
P.S.: i added a breakpoint in the dealloc of CCSprite, which never gets called (i guess it should be called if ARC is releasing it)...
I think that the problem is that you set equal positions to your menu and sprite.
I mean that this part of code
CGPoint location = ccp(200.f, 200.f);
[menu setPosition: location];
[sprite setPosition: location];
[menu addChild: sprite];
will add your sprite with position position (400.f, 400.f), relatieve to the menu's parent. You are doing almost the same thing in your BuildTowerMenu's initMenuAt: method/
As already commented on the initial question_:
Ok, it had nothing to do with ARC; the Sprite which seemed to be released was there, it was just a debugger - bug which didnt display it correctly. The problem was actually the line self.position = location; After moving the setposition after the addChild, everything worked.

Why is my main menu image wrong sized on launch but not after a game?

I have an image that loads on a MainMenu scene and appears as wrong sized when the game launches but then after finishing a level returns you to the MainMenu again the image appears right sized.
The first time the image appears to be three quarters or 4/5 of the size of the screen from left to right. The image has a white background around it so I can see a black tall rectangle in the right side of the screen on the main menu's first launch. But after a game it is sized properly and the white background image is sized properly.
Anybody ever have this happen?
Here is the init code for the MainMenuLayer:
-(id)init {
if( (self=[super initWithColor:ccc4(255,255,255,255)]) ) {
[[GameManager sharedGameManager] playBackgroundTrack:BACKGROUND_TRACK_MAIN_MENU];
CGSize screenSize = [CCDirector sharedDirector].winSize;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
CCSprite *background = [CCSprite spriteWithFile:#"MainMenu-iPad.png"];
[background setPosition:ccp(screenSize.width/2,screenSize.height/2)];
[self addChild:background];
[self displayMainMenu];
} else {
CCSprite *background = [CCSprite spriteWithFile:#"MainMenu.png"];
[background setPosition:ccp(screenSize.width/2,screenSize.height/2)];
[self addChild:background];
[self displayMainMenu];
}
-
It works fine on the simulator though...
Print screen position, if position is wrong then put you code in onEnter instead of init.
See this thread in Stack overflow.
-(id)init {
if( (self=[super initWithColor:ccc4(255,255,255,255)]) ) {
}
return self;
}
-(void)onEnter {
[super onEnter];
[[GameManager sharedGameManager] playBackgroundTrack:BACKGROUND_TRACK_MAIN_MENU];
CGSize screenSize = [CCDirector sharedDirector].winSize;
CCSprite *background = [CCSprite spriteWithFile:#"MainMenu.png"];
[background setPosition:ccp(screenSize.width/2,screenSize.height/2)];
[self addChild:background];
[self displayMainMenu];
}
The image was apparently being cached even after clean and build! I ended up replacing the image by removing the original and adding the same one but with some markers just to make sure it got replaced.

Using glScissor on a modal layer in cocos2d

I am coding a modal layer in cocos2d and I would like to use the OpenGL glScissor API call to crop the inside of a CCScrollLayer that I am using,
Basically,
Present some kind of Modal sprite
Put CCScrollLayer with assets on the modal sprite
I want to crop the CCScrollLayer so that it does not overflow the sprite.
Seems pretty simple.
The problem I'm having is that the visit function never seems to be get hit and thus glScissor never gets implemented.
I'm not sure what I'm doing wrong.
The way I do modals is I use blocks to handle a Yes and No condition/state.
// This appears in my "Pick City scene"
-(id) init
{
if ((self = [super init]))
{
NSLog(#"City list");
for (City *cityObj in listOfCities)
{
citySpriteOff = [CCSprite spriteWithSpriteFrameName:#"city.png"];
citySpriteOn = [CCSprite spriteWithSpriteFrameName:#"city_on.png"];
int x = [cityObj.x intValue];
int y = [cityObj.y intValue];
CCMenuItemSprite *mapMenuItem = [CCMenuItemSprite itemFromNormalSprite:citySpriteOff selectedSprite:citySpriteOn target:self selector:#selector(btnCity:)];
[mapMenuItem setTag:i];
[mapMenuItem setIsRelativeAnchorPoint:YES];
[mapMenuItem setAnchorPoint:CGPointMake(0, 0)];
[mapMenuItem setPosition:CGPointMake(x, y)];
[mapMenuItem setIsEnabled:YES];
[mapMenu addChild:mapMenuItem];
i++;
} // next
[self addChild:mapMenu z:2];
}
}
-(void) btnCity:(id)sender
{
NSLog(#"clicked a city button");
int tag = [sender tag];
City *cityObj = [listOfCities objectAtIndex:tag];
NSLog(#"You clicked on city: %#", cityObj.name);
[self lockLayers];
CCLayer *layer = [CCLayer node];
[self addChild:layer z:100];
[MapModalLayer ConfirmCity:cityObj onLayer:layer yesBlock:^{[self btnConfirmedCity:cityObj];} noBlock:^{[self unlockLayers];}];
}
-(void) btnConfirmedCity:(City *)cityObj
{
NSLog(#"confirmed city: %#", cityObj.name);
}
#pragma mark - Lock/Unlock layers
-(void) lockLayers
{
[self MenuStatus:NO Node:self];
}
-(void) unlockLayers
{
[self MenuStatus:YES Node:self];
}
// Disabled/Enable layers
-(void) MenuStatus:(BOOL)_enable Node:(id)_node
{
for (id result in ((CCNode *)_node).children) {
if ([result isKindOfClass:[CCMenu class]]) {
for (id result1 in ((CCMenu *)result).children) {
if ([result1 isKindOfClass:[CCMenuItem class]]) {
((CCMenuItem *)result1).isEnabled = _enable;
}
}
}
else
[self MenuStatus:_enable Node:result];
} // next
}
The actual modal code appears here,
#implementation MapModalLayer
- (id)init {
self = [super init];
if (self) {
// This method never seems to be called
NSLog(#"MapModalLayer init");
}
return self;
}
// This method never seems to be called
- (void) visit {
NSLog(#"Visit");
if (!self.visible)
return;
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(50, 50, 100 , 150);
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
+ (void) CloseAlert: (CCSprite*) alertDialog onCoverLayer: (CCLayer*) coverLayer executingBlock: (void(^)())block {
// shrink dialog box
[alertDialog runAction:[CCScaleTo actionWithDuration:kAnimationTime scale:0]];
// in parallel, fadeout and remove cover layer and execute block
// (note: you can't use CCFadeOut since we don't start at opacity 1!)
[coverLayer runAction:[CCSequence actions:
[CCFadeTo actionWithDuration:0.2f opacity:0],
[CCCallBlock actionWithBlock:^{
[coverLayer removeFromParentAndCleanup:YES];
if (block) block();
}],
nil]];
}
+(void) ConfirmCity:(City *)cityObj onLayer:(CCLayer *)layer yesBlock :(void (^)())yesBlock noBlock:(void (^)())noBlock
{
CCLayerColor *coverLayer = [CoverLayer new];
[layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
[coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:#"modal.png"];
[dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
[dialog setTag:kDialogTag];
//
// We put our CCScrollLayer *scroller content here... it doesn't matter what it is right now
//
//
// Finally we put our accept/reject buttons
//
// Tick/Cross buttons
CCSprite *closeButtonOn = [CCSprite spriteWithSpriteFrameName:#"btn_close.png"];
CCSprite *tickButtonOn = [CCSprite spriteWithSpriteFrameName:#"btn_accept.png"];
// add one or two buttons, as needed
CCMenuItemSprite *opt1Button = [CCMenuItemSprite itemFromNormalSprite:closeButtonOn
selectedSprite:nil
block:^(id sender){
// close alert and call opt1block when first button is pressed
[self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:noBlock];
} ];
[opt1Button setPosition:CGPointMake(-200, -120)];
// create second button, if requested
CCMenuItemSprite *opt2Button = [CCMenuItemSprite itemFromNormalSprite:tickButtonOn
selectedSprite:nil
block:^(id sender){
// close alert and call opt2block when second button is pressed
[self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:yesBlock];
} ];
[opt2Button setPosition:CGPointMake(40, -120)];
CCMenu *menu = [CCMenu menuWithItems:opt1Button, opt2Button, nil];
[menu setContentSize:dialog.contentSize];
[dialog addChild:menu z:2];
[coverLayer addChild:dialog];
}
#end
I think its because I only ever use MapModalLayer's private methods only.
But I am not sure.
Is there a way to allow me to use the glScissor in a modal like explained above?
I've tried moving the glScissor code to the display of the modal, but it never seems to do anything.
To confirm it is working, I moved the glScissor code to the parent and it seems to work fine.
Thus, how do I make the modal layer use/work with glScissor?
I have since resolved this problem.
I used the Viewport from http://pastebin.com/tWsEbxvJ
The way I did it was:
CoverLayer *coverLayer = [CoverLayer new];
[layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
[coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency
// ------------------------------
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:#"modal.png"];
[dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
[dialog setTag:kDialogTag];
.. // Build your pagesArray here for ScrollLayer...
// Now create the scroller and pass-in the pages (set widthOffset to 0 for fullscreen pages)
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:pagesArray widthOffset: 350];
[scroller setShowPagesIndicator:NO];
// finally add the scroller to your scene
//[dialog addChild:scroller];
Viewport *cn = [[Viewport alloc] initWithRect:CGRectMake(3, 0, dialog.contentSize.width-12, dialog.contentSize.height-5)];
[cn addChild:scroller];
[scroller release];
[coverLayer addChild:dialog z:1];
This allows me to put a modal on a layer, put a CCScrollLayer and make sure that the contents do not spill over the internals of the modal sprite I have made (this is why the width configuration looks a bit odd).
Thanks.

Cocos2d 2.0 - Ignoring touches to transparent areas of layers/sprites

I have an app where I have several layers created from PNG images with transparency. These layers are all on the screen over each other. I need to be able to ignore touches given to transparent areas of layers and just be able to detect as touches, when the user taps on a non-transparent area of a layer... see pic...
How do I do that? thanks.
Here you have a possible solution.
Implement an extension on CCLayer and provide this method:
- (BOOL)isPixelTransparentAtLocation:(CGPoint)loc
{
//Convert the location to the node space
CGPoint location = [self convertToNodeSpace:loc];
//This is the pixel we will read and test
UInt8 pixel[4];
//Prepare a render texture to draw the receiver on, so you are able to read the required pixel and test it
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:screenSize.width
height:screenSize.height
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
//Draw the layer
[self draw];
//Read the pixel
glReadPixels((GLint)location.x,(GLint)location.y, kHITTEST_WIDTH, kHITTEST_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
//Cleanup
[renderTexture end];
[renderTexture release];
//Test if the pixel's alpha byte is transparent
return (pixel[3] == 0);
}
if Lio's solution doesn't work, you may add add transparent sprite as a child you yours, place it just under your non-transparent area with size of this non-tranparent area and resive all touches by this new transparent sprite, but not by original sprite.
Here is my solution to your requirement, let me know if it works or not
Create a Category on CCMenu with Name Transparent
File CCMenu+Tranparent.h
#import "CCMenu.h"
#interface CCMenu (Transparent)
#end
File CCMenu+Tranparent.m
#import "CCMenu+Transparent.h"
#import "cocos2d.h"
#implementation CCMenu (Transparent)
-(CCMenuItem *) itemForTouch: (UITouch *) touch{
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
CCMenuItem* item;
CCARRAY_FOREACH(children_, item){
UInt8 data[4];
// ignore invisible and disabled items: issue #779, #866
if ( [item visible] && [item isEnabled] ) {
CGPoint local = [item convertToNodeSpace:touchLocation];
/*
TRANSPARENCY LOGIC
*/
//PIXEL READING 1 PIXEL AT LOCATION
CGRect r = [item rect];
r.origin = CGPointZero;
if( CGRectContainsPoint( r, local ) ){
if([NSStringFromClass(item.class) isEqualToString:NSStringFromClass([CCMenuItemImage class])]){
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:item.boundingBox.size.width * CC_CONTENT_SCALE_FACTOR()
height:item.boundingBox.size.height * CC_CONTENT_SCALE_FACTOR()
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
[[(CCMenuItemImage *)item normalImage] draw];
data[3] = 1;
glReadPixels((GLint)local.x,(GLint)local.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
[renderTexture end];
[renderTexture release];
if(data[3] == 0){
continue;
}
}
free(data);
return item;
}
}
}
return nil;
}
#end
This will check for pixel for returning the CCMenuItem.
Its working fine here.. let me know if you face any issues
-Paresh Rathod
Cocos2d Lover
The solution that worked great for me was using Sprite sheets. I use TexturePacker to create sprite sheets. Steps to create sprite sheet using TexturePacker:
1. Load all the image (.png) files into TexturePacker.
2. Chose data format as coco2d and choose PVR as the texture format.
3. Load the sprite sheet into your code and extract images from your sprite sheet.
Detailed description can be found here.