TouchesBegan recognised in next view controller - ios

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
NSLog(#"touch recognised");
CGPoint location = [aTouch locationInView:_mainView];
__block NSString *option = [[NSString alloc] init];
__block NSString *type = [[NSString alloc] init];
for (Selectors *tempView in _mainView.subviews) {
if (CGRectContainsPoint(tempView.frame, location)) {
NSLog(#"%# : %#", tempView.option, tempView.type);
option = tempView.option;
type = tempView.type;
break;
}
}
[self moveToNextWeldCustomViewWithOption:option andType:type];
}
Is in my previous UIVIewController - then we present the next UIViewController here
-(void)moveToNextWeldCustomViewWithOption:(NSString *)option andType:(NSString *)type {
WeldDesignViewController *lobby = [self.storyboard instantiateViewControllerWithIdentifier:#"WeldDesignViewController"];
lobby.option = option;
lobby.type = type;
[self presentViewController:lobby animated:NO completion:nil];
}
In the next UIViewController I don't do anything until the viewDidAppear method - However, the touches began is still being recognised in the next viewcontroller.

I think the issue is that the VC you are calling "lobby" is being deallocated after you present it. This takes it out of consideration in the responder chain. Move that reference to be a property of the presenting view controller:
#property (nonatomic, strong) WeldDesignViewController* lobby;
// ...
-(void)moveToNextWeldCustomViewWithOption:(NSString *)option andType:(NSString *)type {
self.lobby = [self.storyboard instantiateViewControllerWithIdentifier:#"WeldDesignViewController"];
lobby.option = option;
lobby.type = type;
[self presentViewController:self.lobby animated:NO completion:nil];
}
You may also need to implement touchesBagan in the presented VC, as it is probably following the responder chain to the previous controller.

Related

How to show leaderboard in iOS 7

I am using sprite-kit and targeted iOS 7. I want to show leaderboard with button in my MenuScene.
my helper method codes.
#import "GameKitHelper.h"
NSString *const PresentAuthenticationViewController =
#"present_authentication_view_controller";
#interface GameKitHelper()<GKGameCenterControllerDelegate>
#end
#implementation GameKitHelper {
BOOL _enableGameCenter;
}
+ (instancetype)sharedGameKitHelper
{
static GameKitHelper *sharedGameKitHelper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGameKitHelper = [[GameKitHelper alloc] init];
});
return sharedGameKitHelper;
}
- (id)init
{
self = [super init];
if (self) {
_enableGameCenter = YES;
}
return self;
}
- (void)showGKGameCenterViewController:
(UIViewController *)viewController
{
if (!_enableGameCenter) {
NSLog(#"Local play is not authenticated");
}
GKGameCenterViewController *gameCenterViewController =
[[GKGameCenterViewController alloc] init];
gameCenterViewController.gameCenterDelegate = self;
gameCenterViewController.viewState =
GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterViewController
animated:YES
completion:nil];
}
I want to Leaderboard Button in this class.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"start"]) {
MyScene *myScene = [MyScene sceneWithSize:self.size];
[self.view presentScene:myScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
if ([node.name isEqualToString:#"gameCenter"]) {
//HERE MY LEADERBOARD BUTTON ACTION
//I don't know what i write here...
{
}
I tried so much methods but these working in iOS 6, I targeted iOS 7.
I tried this:
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:self]; Xcode says for self
Incompatible pointer types sending 'GameMenuScene *' to parameter of type 'UIViewController *'
Andrey is right. gameKitHelper means [gameKitHelper sharedGameKitHelper]. like this example
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
Keep coding :)
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
But actually you should present another ViewController from your ViewController, not from SKScene
Try this, it's easy to implement and works well:
https://github.com/nihalahmed/GameCenterManager
inside viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(openLeaderboard)
name:#"TestNotification"
object:nil];
Inside VC:
- (void) openLeaderboard
{
// Open Leaderboards here
}
In your Scene:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];

