I'm trying to change from gamePlayscene to a GameOverScene, but when the simulator tries to changes the scene, the simulator stops but I don't receive any message in the Log.
GameOverScene.h
#interface GameOverScene : CCScene {
GameOverScene *scene;
//screen size
float winWidth;
float winHeight;
//Game vars
int score;
//Facebook vars
FBSession* session;
NSString *messageStr;
NSString *userid;
}
+ (GameOverScene *)scene;
- (id)init;
#end
GameOverScene.m
#implementation GameOverScene {
}
+ (GameOverScene *)scene
{
return [[self alloc] init];
}
// -----------------------------------------------------------------------
- (id)init
{
if( (self=[super init] )) {
NSLog(#"define tamanho da tela");
winWidth = self.contentSize.width;
winHeight = self.contentSize.height;
NSLog(#"define botao");
// Facebook login button
CCButton *fbLoginButton = [CCButton buttonWithTitle:#"Login with FB" fontName:#"Verdana-Bold" fontSize:30.0f];
fbLoginButton.position = ccp(winWidth/2, winHeight/2);
[fbLoginButton setTarget:self selector:#selector(fbLoginClicked:)];
[self addChild:fbLoginButton];
}
}
I'm calling the GameOverScene this way:
[[CCDirector sharedDirector] replaceScene:[GameOverScene scene]
withTransition:[CCTransition transitionFadeWithDuration:1.0f]];
put "return self" in the -(id)init method after the if block.
Related
Ok, I am going crazy here. I am using Xcode 6.4 and I also tried new 7 beta 3.
What happens is that anything (for example BOOL) that i declare as a global variable can't be seen by certain methods/functions.
-(void)loadView can see it no problem but
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error and some others can't.
I know that globals are dangerous but please let me know what I am doing wrong. Thanks!
my h file:
#interface BannerViewController : UIViewController
{
BOOL isInternetActive;
}
m file:
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
isInternetActive = NO; //it doesn't compile because of this. Error is "Use of undeclared identifier 'isInternetActive'
}
EDITED to show entire h and m file:
h file:
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
//#import <GoogleMobileAds/GoogleMobileAds.h> //Google
#import GoogleMobileAds;
extern NSString * const BannerViewActionWillBegin;
extern NSString * const BannerViewActionDidFinish;
#interface TestBannerViewController : UIViewController
{
GADBannerView *admobBannerView;
}
#property (nonatomic) BOOL isInternetActive;
- (instancetype)initWithContentViewController:(UIViewController *)contentController;
#end
m file:
#import "TestBannerViewController.h"
//#import <GoogleMobileAds/GoogleMobileAds.h> //Google
#import GoogleMobileAds;
NSString * const BannerViewActionWillBegin = #"BannerViewActionWillBegin";
NSString * const BannerViewActionDidFinish = #"BannerViewActionDidFinish";
#interface TestBannerViewController ()
// This method is used by BannerViewSingletonController to inform instances of TestBannerViewController that the banner has loaded/unloaded.
- (void)updateLayout;
#end
#interface BannerViewManager : NSObject <ADBannerViewDelegate>
#property (nonatomic, readonly) ADBannerView *bannerView;
//#property (nonatomic, weak) GADBannerView *admobBannerView; //Google
+ (BannerViewManager *)sharedInstance;
- (void)addBannerViewController:(TestBannerViewController *)controller;
- (void)removeBannerViewController:(TestBannerViewController *)controller;
#end
#implementation TestBannerViewController {
UIViewController *_contentController;
}
#synthesize isInternetActive;
- (instancetype)initWithContentViewController:(UIViewController *)contentController
{
NSAssert(contentController != nil, #"Attempting to initialize a BannerViewController with a nil contentController.");
self = [super init];
if (self != nil) {
_contentController = contentController;
[[BannerViewManager sharedInstance] addBannerViewController:self];
}
return self;
}
- (void)dealloc
{
[[BannerViewManager sharedInstance] removeBannerViewController:self];
}
- (void)loadView
{
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Setup containment of the _contentController.
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
NSLog(#"Google Mobile Ads SDK version: %#", [GADRequest sdkVersion]);
self.view = contentView;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [_contentController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
#endif
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [_contentController preferredInterfaceOrientationForPresentation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [_contentController supportedInterfaceOrientations];
}
- (void)viewDidLayoutSubviews
{
CGRect contentFrame = self.view.bounds, bannerFrame = CGRectZero;
ADBannerView *bannerView = [BannerViewManager sharedInstance].bannerView;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
NSString *contentSizeIdentifier;
if (contentFrame.size.width < contentFrame.size.height) {
contentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
} else {
contentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
}
bannerFrame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSizeIdentifier];
#else
bannerFrame.size = [bannerView sizeThatFits:contentFrame.size];
#endif
if (bannerView.bannerLoaded) {
contentFrame.size.height -= bannerFrame.size.height;
bannerFrame.origin.y = contentFrame.size.height;
} else {
//contentFrame.size.height -= bannerFrame.size.height;
bannerFrame.origin.y = contentFrame.size.height;
}
_contentController.view.frame = contentFrame;
if (self.isViewLoaded && (self.view.window != nil)) {
[self.view addSubview:bannerView];
bannerView.frame = bannerFrame;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
bannerView.currentContentSizeIdentifier = contentSizeIdentifier;
#endif
}
}
- (void)updateLayout
{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.view addSubview:[BannerViewManager sharedInstance].bannerView];
}
- (NSString *)title
{
return _contentController.title;
}
#end
#implementation BannerViewManager {
ADBannerView *_bannerView;
NSMutableSet *_bannerViewControllers;
}
+ (BannerViewManager *)sharedInstance
{
static BannerViewManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[BannerViewManager alloc] init];
});
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (self != nil) {
if ([ADBannerView instancesRespondToSelector:#selector(initWithAdType:)]) {
_bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
} else {
_bannerView = [[ADBannerView alloc] init];
}
_bannerView.delegate = self;
_bannerViewControllers = [[NSMutableSet alloc] init];
}
return self;
}
- (void)addBannerViewController:(TestBannerViewController *)controller
{
[_bannerViewControllers addObject:controller];
}
- (void)removeBannerViewController:(TestBannerViewController *)controller
{
[_bannerViewControllers removeObject:controller];
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
for (TestBannerViewController *bvc in _bannerViewControllers) {
[bvc updateLayout];
}
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
for (TestBannerViewController *bvc in _bannerViewControllers) {
[bvc updateLayout];
}
isInternetActive = YES;
}
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
[[NSNotificationCenter defaultCenter] postNotificationName:BannerViewActionWillBegin object:self];
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
[[NSNotificationCenter defaultCenter] postNotificationName:BannerViewActionDidFinish object:self];
}
#end
You can create new header file in your project.
In that you can write like this :
static BOOL isInternetActive;
Import this header file where you want to access this bool value.
Hope this helps.
I think I got it. in the m file there are two #implementation files (two classes?) and that is why when declaring global in the h file the last class can't see it.
I have two layers set up like so in one scene:
header file for scene:
#interface GameScene1 : CCScene {
GameLayer *gameLayer;
HUDLayer *hudLayer;
}
Main file for scene:
-(id)init {
self = [super init];
if (self != nil) {
gameLayer = [GameLayer node];
[self addChild:gameLayer];
hudLayer = [HUDLayer node];
[self addChild:hudLayer];
}
return self;
}
HUD layer header:
#interface HUDLayer : CCNode {
CCSprite *background;
CGSize screenSize;
}
-(void)updateMonstersSlayed:(NSString*)value;
HUD layer main:
#implementation HudLayer
-(id)init
{
self = [super init];
if (self)
{
CGSize viewSize = [[CCDirector sharedDirector] viewSize];
monstersSlayed = [CCLabelTTF labelWithString:#"Monsters Killed: 0" fontName:#"Arial" fontSize:15];
monstersSlayed.position = ccp(viewSize.width * 0.85, viewSize.height * 0.1 );
[self addChild:monstersSlayed];
}
return self;
}
-(void)updateMonstersSlayed:(NSString*)value
{
monstersSlayed.string = value;
}
Game Layer main
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair collisionPlayer:(CCNode *)user collisionMonster:(CCNode *)monster
{
if (holdingWeapon)
{
HudLayer *myHud = [[HudLayer alloc] init];
[myHud updateMonstersSlayed:#"Monsters Killed: 1"];
}
}
Simply trying to get it set to where I can set text from the Game Layer to show up in a Label in the Hud Layer.
How would I accomplish this in Cocos2d 3?
There are many ways you can do this. But for the sake of simplicity the easiest way you can do this is via notifications. For example in the hud add:
#implementation HudLayer
- (void)onEnter
{
[super onEnter];
NSNotificationCenter* notiCenter = [NSNotificationCenter defaultCenter];
[notiCenter addObserver:self
selector:#selector(onUpdateMonsterText:)
name:#"HudLayerUpdateMonsterTextNotification"
object:nil];
}
- (void)onExit
{
[super onExit];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)onUpdateMonsterText:(NSNotification *)notification
{
NSDictionary* userInfo = notification.userInfo;
if (userInfo)
{
NSString* text = userInfo[#"text"];
if (text)
{
[self updateMonstersSlayed:text];
}
else
{
CCLOG(#"Monster hud text param is invalid!.");
}
}
else
{
CCLOG(#"Monster hud user info invalid!");
}
}
#end
Then anywhere in your application where you want to update text you can just post the notification. Using your physics collision began example:
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair
*emphasized text*collisionPlayer:(CCNode *)user collisionMonster:(CCNode *)monster
{
if (holdingWeapon)
{
NSDictionary* userInfo = #{#"text" : #"Monsters Killed: 1"};
NSString* notiName = #"HudLayerUpdateMonsterTextNotification";
[[NSNotificationCenter defaultCenter] postNotificationName:notiName
object:self userInfo:userInfo];
}
}
Hope this helps.
You can use methods. Make a method in HUD layer class.
-(void) giveMeMyText:(NSString*)someText
{
do something with my someText
}
Don't forget to make the method visible in HUD.h -(void) giveMeMyText; Then import HUD layer class in GameScene1 #import "HUDlayer.h" and use it.
HUDLayer* myHud = [[HUDLayer alloc] init];
[myHud giveMeMyText:#"say hi!"];
You could use delegation, so your scene would implement GameLayerProtocol and the delegate of GameLayer. That way the scene would be notified of any changes the GameLayer has and act appropriately on the HudLayer.
For example:
// GameLayer class
#protocol GameLayerProtocol <NSObject>
- (void)someThingHappenedInGameLayer;
#end
#interface GameLayer : CCNode
#property (nonatomic, weak) id<GameLayerProtocol> delegate;
#end
#implementation GameLayer
- (void)someActionInGameLayer
{
[self.delegate someThingHappenedInGameLayer];
}
#end
// Scene class
#interface IntroScene : CCScene <GameLayerProtocol>
#end
#implementation IntroScene
// Implement protocol methods
- (void)someThingHappenedInGameLayer
{
//Do something with your HUDLayer here
}
#end
I've setup a delegate to take the old and new position of a gauge. However, I can't seem to get a response from the delegate. I could be missing something but I've done a bunch of research and it seems like everything is in order.
MeterView.h
#import <UIKit/UIKit.h>
#import "KTOneFingerRotationGestureRecognizer.h"
#protocol MeterViewDelegate;
#interface MeterView : UIView{
IBOutlet UIImageView *gauge;
IBOutlet UIImageView *needle;
float rotation, oldPos, newPos;
KTOneFingerRotationGestureRecognizer *rgest;
}
#property (nonatomic, weak) id<MeterViewDelegate> delegate;
- (IBAction)handleMovedNeedle;
#end
#protocol MeterViewDelegate <NSObject>
- (void)meterView:(MeterView*)view OldValue:(float)oldval NewValue:(float)newval;
#end
MeterView.m
#import "MeterView.h"
#import <QuartzCore/QuartzCore.h>
#implementation MeterView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(void)handleMovedNeedle{
if ([self.delegate respondsToSelector:#selector(meterView:OldValue:NewValue:)]) {
[self.delegate meterView:self OldValue:oldPos NewValue:newPos];
}
else{
NSLog(#"Delegate call FAIL, needle moved from %f, to %f", oldPos,newPos);
}
}
-(void)awakeFromNib{
gauge = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gauge.png"]];
needle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"needle.png"]];
needle.frame = CGRectMake(0,gauge.frame.size.height-(needle.frame.size.height/2), gauge.frame.size.width, needle.frame.size.height);
[self addSubview:gauge];
[self addSubview:needle];
rotation = 0;
rgest = [[KTOneFingerRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
rgest.center = CGPointMake(CGRectGetMidX([needle bounds]) + needle.frame.origin.x, CGRectGetMidY([needle bounds]) + needle.frame.origin.y);
[self addGestureRecognizer:rgest];
}
- (void)rotate:(UIRotationGestureRecognizer *)recognizer {
switch (recognizer.state) {
case UIGestureRecognizerStateBegan: {
oldPos = ([(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue]/3.14)*100;
}
break;
case UIGestureRecognizerStateChanged: {
CGFloat angle = [(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue];
angle += [recognizer rotation];
if (angle >= 0 && angle <= M_PI) {
[needle setTransform:CGAffineTransformRotate([needle transform], [recognizer rotation])];
rotation += [recognizer rotation];
}
}
break;
case UIGestureRecognizerStateEnded: {
newPos = ([(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue]/3.14)*100;
[self handleMovedNeedle];
}
break;
default:
break;
}
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "MeterView.h"
#import "KTOneFingerRotationGestureRecognizer.h"
#interface ViewController : UIViewController<MeterViewDelegate>{
IBOutlet MeterView *secondMeter;
IBOutlet MeterView *thirdMeter;
}
#end
ViewController.m
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#define DEG2RAD(degrees) (degrees * 0.01745327) // degrees * pi over 180
#define RAD2DEG(radians) (radians * 57.2957795) // radians * 180 over pi
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
secondMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
secondMeter.delegate = self;
thirdMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
thirdMeter.delegate =self;
}
-(void)meterView:(MeterView *)view OldValue:(float)oldval NewValue:(float)newval{
NSLog(#"Delegate call SUCCESS, need moved from %f, to %f", oldval,newval);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This code:
secondMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
secondMeter.delegate = self;
thirdMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
thirdMeter.delegate =self;
creates 2 instances of your view, but it doesn't add them to a view, so they will never be seen.
So, you probably have some other view instances that are on view and don't have delegates, and these views which have delegates but aren't on display. Presumably from an XIB / storyboard as you have outlets.
Connect the views that are on display to the delegate using the outlets rather than creating new instances.
If you make the delegate property in the view an IBOutlet itself then you can connect the view controller as the delegate in the XIB / storyboard and you don't need to worry about the delegate in code at all...
I am trying to create a long press gesture that presents a second view controller, once the press has been held for 3 seconds. However, I only want the second view controller presented if the device is in a certain accelerometer orientation for the ENTIRE 3 seconds. That is, if the gesture is not held long enough or the device is tilted too much, the gesture is dismissed and the user must try again.
// In FirstViewController.h
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
#interface FirstViewController : UIViewController
#property (nonatomic, strong) CMMotionManager *motionManager;
#end
// In FirstViewController.m
#import "FirstViewController"
#import "SecondViewController"
#implementation motionManager;
- (void) viewDidLoad
{
[super viewDidLoad];
self.motionManager = [[CMMotionManager alloc]init];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 3.0;
[self.view addGestureRecognizer:longPress];
}
- (void) handleLongPress: (UILongPressGestureRecognizer *)sender
{
// Not sure what to do here
}
I have previously tried chunks of code in the last method but it looks obnoxious and just is not correct. Instead, I have listed several lines of code below that I know work individually, but I need assistance in making them all work together.
// Accelerometer
if ([self.motionManager isAccelerometerAvailable])
{
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData,NSError *error)
{
if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
{
NSLog(#"Correct Orientation!!!");
[self.motionManager stopAccelerometerUpdates];
}
else
{
NSLog(#"Incorrect orientation!!!");
[self.motionManager stopAccelerometerUpdates];
}];
}
else
{
NSLog(#"Accelerometer is not available.");
}
// Go to second view controller
if (sender.state == UIGestureRecognizerStateBegan)
{
SecondViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self presentViewController:svc animated:YES completion:nil];
}
Any ideas? Or even a more general way to cancel the gesture unless a condition is met would be very helpful.
I hope the code is verbose enough for you to read, it's pretty self explanatory - I've stuck with your accelerometer code, and used the same variable names.
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
#interface ViewController () {
NSOperationQueue *motionQueue;
NSTimer *touchTimer;
NSTimeInterval initialTimeStamp;
BOOL touchValid;
float timerPollInSeconds;
float longPressTimeRequired;
}
#property (strong, nonatomic) NSTimer *touchTimer;
#property (assign, nonatomic) NSTimeInterval initialTimeStamp;
#property (assign, nonatomic) BOOL touchValid;
#property (assign, nonatomic) float timerPollInSeconds;
#property (assign, nonatomic) float longPressTimeRequired;
#property (strong, nonatomic) CMMotionManager *motionManager;
#property (strong, nonatomic) NSOperationQueue *motionQueue;
#end
#implementation ViewController
#synthesize touchTimer = _touchTimer, initialTimeStamp, touchValid, motionQueue = _motionQueue;
#synthesize timerPollInSeconds, longPressTimeRequired, motionManager = _motionManager;
- (void)viewDidLoad
{
self.timerPollInSeconds = 0.25f;
self.longPressTimeRequired = 3.0f;
self.touchTimer = nil;
self.touchValid = NO;
self.initialTimeStamp = NSTimeIntervalSince1970;
self.motionManager = [[CMMotionManager alloc] init];
self.motionQueue = [[NSOperationQueue alloc] init];
[_motionQueue setName:#"MotionQueue"];
[_motionQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
[super viewDidLoad];
self.view.multipleTouchEnabled = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Operations
-(void) startLongPressMonitorWithTimeStamp:(NSTimeInterval) timeStamp {
NSLog(#"Starting monitoring - %g", timeStamp);
if( self.touchTimer ) {
if( [_touchTimer isValid] ) {
[_touchTimer invalidate];
}
}
self.touchTimer = [NSTimer timerWithTimeInterval:self.timerPollInSeconds target:self selector:#selector(timerPolled:) userInfo:nil repeats:YES];
if( [_motionManager isAccelerometerAvailable] ) {
NSLog(#"Accelerometer Available");
if( ![_motionManager isAccelerometerActive] ) {
NSLog(#"Starting Accelerometer");
[_motionManager startAccelerometerUpdatesToQueue:self.motionQueue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
{
dispatch_sync(dispatch_get_main_queue(), ^{
self.touchValid = YES;
});
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
self.touchValid = NO;
[self stopLongPressMonitoring:YES];
});
};
}];
}
else {
NSLog(#"Accelerometer already active");
}
}
else {
NSLog(#"Accelerometer not available");
}
self.initialTimeStamp = timeStamp;
self.touchValid = YES;
[_touchTimer fire];
[[NSRunLoop mainRunLoop] addTimer:self.touchTimer forMode:NSRunLoopCommonModes];
}
-(void) stopLongPressMonitoring:(BOOL) touchSuccessful {
[_motionManager stopAccelerometerUpdates];
[_touchTimer invalidate];
self.touchValid = NO;
if( touchSuccessful ) {
NSLog(#"Yes");
}
else {
NSLog(#"No");
}
}
#pragma mark - User Interaction
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//We're using the current times, interval since the touches timestamp refers to system boot up
// it is more than feasible to use this boot up time, but for simplicity, I'm just using this
NSTimeInterval timestamp = [NSDate timeIntervalSinceReferenceDate];
[self startLongPressMonitorWithTimeStamp:timestamp];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if( self.touchValid && [NSDate timeIntervalSinceReferenceDate] - self.initialTimeStamp == self.longPressTimeRequired ) {
[self stopLongPressMonitoring:YES];
}
else {
[self stopLongPressMonitoring:NO];
}
}
#pragma mark - Timer Call back
-(void) timerPolled:(NSTimer *) timer {
NSTimeInterval firedTimeStamp = [NSDate timeIntervalSinceReferenceDate];
NSLog(#"Timer polled - %g", firedTimeStamp);
if( self.touchValid ) {
NSLog(#"Time elapsed: %d", (int)(firedTimeStamp - self.initialTimeStamp));
if( firedTimeStamp - self.initialTimeStamp >= self.longPressTimeRequired ) {
NSLog(#"Required time has elapsed");
[self stopLongPressMonitoring:YES];
}
}
else {
NSLog(#"Touch invalidated");
[self stopLongPressMonitoring:NO];
}
}
#end
You may be able to do what you want by subclassing UIGestureRecognizer to make your own gesture recognizer similar to UILongPressGestureRecognizer that listens for accelerometer data in addition to presses of at least 3 second duration.
I'd probably override the onTouchesBegan, and onTouchesEnded methods, rather than using a gesture recogniser.
I'd then create a NSTimer object, an NSTimeInterval var and a BOOL in your view controller; for the sake of it, I'll call them, touchTimer, initialTouchTimeStamp, and touchValid.
for the sake of complexity, it's an assumption that the viewControllers view is not multi-touch.
Assume the repeatTime = 0.25f;
longPressTimeRequired = 3;
The timer selector would incorporate your accelerometer method, if the data inside your accelerometer method is invalid, I'd set a touchValid to false (and invalidate the timer), otherwise I'd set it to true After checking the accelerometer, I'd check if my initialTouchTimeStamp var is longPressTimeRequired or more seconds prior to [touchTimer fireDate] - repeatTime , if it is, and the touchValid is true, then I would go to my second controller.
onTouchesBegan, I'd invalidate touchTimer and create a new one that would repeat every repearTime seconds, and lasts for y seconds. Set touchValid to NO, and set initialTouchTimeStamp to touch.timestamp.
onTouchesEnded, I'd invalidate touchTimer, and check if my initialTouchTimeStamp var is longPressTimeRequired or more seconds prior to [touchTimer fireDate] - repeatTime , if it is, and the touchValid is true, then I would go to my second controller.
there are many common elements in here, and it's probably not the most elegant way of doing things, but it should work. Hope this helps.
I can get the HUD layer to appear, but I can't seem to update it. I got it working in Ray's tutorial, but for some reason I can't get it working in my own app. I made a new Cocos2d project just so I can try and isolate the problem and I'm having the same issue... maybe you guys can help. ( I'm getting no errors and tried to fix the indentation as best I could for StackOverflow..)
Problem: I can't update the scoreLabel
Code:
GameHUD.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GameHUD : CCLayer {
CCLabelTTF *scoreLabel;
}
- (void) updateScore:(int)score;
#end
GameHUD.m
#import "GameHUD.h"
#implementation GameHUD
- (id) init {
if (self = [super init]) {
scoreLabel = [CCLabelTTF labelWithString:#"00000" dimensions:CGSizeMake(240,100) hAlignment:kCCTextAlignmentRight fontName:#"Arial" fontSize:32.0f];
scoreLabel.anchorPoint = ccp(0,0);
scoreLabel.position = ccp(200,0);
scoreLabel.color = ccc3(255, 200, 100);
[self addChild:scoreLabel];
}
return self;
}
- (void)updateScore:(int)score {
scoreLabel.string = [NSString stringWithFormat:#"%i",score];
}
#end
HelloWorldLayer.h
#import "cocos2d.h"
#import "GameHUD.h"
#interface HelloWorldLayer : CCLayer
{
GameHUD *_hud;
}
#property (nonatomic,retain) GameHUD *hud;
+(CCScene *) scene;
#end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
#implementation HelloWorldLayer
#synthesize hud = _hud;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
GameHUD *hud = [GameHUD node];
[scene addChild:hud];
layer.hud = hud;
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
// create and initialize a Label
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Layer A" fontName:#"Marker Felt" fontSize:64];
// ask director for the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
label.position = ccp( size.width /2 , size.height/2 );
// add the label as a child to this Layer
[self addChild: label];
// Try to update the scoreLabel in the HUD (NOT WORKING)
[_hud updateScore:74021];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
The init is called when you invoke [HelloWorldLayer node] when the HUD is not created yet, ie, _hud is nil. Sending message to a nil object is a void operation and it doesn't crash as it is if calling functions on 'NULL` objects.