Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial import. raw file copies from Jacob's Shapes. http://www.littl…

  • Loading branch information...
commit 45e640c38f2321f89f0bcda911c522811982b465 0 parents
Nate Murray authored September 07, 2010

Showing 31 changed files with 9,672 additions and 0 deletions. Show diff stats Hide diff stats

  1. 14  .gitignore
  2. 14  Classes/Controllers/CocosOverlayViewController.h
  3. 32  Classes/Controllers/CocosOverlayViewController.m
  4. 52  Classes/Controllers/GameController.h
  5. 174  Classes/Controllers/GameController.mm
  6. 202  Classes/External/Analytics-README.txt
  7. 82  Classes/Other/SynthesizeSingleton.h
  8. 35  Classes/Scenes/HCUPPanelScene.h
  9. 286  Classes/Scenes/HCUPPanelScene.m
  10. 18  Classes/Views/CocosOverlayScrollView.h
  11. 106  Classes/Views/CocosOverlayScrollView.m
  12. 23  Classes/Views/NMPanelMenu.h
  13. 170  Classes/Views/NMPanelMenu.m
  14. 36  Classes/Views/NMPanelMenuItem.h
  15. 96  Classes/Views/NMPanelMenuItem.m
  16. 18  Classes/Views/PreviewScrollContainerView.h
  17. 36  Classes/Views/PreviewScrollContainerView.m
  18. 17  Classes/common.h
  19. 24  Classes/shapesAppDelegate.h
  20. 208  Classes/shapesAppDelegate.m
  21. 20  Classes/tmp.txt
  22. 22  LICENSE.cocos2d
  23. 21  LICENSE.cocosdenshion
  24. BIN  Resources/Icon.png
  25. 39  Resources/Info.plist
  26. BIN  Resources/fps_images.png
  27. 1  libs/README
  28. 16  main.m
  29. 6,424  shapes-panels.xcodeproj/.dat89be.363
  30. 1,478  shapes-panels.xcodeproj/project.pbxproj
  31. 8  shapes_Prefix.pch
14  .gitignore
... ...
@@ -0,0 +1,14 @@
  1
+.DS_Store
  2
+*.swp
  3
+*~.nib
  4
+build/
  5
+*.pbxuser
  6
+*.perspective
  7
+*.perspectivev3
  8
+*.mode1v3
  9
+*.mode2v3
  10
+.autosession.vim
  11
+./html/
  12
+session.vim
  13
+*/.DS_Store
  14
+Resources/sounds/raw/
14  Classes/Controllers/CocosOverlayViewController.h
... ...
@@ -0,0 +1,14 @@
  1
+//
  2
+//  CocosOverlayViewController.h
  3
+//  shapes
  4
+//
  5
+//  Created by Nate Murray on 8/23/10.
  6
+//  Copyright 2010 LittleHiccup. All rights reserved.
  7
+//
  8
+
  9
+#import <Foundation/Foundation.h>
  10
+
  11
+@interface CocosOverlayViewController : UIViewController
  12
+{
  13
+}
  14
+@end
32  Classes/Controllers/CocosOverlayViewController.m
... ...
@@ -0,0 +1,32 @@
  1
+//
  2
+//  CocosOverlayViewController.m
  3
+//  shapes
  4
+//
  5
+//  Created by Nate Murray on 8/23/10.
  6
+//  Copyright 2010 LittleHiccup. All rights reserved.
  7
+//
  8
+
  9
+#import "CocosOverlayViewController.h"
  10
+#import "CocosOverlayScrollView.h"
  11
+
  12
+@implementation CocosOverlayViewController
  13
+
  14
+// Implement loadView to create a view hierarchy programmatically, without using a nib.
  15
+- (void)loadView
  16
