My Cocos2D app utilizes a number of CCMenuItemSprite's for buttons (e.g. back button). When the button is on the left half of a landscape scene, it fails to respond to the touch. The buttons on the right half of the screen work fine. The code to initialize the button is straight forward:
CCSprite *normalSprite = [CCSprite spriteWithFile:#"MenuArrowButtonOblongNormal_iPad.png"];
CCSprite *selectedSprite = [CCSprite spriteWithFile:#"MenuArrowButtonOblongSelected_iPad.png"];
CCMenuItemSprite *backButton = [CCMenuItemSprite itemFromNormalSprite:normalSprite
selectedSprite:selectedSprite
target:self
selector:#selector(returnToOptionsMenu)];
if (screenSizeInPixels.width == 1136.0f) {
[backButton setScaleX:0.9375f];
[backButton setScaleY:0.8322f];
buttonHeight = 0.9f;
}
CCMenu *sceneSelectMenu;
sceneSelectMenu = [CCMenu menuWithItems: backButton,nil];
[sceneSelectMenu alignItemsVerticallyWithPadding:screenSize.height * 0.059f];
[sceneSelectMenu setPosition:ccp(screenSize.width*0.15,
screenSize.height * buttonHeight)];
[self addChild:sceneSelectMenu];
// And finally the back button label
CCLabelTTF *backButtonLabel;
backButtonLabel = [CCLabelTTF labelWithString:NSLocalizedString(#"Back", #"Enables user to exit the current screen and view the previous screen")
fontName:#"Marker Felt"
fontSize:scaledFontSize*1.3];
backButtonLabel.color = ccc3(255,255,255);
[backButtonLabel setAnchorPoint:ccp(0.5,0.5)];
backButtonLabel.position = ccp(screenSize.width * (0.14+labelOffset),
screenSize.height * labelHeight);
[self addChild:backButtonLabel z:2];
This is an older app that utilized Cocos2D version 1.1-RC0. I have made several updates to this code based on the suggested changes in iPhone 6 and 6+ update patch for cocos2d 2.1. But these primarily address resolution/scale factor issues.
If no one has seen this issue, can you suggest where in the cocos2D I might investigate to determine why the touches are not being detected/acted upon?
Related
I want to add animations to some buttons using UIKitDynamics, however doing the very very basics with a UISnapBehaviour doesn't work at all. I am using IB to layout all of my subviews, so keep in mind that I cannot reposition anything by calling self.button.frame, you have to use constraints.
That said here is what I have...When I run the animation it blinks quickly and looks terrible.
// Position the buttons off screen
self.swerveButton.translatesAutoresizingMaskIntoConstraints = NO;
self.followButton.translatesAutoresizingMaskIntoConstraints = NO;
self.swerveButtonTopSpaceConstraint.constant = -200;
CGPoint swerveSnapPoint = self.swerveButton.center;
CGPoint followSnapPoint = self.followButton.center;
UISnapBehavior *followSnap = [[UISnapBehavior alloc] initWithItem:self.followButton
snapToPoint:followSnapPoint];
UISnapBehavior *swerveSnap = [[UISnapBehavior alloc] initWithItem:self.swerveButton
snapToPoint:swerveSnapPoint];
[self.overlayView fadeInWithDuration:0.2 completion:^{
swerveSnap.damping = 0.3;
[self.animator addBehavior:swerveSnap];
followSnap.damping = 0.3;
[self.animator addBehavior:followSnap];
}];
}
UIKitDynamics doesn't work with constraints. If you want to use them you'll have to go old school and set frames manually, at least during the animation anyway.
I'm having a little trouble implementing a background change when the player hits a certain score.
I'm using the if(self.score>=10) line to tell my game to change the background but it doesn't seem to be working. I have no errors with this line but no results either.
What I have:
#implementation Scene{
SKScrollingNode * floor;
SKScrollingNode * back;
SKLabelNode * scoreLabel;
}
- (void) createBackground
{
back = [SKScrollingNode scrollingNodeWithImageNamed:#"back" inContainerWidth:WIDTH(self)];
if(self.score>=10){
back = [SKScrollingNode scrollingNodeWithImageNamed:#"image2" inContainerWidth:WIDTH(self)];
[back setAnchorPoint:CGPointZero];
[back setPhysicsBody:[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]];
back.physicsBody.categoryBitMask = backBitMask;
back.physicsBody.contactTestBitMask = birdBitMask;
[self addChild:back];
}
there are certain points you have to keep in your mind i think your both background contains physics body
1)may be and the time of transition they first background colliding with second background and they preventing each other to swap
change your collisionBitMask for both background ->prevent them for colliding
for eg
bg.physicsBody.categoryBitMask=bg1;
bg.physicsBody.collisionBitMask=0;
bg.physicsBody.contactTestBitMask=bg2;
bg.physicsBody.categoryBitMask=bg2;
bg.physicsBody.collisionBitMask=0;
bg.physicsBody.contactTestBitMask=bg1;
or use skaction to swap backgrounds
The way i would do this would be to create a brand new SKScene entirely with a new background.
Or if you want them to scroll to the next background. I would create two backgrounds.
Ex.
//this syntax is wrong (dont remember)
//initializing
SKSpriteNode *bg1 = [SKSpritenode spritenodefromImage:#"bg1"];
SKSpriteNode *bg1 = [SKSpritenode spritenodefromImage:#"bg1"];
bg1.position = CGPointMake(self.size.width/2, self.size.height/2);
bg2.position = CGPointMake(self.size.width/2 + bg1.size.width, self.size.height/2);
//////////////////////////////
//then when you want to scroll them
-(void)scrollBackgrounds
{
bg1.position = CGPointMake(bg1.position.x - 5, self.size.height/2);
bg2.position = CGPointMake(bg2.position.x -5 , self.size.height/2);
}
I am trying to create a realistic bobblehead app, and want to use physics for the bobble animation. I have seen other apps out there that do it, and from what I gather I need to use SpriteKit.
I have created a SKScene and used a SKPhysicsJointPin to pin the head to the body, but it doesnt move around at all. Any ideas or suggestions?
UPDATED CODE (5/28):
Now using 2 spring joints on the head and it moves left to right, but not up and down. Also, tapping quickly causes the head to eventually go far enough right to "fall of" and out of view. Weird.
Have any ideas on what the proper setting would be to allow it to bobble up, down, left, and right whil staying remotely centered on it's starting position and staying within a specified region so it doesnt come off the body and look all funny?
BobbleheadView is a subclassed SKView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor =[UIColor clearColor];
self.showsFPS = YES;
self.showsNodeCount = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(animateBobble)];
[self addGestureRecognizer:tap];
SKScene *bobbleheadScene = [SKScene sceneWithSize:self.bounds.size];
[self presentScene:bobbleheadScene];
// 1. Body
self.body = [SKSpriteNode spriteNodeWithImageNamed:#"Bobble-Body"];
self.body.position = CGPointMake(self.frame.size.width/2, self.body.frame.size.height/2);
self.body.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
[bobbleheadScene addChild:self.body];
// 2. Head
self.head = [SKSpriteNode spriteNodeWithImageNamed:#"Bobble-Head"];
self.head.position = CGPointMake(self.center.x, self.body.frame.size.height);
//self.head.physicsBody.affectedByGravity = YES;
// self.head.physicsBody.dynamic = NO;
//This bobbles head great, but head falls off body and out of view
self.head.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.head.size center:self.head.position];
//End
//self.head.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.head.frame];
//self.head.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.head.size.height/2];
[bobbleheadScene addChild:self.head];
// 3. Ceiling
self.ceiling = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(32, 32)];
self.ceiling.position = CGPointMake(self.frame.origin.x+self.frame.size.width/2, self.frame.size.height);
self.ceiling.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
[bobbleheadScene addChild:self.ceiling];
//Spring Joint for Ceiling to Head
SKPhysicsJointSpring *spring1 = [SKPhysicsJointSpring jointWithBodyA:self.ceiling.physicsBody bodyB:self.head.physicsBody anchorA:self.ceiling.position anchorB:CGPointMake(self.head.frame.origin.x+self.head.frame.size.width/2, 0)];
spring1.frequency = 20.0; //gives the spring some elasticity.
spring1.damping = 5.0; //Will remove damping to create the 'pendulum'
[bobbleheadScene.physicsWorld addJoint:spring1];
//Spring Joint for Head to Body
SKPhysicsJointSpring *spring = [SKPhysicsJointSpring jointWithBodyA:self.body.physicsBody bodyB:self.head.physicsBody anchorA:CGPointMake(self.body.position.x+self.body.size.width/2, self.body.position.y) anchorB:CGPointMake(self.head.position.x+self.head.size.width/2, self.body.position.y-self.body.size.height/2)];
spring.frequency = 10.0; //gives the spring some elasticity.
spring.damping = 1.0;
[bobbleheadScene.physicsWorld addJoint:spring];
}
return self;
}
-(void)animateBobble{
NSLog(#"Did Tap Bobblehead!");
[self.head.physicsBody applyImpulse:CGVectorMake(100, -200)];
//[self.body.physicsBody applyImpulse:CGVectorMake(20, 10)];
}
The only way you'll get this to work is to make a "sled".
So: make an app where, on screen there are (say) six sliders.
TBC I mean, when the app is actually running, you'll see six sliders.
TBC, this is only a sled, it's only for you as a developer, it's not for the consumer app.
(I believe the term "sled" comes from the automotive industry; when they make the first version of a chassis/engine to test it out.)
Make it so that some sliders control spring power/damp (or whatever factors you have available in cocos) and that other sliders nudge the position of the connections/spring lengths.
it's the only way to get a result! Be sure to show the values on screen, or at least print them out on the console as they change.
This is the everyday thing in game development. Typically the sled is more work than the actual consumer scene or feature. You won't be able to achieve it without a "sled". I hope it helps!
I have a scene with 2 layers. The main layer and a hud layer above it. The hud just has a menu with its buttons and the timer label. I am using CCNode-SFGestureRecognizers so I can attach standard UIGestureRecognizers for each of the CCSprites in the middle of the screen on the main layer. The strange thing is that the menu seems to be eating all touch events for the area right of the red line. Not just at the bottom around the menu but all the way to to the top of the screen. If I don't add the menu to the layer or if I place that layer behind the main layer everything works ok, but that doesn't work visually for me. What do I need to do to fix this?
//The hud layer setup
CCMenu *menu = [CCMenu menuWithArray:#[_recordButton, resetButton, debugButton, _playButton]];
[menu setPosition:ccp(windowSize.width - 225, 50)];
[menu alignItemsHorizontallyWithPadding:50];
[self addChild:menu];
//The scene setup in another class
self.mainLayer = [MainLayer node];
[self addChild:_mainLayer z:0];
self.hudLayer = [HudLayer node];
[self addChild:_hudLayer z:1];
Edit:
I have tried setting the menu's priority [menu setHandlerPriority:128]; and when that didn't work I subclassed CCMenu and overrode:
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:200 swallowsTouches:NO];
}
I've tried it with swallowsTouches: set to NO and YES with no difference.
It turns out that CCMenu is defaulting to a contentSize that is equal to the device's screen size. This was making it effectively cover 1/2 the scene with the position I was using. So I just had to set the content size to something close to the actual menu item's overall size: [menu setContentSize:CGSizeMake(400, 50)];
I'm having problems using CCMenu with scaled CCMenuItemSprite menu items. I'm trying to scale the menu item sprites differently based on which device the game is being played on (the iPad needs to scale it to about 1.5x, whereas on the iPhone it's about 0.75x)
From what I've read, we can't scale the CCSprite directly, or the CCMenuItemSprite, because when it's added to the CCMenu the touch rectangles aren't updated correctly. I believe that I have to scale the CCMenu to scale the Menu Items.
Whenever I do this my sprites appear to be scaled to the correct sizes, however it also seems to scale the CCMenu position coordinates, but in the opposite direction as what I'd expect. Also once I go over a certain threshold the menu seems to disappear altogether.
Does anyone have any suggestions on how I should be scaling Sprites in a CCMenu?
Thanks in advance.
Buzzrick
Try this Code........
CCMenuItemImage *Btn1 = [CCMenuItemImage itemWithNormalImage:#"button1.png" selectedImage:#"button1_active.png" target:self selector:#selector(button1_click:)];
CCMenuItemImage *Btn2 = [CCMenuItemImage itemWithNormalImage:#"button2.png" selectedImage:#"button2_active.png" target:self selector:#selector(button2_click:)];
CCMenu *Action_menu = [CCMenu menuWithItems:Btn1,Btn2, nil];
[Action_menu setPosition:ccp( 79, 288)];
float delayTime = 0.3f;
for (CCMenuItemFont *each in [Action_menu children])
{
each.scaleX = 0.0f;
each.scaleY = 0.0f;
CCAction *action = [CCSequence actions:
[CCDelayTime actionWithDuration: delayTime],
[CCScaleTo actionWithDuration:0.5F scale:1.0],
nil];
delayTime += 0.2f;
[each runAction: action];
}
[self addChild:Action_menu];
My suggestion? Don't!
Internally CCMenu scaled the menu items whenever you touch them. You'll notice this if you tap and hold an item, it's scaled up (zoomed in). So whatever scaling you apply to menu items is lost at the latest when the menu item gets touched.
And then, as you noticed, scaling affects the touch area of an item. It can lead to items responding to touches outside the item, or not responding to touches depending on zoom level. I also wouldn't scale the CCMenu for the same reasons.
Long story short, if you have to apply scaling to your menu items, write your own menu item code. Possibly by basing it on the CCMenu code and stripping out what you don't need and making your desired changes.
But really the easiest way is to supply the menu item images using the file suffixes -hd, -ipad and -ipadhd and scaled correspondingly. Trying to get this right with the scale property is just painful.
Here's how I resolved it in the end:
Basically I created the menu elements first, THEN I sorted out the positioning/scaling/rotation. This seems to work much better.
This code sample below is where i'm using a single sprite to create two opposing left/right arrow buttons
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ButtonSprites.plist"];
CCSpriteBatchNode *buttonSprites = [CCSpriteBatchNode batchNodeWithFile:#"ButtonSprites.png"];
[self addChild:buttonSprites];
CCSprite *arrowLeftSprite = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
CCSprite *arrowLeftSpriteSelected = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
arrowLeftSpriteSelected.opacity = 128;
CCSprite *arrowRightSprite = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
CCSprite *arrowRightSpriteSelected = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
arrowRightSpriteSelected.opacity = 128;
float buttonWidth = screenSize.width * ButtonWidthPercent;
int contentPixelWidth = arrowLeftSprite.contentSize.width;
float scale = buttonWidth / contentPixelWidth;
CCMenuItemSprite *pageLeftMenu = [CCMenuItemSprite itemFromNormalSprite:arrowLeftSprite selectedSprite:arrowLeftSpriteSelected target:self selector:#selector(buttonPageLeft:)];
CCMenuItemSprite *pageRightMenu = [CCMenuItemSprite itemFromNormalSprite:arrowRightSprite selectedSprite:arrowRightSpriteSelected target:self selector:#selector(buttonPageRight:)];
// First perform the creation
CCMenu *menu = [CCMenu menuWithItems: mainMenu, pageLeftMenu, pageRightMenu, nil];
menu.position = ccp(0, 0);
// THEN deal with layout,rotation, and scaling
pageLeftMenu.scale = scale;
pageLeftMenu.rotation = 180;
pageRightMenu.scale = scale;
float arrowHeight = screenSize.height * 0.2;
pageLeftMenu.position = ccp(screenSize.width * 0.1, arrowHeight);
pageRightMenu.position = ccp(screenSize.width * 0.9, arrowHeight);
[self addChild:menu z:2];