I use this code to show game over menu after _hero sprite and _enemy sprite collide :
if (CGRectIntersectsRect(_hero.boundingBox,_enemy.boundingBox)) {
CCActionCallFunc *_callShowMenu=[CCActionCallFunc actionWithTarget:self selector:#selector(showMenu)];
[self runAction:_callShowMenu];
// EDIT : I also remove both sprites when collision happens.
[_hero removeFromParent];
[_enemy removeFromParent];
}
In _callShowMenu I just stop all actions and show a sprite with half transparent black background image and buttons.
Sometimes when collision happens, it seems to me, that _callShowMenu is called twice, because
background is completely black, like there is the same image behind. Has anyone had a similar problem? (Mostly background image is half-transparent, as it should be).
EDIT:
-(void)showMenu{
[[CCDirector sharedDirector] pause];
CCSprite *_halfTransparentBackground=[CCSprite spriteWithImageNamed:#"halfTransparentBackground.png"];
_halfTransparentBackground.position=ccp(160, 280);
[self addChild:_blackBack z:5];
}
I found a solution using BOOL. Actually everyone uses BOOL in this case, so I don't need to reinvent the wheel.
BOOL doNotCallMeTwice;
Somewhere in the didLoad method:
doNotCallMeTwice=NO;
In the collision detection method:
if (doNotCallMeTwice==NO) {
[self showMenu];
}
And finally:
-(void)showMenu{
doNotCallMeTwice=YES;
}
Possibly, showMenu was called twice(or much more times),because collision detection is in the update method.
Related
I am trying to detect a touch on a CCSprite using:
#implementation MainScene{
CCPhysicsNode *_levelView;
}
- (void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event{
CGPoint location = touch.locationInWorld;
CCSprite *clickedSprite;
for (CCSprite *obj in _levelView.children)
{
if (CGRectContainsPoint(obj.boundingBox, location))
clickedSprite = obj;
}
}
which works perfectly fine.
So I can detect clicked Sprites already.
Since I am using sprites which are transparent at some parts, they are also detected when the transparent part of the sprite is clicked.
But I want to exclude the transparent part from the detection…
For the physics I am using physics shape polygon. Is there a way to use this polygon for something like:
polygonContainsPoint(obj.physicsPolygon, location)
? Or maybe even a way saying all pixels but those with transparency 100? Or an even easier solution?
I am working in Cocos2d and xcode to create a side scrolling game.
I have an issue with my coding for adding a background to the levelscene.
I tried to implement a parallax background to no avail so have opted to just have a background the player will scroll across.
But at the moment the background follows the player across the screen, which frankly looks rubbish.
The code I have is
(void)setupParallax {
NSString *backgroundName = [self.tilemap propertyNamed:#"BackgroundImage"];
CCSprite *background = [CCSprite spriteWithFile:[AssetHelper getDeviceSpecificFileNameFor:[NSString stringWithFormat:#"background-noon.png]]];
background.anchorPoint = ccp(0,0);
background.position = CGPointMake(0, 0);
[self addChild:background z:0];
}
I know it must be something with either the position or anchorPoint but these values only change with reference to the screen they are loaded on.
Have you looked at this tutorial on doing parallax scrolling in cocos2d-x?
You an do parallax scrolling by hand...but it will probably easier, at least if you are just starting out, to do it using the CCParallaxNode and let the framework do the heavy lifting for you.
Anyone that can give any hint of the smartest way to do a main loop animation? I don't want to use CCAnimation because I want to control the animations frame by frame.
Shall I store the sprite rect (relative to the sprite sheet) for each individual frame in an array, and then look up the suiting rect in each animation step? I tried to find out how this is done in CCAnimation, but I didn't succeed...
How to get the rect for each frame at initialization?
How to set the rect at each animation step?
Do I need to use CCSpriteBatchNode? I guess not, eh?
Cannot crealry understand, why you don't want to use CCAnimation, but anyway, to get answer for your questions you can check creation code of the CCSprite instance. Then, check creation of CCSpriteFrame instance. There you will find the answer for at least your first question.
Actually if you just want to manage animation frames differently from CCAnimate, you can just store array of CCSpriteFrames and show them as you want(in CCAnimate action these frames are just changed one by one in equal time intervals).
And if you do not want to show more than one frame of your animation, there is no difference will you use CCSpriteBatchNode or not. It saves a lot of processor time if you need to draw several parts of one texture, as it draws them in one draw call instead of send draw message to all of these sprites.
As you want animate sprite frame by frame I think using CCSpriteBatchNode would be a better option as it give you frame by frame access of animation.Making plist of sprites using any tool like "Zwoptex" will give an efficient way to animate using CCSpriteBatchNode.
Hope you know the animation using plist file with CCSpriteBatchNode.
I did the following with inspiration from Morions answer:
In the game tick function:
_animationFrames.legFrame = (_animationFrames.legFrame + 1) % _animationFrames.legFrames.count;
[_legs setDisplayFrame: [_animationFrames.legFrames objectAtIndex: _animationFrames.legFrame]];
And in the init function:
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"Player.png"];
[self addChild:spriteSheet];
_animationFrames.legFrames = [[NSMutableArray array] retain];
for(int i = 0; i <= 15; ++i)
{
[_animationFrames.legFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"Player_legs-%d.png", i]]];
}
_legs = [CCSprite spriteWithSpriteFrameName:#"Player_legs-0.png"];
[_sprite addChild: spriteSheet];
[spriteSheet addChild:_legs z:1];
I'm trying to control the order in which CCSprites are being layered one on top of the other. I'd use zOrder, but I'm animating characters made up of articulated sprites (some sprites parented on others with addChild) and zOrder is only honored among sibling sprites.
Basically, I want to parent my sprites so they can inherit each others' transforms, but I want to determine the draw order.
Looking around, it sounds like using a CCSprite's vertexZ property is the way to go. I've tried that. I set the draw method of my custom CCSprite like so:
- (void)draw
{
glEnable(GL_BLEND);
CHECK_GL_ERROR_DEBUG();
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
CHECK_GL_ERROR_DEBUG();
[super draw];
glDisable(GL_BLEND);
}
Each of my sprites now has a zOrder of 0 and a unique vertexZ to layer them as I'd like, but it's not working: any sprite that has a parent is not displayed!
Trying some things, I find if I don't set vertexZ, all sprites are displayed. And if I keep the vertexZs and don't parent, they're all displayed. But with vertexZs set, any child sprite won't display.
What's going on here and how can I get it to work?
Update: More clues. I can comment out the GL functions around my call to [super draw] entirely and the results are the same. Also, it turns out child sprites with a vertexZ do display, but wherever they overlap any other sprite they go invisible. The purple paper sprite is a child of the creature's left forearm sprite (on screen right) yet should go on top of it.
For the picture above, I'm basically doing this in my CCLayer. I want the parenting, but I want hand and paper to be on the top.
[self addChild:lUpperarm];
[self addChild:lForearm];
[self addChild:face];
[self addChild:rUpperarm];
[self addChild:rForearm];
[lForearm addChild:handAndPaper];
lUpperarm.vertexZ = -100;
lForearm.vertexZ = -99;
face.vertexZ = -98;
rUpperarm.vertexZ = -97;
rForearm.vertexZ = -96;
handAndPaper.vertexZ = -95;
This is how I want it to look. (I changed the last line to [self addChild:handAndPaper] which loses lForearm's transformations, not what I want.)
Update 2: Some have suggested I add all children with zOrder set to -1: e.g. [lForearm addChild:handAndPaper z:-1]. This changed things a little, but still didn't fix it, alas. Seems either vertexZ is not determining draw order and/or the blending is wrong.
I dealt with this issue when writing an RPG with Cocos2d. The problem is the alpha blending. As you are seeing, the paper is being covered up by the left arm sprite, even though it is transparent. For some reason, when Cocos2d's vertexZ technique is used, this problem can sometimes occur. To fix it, you can try changing your alpha blending level. Try 0.0, 0.5 and 1.0:
-(void) draw
{
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
[super draw];
glDisable(GL_ALPHA_TEST);
}
If that doesn't work, then I recommend a complete workaround solution. Keep all your sprites as part of the same parent node and use regular z ordering. It's not an ideal solution, but if you use a "meta" parent node then you can still transform all the children easily.
While adding only u can control z-order?
[self addChild:lUpperarm z:1];
[self addChild:lForearm z:2];
[self addChild:face z:3];
[self addChild:rUpperarm z:4];
[self addChild:rForearm z:5];
[lForearm addChild:handAndPaper z:6];
I can't be sure that this is your problem but I've had issues in the past when playing with draw() and it turned out to be that I wasn't resetting the blendfunc at the end of the call.
Here's a draw function I use that does some basic drawing with some transparency. Again, no guarantees.
- (void) draw {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
ccDrawSolidPoly(vertices, 4, fillColor);
// This is the important bit. Must do this last.
//
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
}
set higher z value to set object on top. and lower z value to set in back..
I want to set the contentsize of scrollayer.
I have a scrollayer, it's CCLayer type and moving is set by ccTouchMove. I have one schedule for smoothing. BUT.
Problem is that scrolling layer is big like the whole display. I want to set the contentsize of scrollayer. Content in this layer will be scroll and showing ONLY in this layer. Not taking up the whole display. Something like this
Scrolling just in gray CCLayer (scrollayer) ....NOT WHOLE SCREEN.
Can you help me?
P.S.: Setting CCLayerColor and initWithColor:Width:Height: is not working. It just makes some stupid color box and it's moving too.
ok, honestly i would put the window frame at a higher z than the scrolling object ... if you dont you may have to crop and change sprite on the fly for the window content, nasty (at least that is the one way i could do this, without further research).
so :
// initialize this logic somewhere useful
CCNode scrollableContent;
CCSprite windowFrame;
BOOL isScrollPossible;
[self addChild:scrollableContent z:0];
[self addChild:windowFrame z:1];
// and in the touch delegate methods
-(void) ccTouchBegan:{
check if the touch happened in the window, if yes, scrolling is possible
}
-(void) ccTouchMoved:{
if (isScrollPossible) {
compute displacement
compute nextPosition for scrollableContent node;
if ( nextPosition in window ) {
// make scrollableContent follow touch
scrollableContent.position=nextPosition;
} else {
// stop any further scrolling until the next 'touch began'
isScrollPossible=NO;
}
} else {
// scroll not possible, do nothing
}
}
This is the basic idea. You may need clamping logic to prevent the creeping of scrollableContent beyond the edges of the window.
Edited for typos.
After trying desperately with masking and GL_SCISSOR, I settled on cutting a hole in the foreground and only moving the background object when onTouchMoved updated.
To see it in action, have a look at the Stats page of Angry Gran.