+{
  17
+	CocosOverlayScrollView *scrollView = [[CocosOverlayScrollView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
  18
+	
  19
+	// NOTE - I have hardcoded the size to 1024x1024 as that is the size of the levels in
  20
+	// our game.  Ideally this value would be parameterized or configurable.
  21
+	//
  22
+	scrollView.contentSize = CGSizeMake(1024, 1024);
  23
+	
  24
+	scrollView.delegate = scrollView;
  25
+	[scrollView setUserInteractionEnabled:TRUE];
  26
+	[scrollView setScrollEnabled:TRUE];
  27
+	
  28
+	self.view = scrollView;
  29
+	
  30
+	[scrollView release];
  31
+}
  32
+@end
52  Classes/Controllers/GameController.h
... ...
@@ -0,0 +1,52 @@
  1
+/*
  2
+ *  GameController.h
  3
+ *  deadmanschest
  4
+ *
  5
+ *  Created by Nate Murray on 6/27/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+#import "cocos2d.h"
  11
+#import "common.h"
  12
+#import "SynthesizeSingleton.h"
  13
+
  14
+@class HSGameScene;
  15
+@class JSWorld;
  16
+@class JSLevel;
  17
+
  18
+@interface GameController : NSObject {
  19
+    int piecesRemaining;
  20
+    JSWorld* currentWorld;
  21
+    JSLevel* currentLevel;
  22
+    int currentWorld_i;
  23
+    int currentLevel_i;
  24
+    NSString* currentVoice;
  25
+    NSOperationQueue* operationQueue;
  26
+    BOOL newPlayer;
  27
+    BOOL levelReady;
  28
+    // HSGameScene* gameScene;
  29
+}
  30
+@property(nonatomic) int piecesRemaining;
  31
+@property(nonatomic, retain) JSWorld* currentWorld;
  32
+@property(nonatomic, retain) JSLevel* currentLevel;
  33
+@property(nonatomic) int currentWorld_i;
  34
+@property(nonatomic) int currentLevel_i;
  35
+@property(nonatomic, retain) NSString* currentVoice;
  36
+@property(nonatomic, retain) NSOperationQueue* operationQueue;
  37
+@property(nonatomic) BOOL newPlayer;
  38
+@property(nonatomic) BOOL levelReady;
  39
+// @property(nonatomic, retain) HSGameScene* gameScene;
  40
+
  41
++(GameController *) sharedGameController;
  42
+- (void) noPiecesRemaining;
  43
+- (void) piecePlaced;
  44
+- (void)setWorld:(int)i level:(int)j;
  45
+- (void)replaceWorld:(int)i level:(int)j;
  46
+- (HSGameScene*) gameScene;
  47
+- (void) cleanupCaches;
  48
+- (void) loadVoicePrefs;
  49
+- (void) changeVoiceTo: (NSString*) newVoice;
  50
+- (void) levelIsReady;
  51
+- (BOOL) firstLaunch;
  52
+@end
174  Classes/Controllers/GameController.mm
... ...
@@ -0,0 +1,174 @@
  1
+/*
  2
+ *  GameController.mm
  3
+ *  deadmanschest
  4
+ *
  5
+ *  Created by Nate Murray on 6/27/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+/*
  11
+   game controller should hold a reference to the current world, the current
  12
+   world holds a reference to the current level the world and level know how to
  13
+   parse the plists.  we need to have the world class load the world
  14
+   definitions dictionary then it can create a level with a particular
  15
+   dictionary then the game controller asks its world for the current level and
  16
+   builds the gamescene based on the level. it gives the gamescene the level
  17
+
  18
+   the panel scene has one panel for all. and otherwise builds a panel for each
  19
+   world. it asks the or maybe just the world class method. for the dictionary
  20
+   of worlds
  21
+
  22
+   when you are playing the game, you start on the first level of the world. if
  23
+   you win, you get a little message, and then its on to the next level of the
  24
+   world. if there is no next level in this world. then you go to the first
  25
+   level of the next world. 
  26
+
  27
+   one problem is how does one get back to the panel world chooser once they
  28
+   have started the game.
  29
+ */
  30
+
  31
+#include "GameController.h"
  32
+#import "GameSoundManager.h"
  33
+#import "HSGameScene.h"
  34
+#import "JSWorld.h"
  35
+
  36
+@interface GameController (Private)
  37
+@end
  38
+
  39
+@implementation GameController
  40
+@synthesize piecesRemaining;
  41
+@synthesize currentWorld;
  42
+@synthesize currentLevel;
  43
+@synthesize currentWorld_i;
  44
+@synthesize currentLevel_i;
  45
+@synthesize currentVoice;
  46
+@synthesize operationQueue;
  47
+@synthesize newPlayer;
  48
+@synthesize levelReady;
  49
+// @synthesize gameScene;
  50
+
  51
+SYNTHESIZE_SINGLETON_FOR_CLASS(GameController);
  52
+SimpleAudioEngine *soundEngine;
  53
+
  54
+-(id)init {
  55
+    if ((self = [super init])){ 
  56
+        self.piecesRemaining = 0;
  57
+        soundEngine = [GameSoundManager sharedManager].soundEngine;
  58
+        [soundEngine retain];
  59
+        [self setWorld: 0 level: 0];
  60
+        // [self setWorld: 16 level: 0];
  61
+        [self loadVoicePrefs];
  62
+        self.operationQueue = [[NSOperationQueue alloc] init]; 
  63
+        self.newPlayer = YES;
  64
+        self.levelReady = YES;
  65
+    }
  66
+    return self;
  67
+}
  68
+
  69
+- (void)setWorld:(int)i level:(int)j {
  70
+    self.currentWorld = [JSWorld world: i];
  71
+    self.currentLevel = [currentWorld level: j];
  72
+    self.currentWorld_i = i;
  73
+    self.currentLevel_i = j;
  74
+}
  75
+
  76
+- (void)replaceWorld:(int)i level:(int)j {
  77
+    // this isn't called when you press the green button
  78
+    CGSize s = [[CCDirector sharedDirector] winSize];
  79
+    [self setWorld:i level:j];
  80
+    HSGameScene *currentLevelLayer = [self gameScene];
  81
+
  82
+    // HSGameScene* nextLevelLayer = [[HSGameScene alloc] init];
  83
+    HSGameScene* nextLevelLayer = [HSGameScene node];
  84
+    [[currentLevelLayer parent] addChild: nextLevelLayer]; // add nextLevel to the same scene
  85
+    nextLevelLayer.position = ccp(s.width, 0);
  86
+
  87
+    /* race condition here? */
  88
+    nextLevelLayer.tag    = kTag_GameScene;
  89
+    currentLevelLayer.tag = kTag_OldGameScene;
  90
+
  91
+    float move_t = 1.0f;
  92
+
  93
+    CCLOG(@"replacing world");
  94
+    self.levelReady = NO;
  95
+
  96
+    id move_in  = [CCMoveTo actionWithDuration:move_t position:ccp(0, 0)]; 
  97
+    id move_out = [CCMoveTo actionWithDuration:move_t position:ccp(-s.width, 0)]; 
  98
+    id rm = [CCCallFuncND actionWithTarget:currentLevelLayer selector:@selector(removeFromParentAndCleanup:) data:(void*)YES];
  99
+    id ready = [CCCallFunc actionWithTarget:self selector:@selector(levelIsReady)];
  100
+    id cleanup = [CCCallFunc actionWithTarget:self selector:@selector(cleanupCaches)];
  101
+
  102
+    [currentLevelLayer runAction: [CCSequence actions: move_out, rm, cleanup, nil]];
  103
+    [nextLevelLayer runAction: [CCSequence actions: move_in, ready, nil]];
  104
+}
  105
+
  106
+- (HSGameScene*) gameScene {
  107
+    CCScene* scene = [[CCDirector sharedDirector] runningScene];
  108
+    // HSGameScene* layer = (HSGameScene*)[[scene children] objectAtIndex:0]; // thin ice, use a tag!
  109
+    HSGameScene* layer = (HSGameScene*)[scene getChildByTag:kTag_GameScene];
  110
+    return layer;
  111
+}
  112
+
  113
+-(void)dealloc {
  114
+    [soundEngine release];
  115
+	self.currentVoice = nil;
  116
+	self.operationQueue = nil;
  117
+    [super dealloc];
  118
+}
  119
+
  120
+- (void) piecePlaced {
  121
+    self.piecesRemaining -= 1;
  122
+    if(self.piecesRemaining <= 0) {
  123
+        [self noPiecesRemaining];
  124
+    }
  125
+}
  126
+
  127
+- (void) noPiecesRemaining {
  128
+    // [[self gameScene] levelPassed];
  129
+
  130
+    // todo, i don't like putting this here, but it is the best place
  131
+    // id delay = [CCDelayTime actionWithDuration: 1.0]; // delay to allow the last sound to play
  132
+    id delay = [CCDelayTime actionWithDuration: 1.2]; // delay to allow the last sound to play
  133
+    id passed = [CCCallFunc actionWithTarget:[self gameScene] selector:@selector(levelPassed)];
  134
+    [[self gameScene] runAction: [CCSequence actions: delay, passed, nil]];
  135
+}
  136
+
  137
+- (void) cleanupCaches {
  138
+    // [[CCTextureCache sharedTextureCache] removeUnusedTextures];
  139
+}
  140
+
  141
+- (void) levelIsReady {
  142
+    CCLOG(@"level is ready!");
  143
+    self.levelReady = YES;
  144
+}
  145
+
  146
+- (void) loadVoicePrefs {
  147
+    if (![[NSUserDefaults standardUserDefaults] valueForKey:@"currentVoice"])  {
  148
+        CCLOG(@"setting default voice");
  149
+        [self changeVoiceTo:@"addie"];
  150
+    } else {
  151
+        NSString* voiceName = [[NSUserDefaults standardUserDefaults] objectForKey:@"currentVoice"];
  152
+        CCLOG(@"loading voice: %@", voiceName);
  153
+        self.currentVoice = voiceName;
  154
+    }
  155
+}
  156
+
  157
+- (void) changeVoiceTo: (NSString*) newVoice {
  158
+    self.currentVoice = newVoice;
  159
+    [[NSUserDefaults standardUserDefaults] setObject:newVoice forKey:@"currentVoice"];
  160
+}
  161
+
  162
+- (BOOL) firstLaunch {
  163
+    if (![[NSUserDefaults standardUserDefaults] boolForKey:@"launchedBefore"])  {
  164
+        CCLOG(@"first launch");
  165
+        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"launchedBefore"];
  166
+        return YES;
  167
+    } else {
  168
+        CCLOG(@"launched before");
  169
+        // return [[NSUserDefaults standardUserDefaults] boolForKey:@"launchedBefore"];
  170
+        return NO;
  171
+    }
  172
+}
  173
+
  174
+@end
202  Classes/External/Analytics-README.txt
... ...
@@ -0,0 +1,202 @@
  1
+Welcome to Flurry Analytics!
  2
+
  3
+This README contains:
  4
+
  5
+1. Introduction
  6
+2. Integration
  7
+3. Latest SDK Update
  8
+4. Optional Features
  9
+5. Recommendations
  10
+6. FAQ
  11
+
  12
+=====================================
  13
+1. Introduction
  14
+
  15
+The Flurry iPhone Analytics Agent allows you to track the usage and behavior of your iPhone application
  16
+on users' phones for viewing in the Flurry Analytics system. It is designed to be as easy as possible
  17
+with a basic setup complete in under 5 minutes.
  18
+
  19
+This archive should contain these files:
  20
+ - ProjectApiKey.txt : This file contains the name of your project and your project's API key.
  21
+ - Analytics-README.txt : This text file containing instructions. 
  22
+ - FlurryLibWithLocation/FlurryAPI.h
  23
+ - FlurryLibWithLocation/libFlurryWithLocation.a : The library containing Flurry's collection and reporting code. This version includes GPS location capabilities. Requires Xcode 3.2.3 or above. 
  24
+ - FlurryLib/FlurryAPI.h
  25
+ - FlurryLib/libFlurry.a : The library containing Flurry's collection and reporting code. This version does not include GPS location capabilities. Requires Xcode 3.2.3 or above.
  26
+ 
  27
+ - FlurryLib/FlurryAdDelegate.h
  28
+ - FlurryLibWithLocation/FlurryAdDelegate.h : These are optional files for use with Flurry AppCircle. You do NOT need them for Flurry Analytics.
  29
+
  30
+Note that there are two versions of the Flurry analytics library: With and without location. We recommend using FlurryLibWithLocation so that you can receive detailed analytics about where your users are using your app.
  31
+However, if you do not currently use location in your application, you can use FlurryLib and receive all of the same analytics without detailed location information.
  32
+We also recommend calling FlurryAPI from the main thread. FlurryAPI is not supported when called from other threads.
  33
+
  34
+=====================================
  35
+2. Integration
  36
+ 
  37
+To integrate Flurry Analytics into your iPhone application, first decide if you want to use location services or not.  
  38
+If you do wish to use location, see the steps in 2a.  If you do not wish to use location, skip to 2b.
  39
+
  40
+Note that you should only use Flurry location services if your application already uses the CLLocationManager. You should not enable location services for analytics if you do not already use the CLLocationManager as your application will be rejected by Apple. 
  41
+Apple requires that your application use location in a way useful to the end user in order to access the CLLocationManager.
  42
+
  43
+2a. Integration without Location
  44
+-------------------------------------------------------------
  45
+
  46
+1. In the finder, drag FlurryLib into project's file folder.
  47
+   NOTE: If you are upgrading the Flurry iPhone SDK, be sure to remove any existing Flurry library folders from your project's file folder before proceeding.
  48
+
  49
+2. Now add it to your project =>  Project > Add to project > FlurryLib
  50
+    - Choose 'Recursively create groups for any added folders'
  51
+
  52
+3. In your Application Delegate:
  53
+      a. Import FlurryAPI =>  #import "FlurryAPI.h"
  54
+      b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSession:@"YOUR_API_KEY"];
  55