UIKit Dynamics in a Custom Segue

I'm trying to make a view fall as a custom segue transition, but when the perform method is called in the UIStoryboardSegue implementation, it does not fall. I have tried moving the view to be dropped into the source's view to see if it does anything, but it doesn't.
-(void)perform {
UIViewController *src = (UIViewController *)self.sourceViewController;
UIViewController *dest = (UIViewController *)self.destinationViewController;
UIView *viewdrop = [dest.view snapshotViewAfterScreenUpdates:YES];
viewdrop.frame = CGRectMake(0, -src.view.frame.size.height, dest.view.frame.size.width, dest.view.frame.size.height);
[src.view addSubview:viewdrop];
animator = [[UIDynamicAnimator alloc] initWithReferenceView:src.view];
UIGravityBehavior* gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[viewdrop]];
[animator addBehavior:gravityBehavior];
}
The reason it doesn't drop is because the gravity behavior takes time, but the segue itself is deallocated as soon as the perform method finishes. So, you need a way to keep the segue alive at least until the movement is complete. One way to do this is to make a strong property for the segue in the source view controller, and set its value in prepareForSegue,
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.dropSegue = segue;
}
I made a modified version of your segue that also adds a collision behavior, and sets the source view controller as the delegate of the collision behavior, so I can use the delegate method, collisionBehavior:endedContactForItem:withBoundaryIdentifier:, to set the dropSegue property to nil (after a slight delay) which causes the segue to be deallocated,
-(void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier {
NSLog(#"collision ended with %#", identifier);
[self performSelector:#selector(setDropSegue:) withObject:nil afterDelay:1];
}
Here is my version of the gravity drop segue,
#interface RDSegue ()
#property (strong, nonatomic) UIDynamicAnimator *animator;
#end
#implementation RDSegue
-(id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {
if (self = [super initWithIdentifier:identifier source:source destination:destination]) {
UIViewController *src = self.sourceViewController;
UIViewController *dest = self.destinationViewController;
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:src.view];
[src addChildViewController:dest];
[dest didMoveToParentViewController:src];
dest.view.frame = CGRectMake(0, -src.view.bounds.size.height, src.view.bounds.size.width, src.view.bounds.size.height);
[src.view addSubview:dest.view];
}
return self;
}
-(void)perform {
UIGravityBehavior* gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[[self.destinationViewController view]]];
UICollisionBehavior *collide = [[UICollisionBehavior alloc] initWithItems:#[[self.destinationViewController view]]];
CGPoint left = CGPointMake(self.animator.referenceView.bounds.origin.x, self.animator.referenceView.bounds.origin.y + self.animator.referenceView.bounds.size.height);
CGPoint right = CGPointMake(self.animator.referenceView.bounds.origin.x + self.animator.referenceView.bounds.size.width, self.animator.referenceView.bounds.origin.y + self.animator.referenceView.bounds.size.height);
[collide addBoundaryWithIdentifier:#"bottom" fromPoint:left toPoint:right];
[collide setCollisionDelegate:self.sourceViewController];
[self.animator addBehavior:gravityBehavior];
[self.animator addBehavior:collide];
}
-(void)dealloc {
NSLog(#"In dealloc");
}

How do I present a UIViewController from SKScene?

I'm entering iOS via Sprite Kit, which I recognize is unwise.
My goal is to display a "Share" button upon Game Over. Tapping the share button should present a SLComposeViewController (Twitter Share). The contents of the scene should not change.
The game logic that dictates "Game Over" lives in SpriteMyScene.m, a subclass of SKScene.
I'm able to display a Share button on Game Over this way:
-(void)update:(CFTimeInterval)currentTime {
if (gameOver){
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(sendToController)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
}
- (void)sendToController
{
NSLog(#"ok");
SpriteViewController *viewController = [SpriteViewController alloc];
[viewController openTweetSheet];
}
Where I get stuck is trying to get the showTweetButton method to work. My SpriteViewController.m looks like this:
- (void)openTweetSheet
{
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:
SLServiceTypeTwitter];
// Sets the completion handler. Note that we don't know which thread the
// block will be called on, so we need to ensure that any required UI
// updates occur on the main queue
tweetSheet.completionHandler = ^(SLComposeViewControllerResult result) {
switch(result) {
// This means the user cancelled without sending the Tweet
case SLComposeViewControllerResultCancelled:
break;
// This means the user hit 'Send'
case SLComposeViewControllerResultDone:
break;
}
};
// Set the initial body of the Tweet
[tweetSheet setInitialText:#"just setting up my twttr"];
// Adds an image to the Tweet. For demo purposes, assume we have an
// image named 'larry.png' that we wish to attach
if (![tweetSheet addImage:[UIImage imageNamed:#"larry.png"]]) {
NSLog(#"Unable to add the image!");
}
// Add an URL to the Tweet. You can add multiple URLs.
if (![tweetSheet addURL:[NSURL URLWithString:#"http://twitter.com/"]]){
NSLog(#"Unable to add the URL!");
}
// Presents the Tweet Sheet to the user
[self presentViewController:tweetSheet animated:NO completion:^{
NSLog(#"Tweet sheet has been presented.");
}];
}
I always get something like this in the logs:
-[UIView presentScene:]: unrecognized selector sent to instance 0x13e63d00 2013-10-17 18:40:01.611 Fix[33409:a0b] * Terminating app
due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIView presentScene:]: unrecognized selector sent to instance
0x13e63d00'
You're creating a new view controller but never presenting it:
SpriteViewController *viewController = [SpriteViewController alloc];
I'm assuming that SpriteViewController is what presents your SpriteMyScene, and you'd like to hand control back to the presenting SpriteViewController.
You need to keep a reference to SpriteViewController in your SpriteMyScene subclass, and then access that reference when you call openTweetSheet.
in SpriteMyScene.h
#class SpriteViewController;
#interface SpriteMyScene : SKScene
#property (nonatomic, weak) SpriteViewController *spriteViewController;
#end
in SpriteViewController.m
// somewhere you initialize your SpriteMyScene object, I'm going to call it myScene
myScene.spriteViewController = self;
in SpriteMyScene.m
#import "SpriteViewController.h"
- (void)sendToController
{
NSLog(#"ok");
// use the already-created spriteViewController
[_spriteViewController openTweetSheet];
}
You can use
UIViewController *vc = self.view.window.rootViewController;
This code will give you the access to your root View controller so you can do anything you do will your view controller like normal.
However, do you need to add a button? Use a sprite and add an event to it is better for you in this case. Just call:
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
And
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
}
}
}
If you want to open another UIViewController from inside your scene, you have to first create a delegate in the primary View Controller that originally created this scene so your scene can notify its ViewController of an open tweet action. You will need following steps:
Define a delegate in the primary View Controller - the view controller of our scene, to handle the open tweet action.
Implement the delegate method in the primary View Controller
Add a delegate property in your scene so it can keep a handle to its ViewController's delegate method implementation. Set this delegate as the primary View Controller during the creation of the scene
Detect an event on the scene to call the delegate method of the primary ViewController
In the delegate method implementation pass the control to the TweetSheetViewController
Here's the example:
#protocol ViewControllerDelegate <NSObject>
-(void) openTweetSheet;
#end
Extend this ViewController to support this protocol in its .h file
#interface ViewController : UIViewController<ViewControllerDelegate>
#end
Then in the .m file implement the method from the protocol
-(void) openTweetSheet{
TweetSheetViewController *ctrl = [[TweetSheetViewController alloc] initWithNibName:#"TweetSheetViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
In your Scene header class, add a delegate property
#interface MyScene : SKScene {
}
#property (nonatomic, weak) id <ViewControllerDelegate> delegate;
#end
In the ViewController, before presenting the scene set its delegate in viewDidLoad method:
// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
Now your Scene can pass the message back to its ViewController and the ViewController can open another ViewController. In your scene class, determine the action which will trigger the opening up of TweetSheetViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKAction *fadeOut = [SKAction fadeOutWithDuration:0.5];
SKAction *fadeIn = [SKAction fadeInWithDuration:1.0];
SKAction *sequence = [SKAction sequence:#[fadeOut,fadeIn]];
SKNode *node = [self nodeAtPoint:location];
if ([[node name] isEqual: #"openTweet"]) {
NSLog(#"help");
[node runAction:sequence];
[delegate openTweetSheet];
}
}
Hope that helps.
Write the SlComposeViewController Method in the scene you want it to take place. For example:
#interface GameOverScene: SKScene
...initwithsize bla bla bla
...
Add these methods:
-(void)OpenTweetShet{
if ([SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]) {
_composeTwitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[_composeTwitter setInitialText:#"TWEET"];
Then call:
self.view.window.rootViewController **to present the SLComposeViewController**
[self.view.window.rootViewController presentViewController:_composeTwitter animated:YES completion:nil];
}
[_composeTwitter setCompletionHandler:^(SLComposeViewControllerResult result){
NSString *output =[[NSString alloc]init];
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Post cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Succesfull";
break;
default:
break;
}
Here is the option for presenting UIAlert after the send/cancel post:
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Twitter" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}];
}
#end
This worked for me: self.view.window.rootViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[self.view.window.rootViewController openTweetSheet];
}
}
}

Making a button persistent across all view controllers

I want to have a persistent button in the bottom right corner of my app. During all view transitions, the button should remain static. I'm having trouble deciding what view to add the button to. I know the button ought to be stored in the AppDelegate, but I don't know what other view it would be sense to add it to except the window. One downside of adding it to the window is that when there's an app running in the background (ie Phone), the added status bar padding will push down the window. In general, adding it to the window seems to be a hacky solution -- any thoughts?
Yes, adding it to the UIWindow would be extremely hacky and finicky.
Storyboards
If you're using Storyboards and iOS 5.0 onwards, you should be able to use container views and do something like this:
Here's another picture showing the, rather simplistic, structure of the first View Controller:
The view controller on the left has a container, and then a view which holds the button on top of it. The container indicates that the navigation controller (directly to the right) should appear within itself, that relationship is shown by the =([])=> arrow (formally known as an embed segue). Finally the navigation controller defines its root view controller to the one on the right.
In summary, the first view controller pancakes-in the container view with the button on top, so everything that happens inside has to have the button on top.
Using childViewControllers
aka. The "I hate Storyboards and puppies" mode
Using a similar structure to the Storyboard version, you could create the base view controller with its button, and then, add the view that will become then new "root" of the application, underneath.
To make it clear, let's call the one view controller that holds the button the FakeRootViewController, and the view controller that will be, for all practical purposes, the root of the application: RootViewController. All subsequent view controllers won't even know that there's the FakeRootViewController above everyone else.
FakeRootViewController.m
// The "real" root
#import "RootViewController.h"
// Call once after the view has been set up (either through nib or coded).
- (void)setupRootViewController
{
// Instantiate what will become the new root
RootViewController *root = [[RootViewController alloc] <#initWith...#>];
// Create the Navigation Controller
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:root];
// Add its view beneath all ours (including the button we made)
[self addChildViewController:nav];
[self.view insertSubview:nav.view atIndex:0];
[nav didMoveToParentViewController:self];
}
AppDelegate.m
#import "FakeRootViewController.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FakeRootViewController *fakeRoot = [[FakeRootViewController alloc] <#initWith...#>];
self.window.rootViewController = fakeRoot;
[self.window makeKeyAndVisible];
return YES;
}
That way, you can have all the benefits of inserting the button on the window, without all the guilt and "Should I really be a programmer?" that it causes.
Potentially you could have 1 main "root" view controller, and all you other view controllers could be child view controllers, with their views as child views. Then they would have their content, and the button would be in the "root" view controller. But this seems just as sketchy and hacky as putting it in the window, and probably less convenient.
I use this button:
#interface UIPopUpButton : UIImageView <UIPopoverControllerDelegate, UIActionSheetDelegate>
{
UIPopoverController* popoverController;
Class popoverClass;
}
- (id) initWithPoint: (CGPoint) point;
- (void) touchesBegan: (NSSet*) touches
withEvent: (UIEvent*) event;
+ (id) buttonAtPoint: (CGPoint) point;
+ (id) buttonAtOriginalPoint;
+ (void) unhighlight;
+ (void) bringButtonToFront;
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, assign) Class popoverClass;
#end
#import "UIPopUpButton.h"
#implementation UIPopUpButton
static UIPopUpButton* button = nil;
static CGPoint originalPoint;
#synthesize popoverClass;
#synthesize popoverController;
+ (id) buttonAtPoint: (CGPoint) point
{
if (button == nil)
{
button = [[UIPopUpButton alloc] initWithPoint: point];
originalPoint = point;
button.popoverClass = [UIPopoverController class];
}
else
{
button.frame = CGRectMake(point.x, point.y, button.frame.size.width, button.frame.size.height);
}
return button;
}
+ (id) buttonAtOriginalPoint
{
return [self buttonAtPoint: originalPoint];
}
+ (void) unhighlight
{
button.highlighted = NO;
}
+ (void) bringButtonToFront
{
[[UIApplication sharedApplication].keyWindow addSubview: [self buttonAtOriginalPoint]];
}
- (id) initWithPoint: (CGPoint) point
{
UIImage* image1 = [UIImage imageNamed: #"topbutton.png"];
UIImage* image2 = [UIImage imageNamed: #"topbutton.png"];
if ((self = [super initWithImage: image1
highlightedImage: image2]))
{
self.userInteractionEnabled = YES;
self.frame = CGRectMake(point.x, point.y, self.frame.size.width, self.frame.size.height);
self.multipleTouchEnabled = NO;
}
return self;
}
- (BOOL) isAppCurrStatus
{
return ([DevToolsClientController sharedInstance].statusOfRootViewController == FrontEndApplication);
}
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
if(touch.view == self)
{
if (self.popoverController == nil)
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle: #"Please choice operation:"
delegate: self
cancelButtonTitle: nil
destructiveButtonTitle: nil
otherButtonTitles: nil];
[actionSheet addButtonWithTitle: #"Cancel"];
actionSheet.cancelButtonIndex = 0;
[actionSheet addButtonWithTitle: #"Button 1"];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet setTag: 0];
[actionSheet setDelegate: self];
[actionSheet showInView: [self superview]];
[actionSheet release];
[actions release];
}
else
{
PopoverMenuController* contentViewController = [[PopoverMenuController alloc] init];
self.popoverController = [[UIPopoverController alloc] initWithContentViewController: contentViewController];
popoverController.delegate = self;
[popoverController presentPopoverFromRect: CGRectMake(10.0f, 10.0f, 5.0f, 5.0f)
inView: self
permittedArrowDirections: UIPopoverArrowDirectionAny
animated: YES];
contentViewController.popoverController = self.popoverController;
[contentViewController reloadData];
}
}
else
{
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
[super touchesBegan: touches withEvent: event];
}
#pragma mark UIActionSheetDelegate implementation
-(void) actionSheet: (UIActionSheet*) actionSheet clickedButtonAtIndex: (NSInteger) buttonIndex
{
NSNumber* indexAction = [[NSNumber alloc] initWithInt: buttonIndex - 1];
}
- (void) runAction: (NSNumber*) indexAction
{
[DevToolsPopoverMenuController runAction: [indexAction integerValue]];
}
#pragma mark -
#pragma mark UIPopoverControllerDelegate implementation
- (void) popoverControllerDidDismissPopover: (UIPopoverController*) thePopoverController
{
if (self.popoverController != nil)
{
self.popoverController = nil;
}
}
- (BOOL) popoverControllerShouldDismissPopover: (UIPopoverController*) thePopoverController
{
//The popover is automatically dismissed if you click outside it, unless you return NO here
return YES;
}
#end
call:
[UIPopUpButton bringButtonToFront];
My button is always on top.
Try subclassing the UIViewController class and make your own one with the button
Create a singleton object that holds the button so all view controllers can reference it and add it to their subview or add it to the window directly.
SomeClass.h
#property (nonatomic) UIButton *yourButton;
+(SomeClass*)sharedSomeClass;
SomeClass.m
#synthesize yourButton = _yourButton;
-(id)init
{
self = [super init];
if(self)
{
_yourButton = [UIButton new];
//Other settings you want for your button
}
return self;
}
+(SomeClass)sharedSomeClass
{
static SomeClass *sharedSomeClass;
if (!sharedSomeClass)
sharedSomeClass = [[super allocWithZone:nil]init];
return sharedSomeClass;
}
+(void)allocWithZone:(NSZone*)zone
{
return [self sharedSomeClass];
}
If you like you can access the window directly like this:
UIWindow *mainwindow = [[[UIApplication sharedApplication]delegate]window];
import SomeClass.h into your view controllers, and access the button from anywhere
#import "SomeClass.h"
SomeClass *someClass = [SomeClass sharedSomeclass];
UIButton *localButton = someClass.yourButton;

Why is an init method of a child not called by a parent allocating that child in cocos2d v2.0?

I have this Class:
//Interface
#interface SavingDataPlist : SimpleTimedGameRecipe
{
NSMutableArray *moles;
int tagCount;
int moleCount;
CCSprite *mallet;
CGPoint malletPosition;
}
-(CCLayer*) runRecipe;
-(void) step;
-(void) initBackground;
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z;
-(void) processMoleHit;
-(void) addHiScoresToMenu;
-(void) loadHiScores;
-(void) addHiScore;
-(void) deleteHiScores;
-(void) startNewGame;
-(void) gameOver;
-(void) step:(ccTime)delta;
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
which in its reunRecipe method calls this:
[self createMoleAtPosition:ccp(50,205) withZ:0];
and that call corresponds to this method:
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z {
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSprite *back = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_back.png"]];
back.position = ccp(point.x, point.y);
[self addChild:back z:z tag:tagCount];
tagCount++;
Mole *mole = [Mole spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_normal.png"]];
[mole setDownPosition:ccp(point.x,point.y-30)];
[self addChild:mole z:z tag:tagCount];
[moles addObject:mole];
NSLog(#"moles.count %d", moles.count);
tagCount++;
CCSprite *front = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_front.png"]];
front.position = ccp(point.x, point.y);
[self addChild:front z:z tag:tagCount];
tagCount++;
}
The Mole Class init method looks like this:
-(id)init {
NSLog(#"moleinit");
self = [super init];
if (self != nil) {
state = MOLE_DOWN;
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
//
//MEVPCHANGE
//Create framenumber array to populate ccanimation later
NSMutableArray *animationFramesArray = [[NSMutableArray alloc] init];
NSMutableArray *animationFramesArray2 = [[NSMutableArray alloc] init];
//MEVPCHANGE - add frames to array
[animationFramesArray addObject:[cache spriteFrameByName:#"mole_normal.png"]];
[animationFramesArray2 addObject:[cache spriteFrameByName:#"mole_hit.png"]];
normalAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray delay:1.0f];
hitAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray2 delay:1.0f];
//MEVPCHANGE - create animation
[animationFramesArray release];
[animationFramesArray2 release];
//
[self runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:normalAnim]]];
}
return self;
}
Now in cocos2d v1.0 this code works fine. The Mole's get created and they pop up and down when they get whacked. But in v2.0, I only get the front facing moles but the NSLog in the Mole init method doesnt even get called (as evidenced by the lack of NSLog in the console).

Resources