+     
  56
+      - (void)applicationDidFinishLaunching:(UIApplication *)application {
  57
+          [FlurryAPI startSession:@"YOUR_API_KEY"];
  58
+          //your code
  59
+        }
  60
+      
  61
+You're done! That's all you need to do to begin receiving basic metric data.
  62
+
  63
+2b. Integration with location
  64
+-------------------------------------------------------------
  65
+1. In the finder, drag FlurryLibWithLocation into project's file folder.  
  66
+   NOTE: If you are upgrading the Flurry iPhone SDK, be sure to remove any existing Flurry library folders from your project's file folder before proceeding.
  67
+
  68
+2. Now add it to your project =>  Project > Add to project > FlurryLibWithLocation
  69
+    - Choose 'Recursively create groups for any added folders'
  70
+
  71
+3. At this point, there are two options.  First, if your application already has initialized a CLLocationManager, you can simply pass location information to the Flurry API for each session.  For this option see the steps in 3a.  
  72
+   Second, if your application has not already defined a CLLocationManager and you want Flurry to handle this for you, see the steps in 3b.
  73
+
  74
+3a. You pass location information to the FlurryAPI.  In your Application Delegate:
  75
+      a. Import FlurryAPI =>  #import "FlurryAPI.h"
  76
+      b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSession:@"YOUR_API_KEY"];
  77
+     
  78
+      - (void)applicationDidFinishLaunching:(UIApplication *)application {
  79
+          [FlurryAPI startSession:@"YOUR_API_KEY"];
  80
+          //your code
  81
+        }
  82
+      c. Each time you want to update the location that Flurry Analytics will record, use the function below.  Only the last location reported will be used for each session.
  83
+         [FlurryAPI setLocation:YOUR_UPDATED_CLLOCATION];
  84
+
  85
+3b. Flurry manages all location capabilities.  In your Application Delegate:
  86
+      a. Import FlurryAPI =>  #import "FlurryAPI.h"
  87
+      b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSessionWithLocationServices:@"YOUR_API_KEY"];
  88
+     
  89
+      - (void)applicationDidFinishLaunching:(UIApplication *)application {
  90
+          [FlurryAPI startSessionWithLocationServices:@"YOUR_API_KEY"];
  91
+          //your code
  92
+        }
  93
+      
  94
+      NOTE: You must also include the CoreLocation.framework if you do this. To add this framework, go to
  95
+      Project > Edit Active Target "YOUR_APP" > Add Libraries ('+' sign at the bottom) and select CoreLocation.framework
  96
+
  97
+You're done! That's all you need to do to begin receiving basic metric data.  For optional advanced features, skip to Section 3.
  98
+
  99
+=====================================
  100
+3. Latest SDK Update
  101
+Going forward, the Flurry SDK will only support Xcode 3.2.3 and above. Please email support if you need to use older versions of the Flurry SDK.
  102
+
  103
+This version of the Flurry SDK is compatible with Xcode 3.2.3 and designed for OS 4.0 (iOS) applications.
  104
+
  105
+In this version of the Flurry SDK, we modified which data is collected. This updated SDK version does not collect the following device data: device name, operating system version and firmware version.  Because Apple allows the collection of UDID for the purpose of advertising, we continue to collect this data as the Flurry SDK includes AppCircle, Flurry's mobile advertising solution.
  106
+
  107
+Per Flurry's existing Terms of Service and Privacy Policy, please inform your consumers about data you collect through the use of our services.  Additionally, please remember that you must abide by the rules set forth in the new Apple iPhone Developer Program License Agreement.
  108
+
  109
+Despite our latest efforts, please understand that we are unable to guarantee whether Apple reviewers will approve your application in its App Store submission process. 
  110
+
  111
+=====================================
  112
+4. Optional / Advanced Features
  113
+
  114
+You can use the following methods to report additional data.  These methods work exactly the same with or without location services enabled.
  115
+
  116
+[FlurryAPI logEvent:@"EVENT_NAME"];
  117
+Use logEvent to count the number of times certain events happen during a session of your application.  This can be useful for measuring how often users perform various actions, for example.  Your application is currently limited to counting occurrences for 100 different event ids (maximum length 255 characters).
  118
+
  119
+[FlurryAPI logEvent:@"EVENT_NAME" withParameters:YOUR_NSDictionary];
  120
+Use this version of logEvent to count the number of times certain events happen during a session of your application and to pass dynamic parameters to be recorded with that event.  For example, you could record that a user used your search box tool and also dynamically record which search terms the user entered.  Your application is currently limited to counting occurrences for 100 different event ids (maximum length 255 characters). 
  121
+
  122
+  An example NSDictionary to use with this method could be:
  123
+  NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"your dynamic parameter value", @"your dynamic parameter name", nil];
  124
+
  125
+[FlurryAPI logEvent:@"EVENT_NAME" timed:YES];
  126
+Use this version of logEvent to start timed event. 
  127
+
  128
+[FlurryAPI logEvent:@"EVENT_NAME" withParameters:YOUR_NSDictionary timed:YES];
  129
+Use this version of logEvent to start timed event with event parameters.
  130
+
  131
+[FlurryAPI endTimedEvent:@"EVENT_NAME"];
  132
+Use endTimedEvent to end timed event before app exists, otherwise timed events automatically end when app exists.
  133
+
  134
+[FlurryAPI logError:@"ERROR_NAME" message:@"ERROR_MESSAGE" exception:e];
  135
+Use this to log exceptions and/or errors that occur in your app. Flurry will report the first 10 errors that occur in each session.
  136
+
  137
+[FlurryAPI setUserID:@"USER_ID"];
  138
+Use this to log the user's assigned ID or username in your system after identifying the user. 
  139
+
  140
+[FlurryAPI setAge:21];
  141
+Use this to log the user age after identifying the user. Valid inputs are 0 or greater.
  142
+
  143
+[FlurryAPI countPageViews:navigationController];
  144
+Use this to track user interactions with application's navigation structures. Each interaction is considered a page view. To enable tracking, pass in an instance of UINavigationController and UITabBarController. Multiple UINavigationController and UITabBarController instances can be tracked.
  145
+
  146
+[FlurryAPI countPageView];
  147
+If your app does not use UINavigationController or UITabBarController, Flurry API will not be able to automatically track user's interactions. In this case, you can use manually count a page view after detecting the user interaction yourself.
  148
+
  149
+[FlurryAPI setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose];
  150
+This option is on by default. When enabled, Flurry will attempt to send session data when the app is exited as well as it normally does when the app is started. This will improve the speed at which your application analytics are updated but can prolong the app termination process due to network latency. In some cases, the network latency can cause the app to crash.
  151
+
  152
+[FlurryAPI setSessionReportsOnPauseEnabled:(BOOL)sendSessionReportsOnPause];
  153
+This option is off by default. When enabled, Flurry will attempt to send session data when the app is paused as well as it normally does when the app is started. This will improve the speed at which your application analytics are updated but can prolong the app pause process due to network latency. In some cases, the network latency can cause the app to crash.
  154
+
  155
+=====================================
  156
+5. Recommendations
  157
+
  158
+We recommend adding an uncaught exception listener to your application (if you don't already have one) and use logError to record any application crashes.
  159
+Adding an uncaught exception listener is easy; you just need to create a function that looks like the following:
  160
+
  161
+    void uncaughtExceptionHandler(NSException *exception) {
  162
+        [FlurryAPI logError:@"Uncaught" message:@"Crash!" exception:exception];
  163
+    }                                       
  164
+
  165
+You then need to register this function as an uncaught exception listener as follows:
  166
+
  167
+    - (void)applicationDidFinishLaunching:(UIApplication *)application {
  168
+        NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
  169
+        [FlurryAPI startSession:@"YOUR_API_KEY"];
  170
+            ....
  171
+    }           
  172
+
  173
+Note that you can name the function whatever you'd like and record whatever error information you'd like in the error name and event fields.
  174
+
  175
+=====================================
  176
+6. FAQ
  177
+
  178
+When does the Flurry Agent send data?
  179
+
  180
+By default, the Flurry Agent will send the stored metrics data to Flurry servers when the app starts, resumes, and terminates. 
  181
+To override default Agent behavior, you can turn off sending data on termination with [FlurryAPI setSessionReportsOnCloseEnabled:NO];
  182
+Sending metrics data when the app pauses is also supported, but not enabled by default. You can enable sending data on pause with [FlurryAPI setSessionReportsOnPauseEnabled:YES];
  183
+
  184
+How much data does the Agent send each session?
  185
+
  186
+All data sent by the Flurry Agent is sent in a compact binary format.
  187
+
  188
+What data does the Agent send?
  189
+
  190
+The data sent by the Flurry Agent includes time stamps, logged events, logged errors, and various device specific information. This is the same information that can be seen in the custom event logs on in the Event Analytics section. 
  191
+If AppCircle is used, Flurry Agent will also send AppCircle user interaction data. These information can be seen in the AppCircle section.  
  192
+We are also collecting App Store ID, purchase date, release date, and purchase price in order to provide more metrics in the future.
  193
+We do not collect personally identifiable information.  
  194
+
  195
+=====================================
  196
+
  197
+Please let us know if you have any questions. If you need any help, just email iphonesupport@flurry.com!
  198
+
  199
+Cheers,
  200
+The Flurry Team
  201
+http://www.flurry.com
  202
+iphonesupport@flurry.com
82  Classes/Other/SynthesizeSingleton.h
... ...
@@ -0,0 +1,82 @@
  1
+//
  2
+//  SynthesizeSingleton.h
  3
+//  CocoaWithLove
  4
+//
  5
+//  Created by Matt Gallagher on 20/10/08.
  6
+//  Copyright 2009 Matt Gallagher. All rights reserved.
  7
+//
  8
+//  Permission is given to use this source code file without charge in any
  9
+//  project, commercial or otherwise, entirely at your risk, with the condition
  10
+//  that any redistribution (in part or whole) of source code must retain
  11
+//  this copyright and permission notice. Attribution in compiled projects is
  12
+//  appreciated but not required.
  13
+//
  14
+// To use:
  15
+//
  16
+//     SYNTHESIZE_SINGLETON_FOR_CLASS(MyClassName);
  17
+//
  18
+// inside the @implementation MyClassName declaration and your class will become a singleton. You will also need to add the line:
  19
+// 
  20
+//     + (MyClassName *)sharedMyClassName;
  21
+// 
  22
+// to the header file for MyClassName so the singleton accessor method can be found from other source files if they #import the header.
  23
+// 
  24
+// Once your class is a singleton, you can access the instance of it using the line:
  25
+//
  26
+//     [MyClassName sharedMyClassName];
  27
+//
  28
+
  29
+#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
  30
+ \
  31
+static classname *shared##classname = nil; \
  32
+ \
  33
++ (classname *)shared##classname \
  34
+{ \
  35
+	@synchronized(self) \
  36
+	{ \
  37
+		if (shared##classname == nil) \
  38
+		{ \
  39
+			shared##classname = [[self alloc] init]; \
  40
+		} \
  41
+	} \
  42
+	 \
  43
+	return shared##classname; \
  44
+} \
  45
+ \
  46
++ (id)allocWithZone:(NSZone *)zone \
  47
+{ \
  48
+	@synchronized(self) \
  49
+	{ \
  50
+		if (shared##classname == nil) \
  51
+		{ \
  52
+			shared##classname = [super allocWithZone:zone]; \
  53
+			return shared##classname; \
  54
+		} \
  55
+	} \
  56
+	 \
  57
+	return nil; \
  58
+} \
  59
+ \
  60
+- (id)copyWithZone:(NSZone *)zone \
  61
+{ \
  62
+	return self; \
  63
+} \
  64
+ \
  65
+- (id)retain \
  66
+{ \
  67
+	return self; \
  68
+} \
  69
+ \
  70
+- (NSUInteger)retainCount \
  71
+{ \
  72
+	return NSUIntegerMax; \
  73
+} \
  74
+ \
  75
+- (void)release \
  76
+{ \
  77
+} \
  78
+ \
  79
+- (id)autorelease \
  80
+{ \
  81
+	return self; \
  82
+}
35  Classes/Scenes/HCUPPanelScene.h
... ...
@@ -0,0 +1,35 @@
  1
+/*
  2
+ *  HSLevelSelectionScene.h
  3
+ *  shapes
  4
+ *
  5
+ *  Created by Nate Murray on 7/24/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+// When you import this file, you import all the cocos2d classes
  11
+#import "cocos2d.h"
  12
+#import "CocosOverlayScrollView.h"
  13
+
  14
+@class PreviewScrollContainerView;
  15
+@class NMPanelMenu;
  16
+
  17
+// HSLevelSelectionScene Layer
  18
+@interface HSLevelSelectionScene2 : CCLayer
  19
+{
  20
+    int nextWorld_;
  21
+    BOOL transitioning_;
  22
+    CocosOverlayScrollView* scrollView;
  23
+    PreviewScrollContainerView* scrollViewContainer;
  24
+    UIPageControl* pageControl;
  25
+    NSString* currentLockPanelName_;
  26
+}
  27
+@property(nonatomic,retain) NSString* currentLockPanelName;
  28
+
  29
+// returns a Scene that contains the HSLevelSelectionScene as the only child
  30
++(id) scene;
  31
+- (void) menuButtonPressed: (id) sender;
  32
+- (void) addLockPanelToMenu:(NMPanelMenu*)menu;
  33
+- (void) lockPanelPicked: (id) sender;
  34
+
  35
+@end
286  Classes/Scenes/HCUPPanelScene.m
... ...
@@ -0,0 +1,286 @@
  1
+/*
  2
+ *  HSLevelSelectionScene2.m
  3
+ *  shapes
  4
+ *
  5
+ *  Created by Nate Murray on 7/24/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+#include "HCUPPanelScene.h"
  11
+#import "HSGameScene.h"
  12
+#import "NMPanelMenu.h"
  13
+#import "NMPanelMenuItem.h"
  14
+#import "GameController.h"
  15
+#import "JSWorld.h"
  16
+#import "PreviewScrollContainerView.h"
  17
+#import "HSMenuScene.h"
  18
+#import "JSNetworkManager.h"
  19
+
  20
+#ifdef LITE_VERSION
  21
+#import "FlurryAPI.h"
  22
+#endif
  23
+
  24
+// http://getsetgames.com/2009/08/21/cocos2d-and-uiscrollview/
  25
+// http://blog.proculo.de/archives/180-Paging-enabled-UIScrollView-With-Previews.html
  26
+
  27
+@implementation HSLevelSelectionScene2
  28
+@synthesize currentLockPanelName=currentLockPanelName_;
  29
+
  30
++(id) scene
  31
+{
  32
+    CCScene *scene = [CCScene node];
  33
+    HSLevelSelectionScene2 *layer = [HSLevelSelectionScene2 node];
  34
+    [scene addChild: layer];
  35
+    return scene;
  36
+}
  37
+
  38
+-(id) init
  39
+{
  40
+    if( (self=[super init] )) {
  41
+        nextWorld_ = -1;
  42
+        transitioning_ = NO;
  43
+
  44
+        CCSpriteFrameCache* fcache = [CCSpriteFrameCache sharedSpriteFrameCache];
  45
+        [fcache addSpriteFramesWithFile: @"panels-sheet-1.plist"];
  46
+        [fcache addSpriteFramesWithFile: @"panels-sheet-2.plist"];
  47
+        self.currentLockPanelName = @"n/a";
  48
+
  49
+#ifdef LITE_VERSION
  50
+        [FlurryAPI logEvent:@"LevelSelectionScene"];
  51
+#endif
  52
+
  53
+    }
  54
+    return self;
  55
+}
  56
+
  57
+- (void) onEnter 
  58
+{
  59
+    // CCLOG(@"======= HSLevelSelection onEnter");
  60
+    CGSize s = [[CCDirector sharedDirector] winSize];
  61
+
  62
+    CCSprite* bg = [CCSprite spriteWithFile:@"paper-background-2.png"];
  63
+    bg.position = ccp(s.width/2, s.height/2);
  64
+    [self addChild: bg];
  65
+
  66
+    CCLayer* panels = [CCLayer node];
  67
+    CCLOG(@"p.x:%f p.y:%f", panels.position.x, panels.position.y);
  68
+    // panels.position = ccp(s.width/2, s.height/2);
  69
+
  70
+    // create "all" panel
  71
+    CCSprite* pane1 = [CCSprite spriteWithFile:@"main-menu-panel.png"];
  72
+    CCSprite* pane2 = [CCSprite spriteWithFile:@"main-menu-panel-on.png"];
  73
+    // pane1.opacity = 0;
  74
+    NMPanelMenuItem* menuItem1 = [NMPanelMenuItem itemFromNormalSprite:pane1 selectedSprite:pane2 target:self selector:@selector(menuButtonPressed:)];
  75
+    menuItem1.world = 0;
  76
+    menuItem1.name = @"blank";
  77
+
  78
+    NMPanelMenu* menu = [NMPanelMenu menuWithItems: menuItem1, nil];
  79
+    //CCSpriteFrameCache* fcache = [CCSpriteFrameCache sharedSpriteFrameCache];
  80
+
  81
+    for(int i=0; i < [JSWorld numWorlds]; i++) {
  82
+        JSWorld* world = [JSWorld world: i];
  83
+        // CCSprite* pane2 = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@-panel.png", world.name]];
  84
+        CCSprite* pane2 = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat: @"%@-panel.png", world.name]];
  85
+        // CCSprite* pane2_on = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@-panel-on.png", world.name]];
  86
+
  87
+        NMPanelMenuItem* menuItem2 = [[NMPanelMenuItem alloc] initFromNormalSprite:pane2 
  88
+                                                                    selectedSprite:pane2
  89
+                                                                      activeSprite:pane2
  90
+                                                                    disabledSprite:pane2
  91
+                                                                              name:world.name
  92
+                                                                            target:self selector:@selector(levelPicked:)];
  93
+        menuItem2.world = i;
  94
+        menuItem2.name = world.name;
  95
+        [menu addChild: menuItem2];
  96
+        [menuItem2 release];
  97
+    }
  98
+
  99
+#ifdef LITE_VERSION
  100
+    
  101
+    // [self addLockPanelToMenu: menu];
  102
+    NSUInteger randomIndex = arc4random() % 100;
  103
+    NSString* paneName = randomIndex <= 50 ? @"locked-panel-camp" : @"locked-panel-dino";
  104
+    CCSprite* pane    = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@.png",    paneName]];
  105
+    CCSprite* pane_on = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@-on.png", paneName]];
  106
+
  107
+    NMPanelMenuItem* lockedItem = [[NMPanelMenuItem alloc] initFromNormalSprite:pane 
  108
+                                                               selectedSprite:pane
  109
+                                                                 activeSprite:pane_on
  110
+                                                               disabledSprite:pane
  111
+                                                                         name:@"blank"
  112
+                                                                       target:self selector:@selector(lockPanelPicked:)];
  113
+    lockedItem.showGlow = false;
  114
+
  115
+    [menu addChild: lockedItem];
  116
+    // menuItem.position = ccp(menuItem.position.x, menuItem.position.y - 100);
  117
+    [lockedItem release];
  118
+
  119
+#endif
  120
+
  121
+    // where you're at: get the locked panel to align vertically
  122
+    // get it to work
  123
+    // then add the last level buy now screen
  124
+
  125
+    [menu alignItemsHorizontallyWithPadding:30.0];
  126
+    [panels addChild:menu];
  127
+
  128
+#ifdef LITE_VERSION
  129
+    lockedItem.position = ccp(lockedItem.position.x, lockedItem.position.y - 7);
  130
+#endif
  131
+
  132
+
  133
+    // menu.anchorPoint = ccp(0,0);
  134
+    // CCLOG(@"menu.x:%f menu.y:%f", menu.position.x, menu.position.y);
  135
+    // menu.position = ccp(0, s.height/2);
  136
+    // CCLOG(@"menu.x:%f menu.y:%f", menu.position.x, menu.position.y);
  137
+
  138
+    int numberOfPages = [JSWorld numWorlds];
  139
+
  140
+#ifdef LITE_VERSION
  141
+    numberOfPages += 1;
  142
+#endif
  143
+
  144
+    float onePanelWide = 363;
  145
+    //float padding = 15;
  146
+    float totalWidth = numberOfPages * onePanelWide; // panel width + padding * 2
  147
+
  148
+    [self addChild:panels];
  149
+
  150
+    // 
  151
+    GameController* gc = [GameController sharedGameController];
  152
+    CCLOG(@"setting to panel: %d", gc.currentWorld_i+1);
  153
+    CCLOG(@"menu.x:%f menu.y:%f", menu.position.x, menu.position.y);
  154
+    // newMenuX =  
  155
+    // menu.position = ccp(newMenuX, menu.position.y);
  156
+    // [menu setToPanel: gc.currentWorld_i+1]; // ew
  157
+    CCLOG(@"menu.x:%f menu.y:%f", menu.position.x, menu.position.y);
  158
+    // float unknown = 70;
  159
+    float unknown = 15;
  160
+    // menu.position = ccp(totalWidth/2 + onePanelWide/2 - onePanelWide + unknown,  s.height/2);
  161
+    // menu.position = ccpAdd(menu.position, ccp(totalWidth/2 - onePanelWide + unknown, 0));
  162
+    int woff = gc.currentWorld_i;
  163
+    // menu.position = ccpAdd(menu.position, ccp(totalWidth/2 - onePanelWide - (woff * onePanelWide) + unknown, 0));
  164
+    // menu.position = ccpAdd(menu.position, ccp(totalWidth/2 - onePanelWide + unknown, 0)); // use this
  165
+    menu.position = ccpAdd(menu.position, ccp(totalWidth/2 + unknown, 0));
  166
+    // you need to scroll the scoll view container
  167
+
  168
+
  169
+    // Init Scrollview
  170
+
  171
+    // scrollView = [[CocosOverlayScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 320)];
  172
+    // scrollView = [[CocosOverlayScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
  173
+
  174
+    scrollViewContainer = [[PreviewScrollContainerView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
  175
+
  176
+    scrollView = [[CocosOverlayScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, onePanelWide)
  177
+                                                      numPages: numberOfPages + 1
  178
+                                                         width: onePanelWide
  179
+                                                         layer: panels];
  180
+
  181
+    scrollViewContainer.scrollView = scrollView;
  182
+
  183
+    // pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 0, 50, 480)];
  184
+    // pageControl.numberOfPages = numberOfPages;
  185
+    // pageControl.currentPage = 0;
  186
+    // pageControl.delegate = scrollView;
  187
+
  188
+    [scrollView setContentOffset: CGPointMake(0, (woff + 1) * onePanelWide) animated: NO];
  189
+
  190
+    // Add Scrollview to cocos2d
  191
+    [[[CCDirector sharedDirector] openGLView] addSubview:scrollViewContainer];
  192
+    [[[CCDirector sharedDirector] openGLView] addSubview:scrollView];
  193
+    // [[[CCDirector sharedDirector] openGLView] addSubview:pageControl];
  194
+
  195
+    // set to current level
  196
+    // [scrollView setContentOffset: CGPointMake(woff * onePanelWide, s.height/2) animated: YES];
  197
+
  198
+    [scrollView release];
  199
+    [scrollViewContainer release];
  200
+
  201
+    [super onEnter]; // ?
  202
+}
  203
+
  204
+- (void) menuButtonPressed: (id) sender 
  205
+{
  206
+    [[CCDirector sharedDirector] replaceScene:[CCCrossFadeTransition transitionWithDuration:0.5 scene:[HSMenuScene scene]]];
  207
+}
  208
+
  209
+- (void) addLockPanelToMenu:(NMPanelMenu*)menu
  210
+{
  211
+    NSString* paneName = @"locked-panel-camp";
  212
+    CCSprite* pane    = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@.png",    paneName]];
  213
+    CCSprite* pane_on = [CCSprite spriteWithFile:[NSString stringWithFormat: @"%@-on.png", paneName]];
  214
+    self.currentLockPanelName = paneName;
  215
+
  216
+    NMPanelMenuItem* menuItem = [[NMPanelMenuItem alloc] initFromNormalSprite:pane 
  217
+                                                               selectedSprite:pane
  218
+                                                                 activeSprite:pane_on
  219
+                                                               disabledSprite:pane
  220
+                                                                         name:@"blank"
  221
+                                                                       target:self selector:@selector(lockPanelPicked:)];
  222
+
  223
+    [menu addChild: menuItem];
  224
+    // menuItem.position = ccp(menuItem.position.x, menuItem.position.y - 100);
  225
+    [menuItem release];
  226
+}
  227
+
  228
+- (void) lockPanelPicked: (id) sender {
  229
+    CCLOG(@"buying!");
  230
+
  231
+#ifdef LITE_VERSION
  232
+    NSArray *keys = [NSArray arrayWithObjects:@"image", nil];
  233
+    NSArray *objects = [NSArray arrayWithObjects:self.currentLockPanelName, nil];
  234
+    NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
  235
+    [FlurryAPI logEvent:@"LockPanelBuyNowPressed" withParameters:dictionary];
  236
+#endif
  237
+
  238
+    [[JSNetworkManager manager] openFullVersionURL];
  239
+}
  240
+
  241
+
  242
+
  243
+- (void) levelPicked: (id) sender 
  244
+{
  245
+    // tmp
  246
+    // [scrollView removeFromSuperview];
  247
+    // [scrollViewContainer removeFromSuperview];
  248
+
  249
+    CCLOG(@"world %@ %d picked", ((NMPanelMenuItem*)sender).name, ((NMPanelMenuItem*)sender).world);
  250
+    nextWorld_ = ((NMPanelMenuItem*)sender).world;
  251
+    // if(false) {
  252
+    //     GameController* gc = [GameController sharedGameController];
  253
+    //     [gc setWorld:((NMPanelMenuItem*)sender).world level:0];
  254
+    //     [[CCDirector sharedDirector] replaceScene:[CCCrossFadeTransition transitionWithDuration:0.5 scene:[HSGameScene scene]]];
  255
+    // }    
  256
+}
  257
+
  258
+- (void) visit {
  259
+    if(nextWorld_ > -1 && !transitioning_) {
  260
+        transitioning_ = YES;
  261
+        GameController* gc = [GameController sharedGameController];
  262
+        [gc setWorld:nextWorld_ level:0]; //maybe this cuold be an object to be slightly faster
  263
+        [[CCDirector sharedDirector] replaceScene:[CCCrossFadeTransition transitionWithDuration:0.5 scene:[HSGameScene scene]]];
  264
+    }
  265
+    [super visit];
  266
+}
  267
+
  268
+- (void) onExit 
  269
+{
  270
+    CCLOG(@"=== removing view");
  271
+    [scrollView removeFromSuperview];
  272
+    [scrollViewContainer removeFromSuperview];
  273
+    [super onExit];
  274
+}
  275
+
  276
+- (void) dealloc
  277
+{
  278
+    self.currentLockPanelName = nil;
  279
+    CCLOG(@"=== deallocing HSLevelSelectionScene2");
  280
+    // [scrollView removeFromSuperview];
  281
+    // [scrollViewContainer removeFromSuperview];
  282
+
  283
+    // [pageControl removeFromSuperview];
  284
+    [super dealloc];
  285
+}
  286
+@end
18  Classes/Views/CocosOverlayScrollView.h
... ...
@@ -0,0 +1,18 @@
  1
+//
  2
+//  CocosOverlayScrollView.h
  3
+//  shapes
  4
+//
  5
+//  Created by Nate Murray on 8/23/10.
  6
+//  Copyright 2010 LittleHiccup. All rights reserved.
  7
+//
  8
+
  9
+#import <Foundation/Foundation.h>
  10
+#import "cocos2d.h"
  11
+
  12
+@interface CocosOverlayScrollView : UIScrollView
  13
+{
  14
+    CCNode* targetLayer;
  15
+}
  16
+@property(nonatomic, retain) CCNode* targetLayer;
  17
+-(id) initWithFrame: (CGRect) frameRect numPages: (int) numPages width: (float) width layer: (CCNode*) layer;
  18
+@end
106  Classes/Views/CocosOverlayScrollView.m
... ...
@@ -0,0 +1,106 @@
  1
+//
  2
+//  CocosOverlayScrollView.m
  3
+//  shapes
  4
+//
  5
+//  Created by Nate Murray on 8/23/10.
  6
+//  Copyright 2010 LittleHiccup. All rights reserved.
  7
+//
  8
+
  9
+#import "CocosOverlayScrollView.h"
  10
+
  11
+@implementation CocosOverlayScrollView
  12
+@synthesize targetLayer;
  13
+
  14
+-(id) initWithFrame: (CGRect) frameRect numPages: (int) numPages width: (float) width layer: (CCNode*) layer {
  15
+    if ((self = [super initWithFrame: frameRect])){ 
  16
+        self.contentSize = CGSizeMake(320, width * numPages);
  17
+        self.bounces = YES;
  18
+        self.delaysContentTouches = NO;
  19
+        self.delegate = self;
  20
+        self.pagingEnabled = YES;
  21
+        self.scrollsToTop = NO;
  22
+        self.showsVerticalScrollIndicator = NO;
  23
+        self.showsHorizontalScrollIndicator = NO;
  24
+        [self setUserInteractionEnabled:TRUE];
  25
+        [self setScrollEnabled:TRUE];
  26
+        self.targetLayer = layer;
  27
+    }
  28
+    return self;
  29
+}
  30
+
  31
+-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
  32
+{
  33
+    if (!self.dragging)
  34
+    {
  35
+        UITouch* touch = [[touches allObjects] objectAtIndex:0];
  36
+        //CGPoint location = [touch locationInView: [touch view]];
  37
+        //CCLOG(@"touch at l.x:%f l.y:%f", location.x, location.y);
  38
+
  39
+        [self.nextResponder touchesBegan: touches withEvent:event];
  40
+        [[[CCDirector sharedDirector] openGLView] touchesBegan:touches withEvent:event];
  41
+    }
  42
+
  43
+    [super touchesBegan: touches withEvent: event];
  44
+}
  45
+
  46
+-(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
  47
+{
  48
+    if (!self.dragging)
  49
+    {
  50
+        [self.nextResponder touchesEnded: touches withEvent:event];
  51
+        [[[CCDirector sharedDirector] openGLView] touchesEnded:touches withEvent:event];
  52
+    }
  53
+
  54
+    [super touchesEnded: touches withEvent: event];
  55
+}
  56
+
  57
+-(void) touchesCancelled: (NSSet *) touches withEvent: (UIEvent *) event
  58
+{
  59
+    if (!self.dragging)
  60
+    {
  61
+        [self.nextResponder touchesCancelled: touches withEvent:event];
  62
+        [[[CCDirector sharedDirector] openGLView] touchesCancelled:touches withEvent:event];
  63
+    }
  64
+
  65
+    [super touchesCancelled: touches withEvent: event];
  66
+}
  67
+
  68
+
  69
+- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
  70
+{
  71
+  // TODO - Custom code for handling deceleration of the scroll view
  72
+}
  73
+
  74
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView
  75
+{
  76
+    CGPoint dragPt = [scrollView contentOffset];
  77
+
  78
+    // CCScene* currentScene = [[CCDirector sharedDirector] runningScene];
  79
+
  80
+    // Only take the top layer to modify but other layers could be retrieved as well
  81
+    //
  82
+    // CCLayer* topLayer = (CCLayer *)[currentScene.children objectAtIndex:0];
  83
+
  84
+    //dragPt = [[CCDirector sharedDirector] convertCoordinate:dragPt];
  85
+    dragPt = [[CCDirector sharedDirector] convertToGL:dragPt];
  86
+
  87
+    dragPt.y = dragPt.y * -1;
  88
+    dragPt.x = dragPt.x * -1;
  89
+
  90
+    // CGPoint newLayerPosition = CGPointMake(dragPt.x + (scrollView.contentSize.height * 0.5f), dragPt.y + (scrollView.contentSize.width * 0.5f));
  91
+    CGPoint newLayerPosition = CGPointMake(dragPt.x, dragPt.y);
  92
+
  93
+    [targetLayer setPosition:newLayerPosition];
  94
+}
  95
+
  96
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
  97
+{
  98
+    // CGPoint dragPt = [scrollView contentOffset];
  99
+
  100
+}
  101
+
  102
+-(void) dealloc {
  103
+	self.targetLayer = nil;
  104
+    [super dealloc];
  105
+}
  106
+@end
23  Classes/Views/NMPanelMenu.h
... ...
@@ -0,0 +1,23 @@
  1
+/*
  2
+ *  NMPanelMenu.h
  3
+ *  shapes
  4
+ *
  5
+ *  Created by Nate Murray on 7/29/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+#import "cocos2d.h"
  11
+
  12
+@class NMPanelController;
  13
+@interface NMPanelMenu : CCMenu {
  14
+    NMPanelController* pc;
  15
+    BOOL dragged;
  16
+}
  17
+@property(nonatomic, retain) NMPanelController* pc;
  18
+
  19
+-(CCMenuItem *) itemForTouch: (UITouch *) touch;
  20
+- (void) onEnter;
  21
+// -(void) setToPanel: (int) n;
  22
+
  23
+@end
170  Classes/Views/NMPanelMenu.m
... ...
@@ -0,0 +1,170 @@
  1
+/*
  2
+ *  NMPanelMenu.m
  3
+ *  shapes
  4
+ *
  5
+ *  Created by Nate Murray on 7/29/10.
  6
+ *  Copyright 2010 YetiApps. All rights reserved.
  7
+ *
  8
+ */
  9
+
  10
+#include "NMPanelMenu.h"
  11
+#import "common.h"
  12
+#import "NMPanelController.h"
  13
+#import "NMPanelMenuItem.h"
  14
+
  15
+@interface NMPanelMenu (Private)
  16
+@end
  17
+
  18
+@implementation NMPanelMenu
  19
+@synthesize pc;
  20
+
  21
+- (void) onEnter {
  22
+    [super onEnter];
  23
+    self.pc = [[NMPanelController alloc] initWithNode: self];
  24
+    // todo, set contentSize to be the size of the children + padding
  25
+
  26
+    // CCLOG(@"we have %d children", [[self children] count]);
  27
+    [pc definePanelsWithSprites: [[self children] getNSArray]];
  28
+    // [pc setNodePositionToPanel: 0];
  29
+}
  30
+
  31
+/*
  32
+// the trick here is to give the PanelMenu a high touch priority than its items
  33
+// and if the PanelMenu ignores the touch, only then do you let the items have the touch
  34
+// in this way, you might not need any panel items at all
  35
+-(void) registerWithTouchDispatcher
  36
+{
  37
+    [[CCTouchDispatcher sharedDispatcher] 
  38
+        addTargetedDelegate:self 
  39
+                   priority:touchPriority_panelMenu 
  40
+            swallowsTouches:YES];
  41
+}
  42
+
  43
+- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
  44
+{
  45
+    return NO; // ******************* tmp
  46
+    CCMenuItem* sprite = [self itemForTouch: touch];
  47
+    if (sprite) { 
  48
+        // [sprite selected];
  49
+        return [pc ccTouchBegan:touch withEvent:event forSprite:sprite];
  50
+    }
  51
+    dragged = NO;
  52
+    return NO;
  53
+}
  54
+
  55
+- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
  56<